diff --git a/DEPS b/DEPS index 96dfe4e0f61..2b20bf90ba3 100644 --- a/DEPS +++ b/DEPS @@ -408,6 +408,27 @@ deps = { ], "dep_type": "cipd", }, + + # TODO(37531): Remove these cipd packages and build with sdk instead when + # benchmark runner gets support for that. + Var("dart_root") + "/benchmarks/FfiBoringssl/dart/native/out/": { + "packages": [ + { + "package": "dart/benchmarks/ffiboringssl", + "version": "commit:a86c69888b9a416f5249aacb4690a765be064969", + }, + ], + "dep_type": "cipd", + }, + Var("dart_root") + "/benchmarks/FfiCall/dart/native/out/": { + "packages": [ + { + "package": "dart/benchmarks/fficall", + "version": "version:1", + }, + ], + "dep_type": "cipd", + }, } deps_os = { diff --git a/benchmarks/FfiBoringssl/dart/FfiBoringssl.dart b/benchmarks/FfiBoringssl/dart/FfiBoringssl.dart new file mode 100644 index 00000000000..c87711bab92 --- /dev/null +++ b/benchmarks/FfiBoringssl/dart/FfiBoringssl.dart @@ -0,0 +1,144 @@ +// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +// Macro-benchmark for ffi with boringssl. + +import 'dart:convert'; +import 'dart:ffi'; +import 'dart:typed_data'; + +import 'package:benchmark_harness/benchmark_harness.dart'; + +import 'digest.dart'; +import 'types.dart'; + +// +// BoringSSL functions +// + +Uint8List inventData(int length) { + final result = Uint8List(length); + for (int i = 0; i < length; i++) { + result[i] = i % 256; + } + return result; +} + +Uint8List toUint8List(Bytes bytes, int length) { + final result = Uint8List(length); + final uint8bytes = bytes.asUint8Pointer(); + for (int i = 0; i < length; i++) { + result[i] = uint8bytes.elementAt(i).load(); + } + return result; +} + +void copyFromUint8ListToTarget(Uint8List source, Data target) { + final int length = source.length; + final uint8target = target.asUint8Pointer(); + for (int i = 0; i < length; i++) { + uint8target.offsetBy(i).store(source[i]); + } +} + +String hash(Pointer data, int length, Pointer hashAlgorithm) { + final context = EVP_MD_CTX_new(); + EVP_DigestInit(context, hashAlgorithm); + EVP_DigestUpdate(context, data, length); + final int resultSize = EVP_MD_CTX_size(context); + final Pointer result = + Pointer.allocate(count: resultSize).cast(); + EVP_DigestFinal(context, result, nullptr.cast()); + EVP_MD_CTX_free(context); + final String hash = base64Encode(toUint8List(result.load(), resultSize)); + result.free(); + return hash; +} + +// +// Benchmark fixtures. +// + +// Number of repeats: 1 && Length in bytes: 10000000 +// * CPU: Intel(R) Xeon(R) Gold 6154 +// * Architecture: x64 +// * 23000 - 52000000 us (without optimizations) +// * 23000 - 30000 us (with optimizations) +// * Architecture: SimDBC64 +// * 23000 - 5500000 us (without optimizations) +// * 23000 - 30000 us (with optimizations) +const int L = 1000; // Length of data in bytes. + +final hashAlgorithm = EVP_sha512(); + +// Hash of generated data of `L` bytes with `hashAlgorithm`. +const String expectedHash = + "bNLtqb+cBZcSkCmwBUuB5DP2uLe0madetwXv10usGUFJg1sdGhTEi+aW5NWIRW1RKiLq56obV74rVurn014Iyw=="; + +/// This benchmark runs a digest algorithm on data residing in C memory. +/// +/// This benchmark is intended as macro benchmark with a realistic workload. +class DigestCMemory extends BenchmarkBase { + DigestCMemory() : super("FfiBoringssl.DigestCMemory"); + + Pointer data; // Data in C memory that we want to digest. + + void setup() { + data = Pointer.allocate(count: L).cast(); + copyFromUint8ListToTarget(inventData(L), data.load()); + hash(data, L, hashAlgorithm); + } + + void teardown() { + data.free(); + } + + void run() { + final String result = hash(data, L, hashAlgorithm); + if (result != expectedHash) { + throw Exception("$name: Unexpected result: $result"); + } + } +} + +/// This benchmark runs a digest algorithm on data residing in Dart memory. +/// +/// This benchmark is intended as macro benchmark with a realistic workload. +class DigestDartMemory extends BenchmarkBase { + DigestDartMemory() : super("FfiBoringssl.DigestDartMemory"); + + Uint8List data; // Data in C memory that we want to digest. + + void setup() { + data = inventData(L); + final Pointer dataInC = Pointer.allocate(count: L).cast(); + copyFromUint8ListToTarget(data, dataInC.load()); + hash(dataInC, L, hashAlgorithm); + dataInC.free(); + } + + void teardown() {} + + void run() { + final Pointer dataInC = Pointer.allocate(count: L).cast(); + copyFromUint8ListToTarget(data, dataInC.load()); + final String result = hash(dataInC, L, hashAlgorithm); + dataInC.free(); + if (result != expectedHash) { + throw Exception("$name: Unexpected result: $result"); + } + } +} + +// +// Main driver. +// + +main() { + final benchmarks = [ + () => DigestCMemory(), + () => DigestDartMemory(), + ]; + benchmarks.forEach((benchmark) => benchmark().report()); +} diff --git a/benchmarks/FfiBoringssl/dart/digest.dart b/benchmarks/FfiBoringssl/dart/digest.dart new file mode 100644 index 00000000000..ecc869bb26c --- /dev/null +++ b/benchmarks/FfiBoringssl/dart/digest.dart @@ -0,0 +1,99 @@ +// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:ffi'; +import 'dart:io'; + +import 'dlopen_helper.dart'; +import 'types.dart'; + +// See: +// https://commondatastorage.googleapis.com/chromium-boringssl-docs/digest.h.html + +DynamicLibrary openSsl() { + // Force load crypto. + dlopenPlatformSpecific("crypto", + path: Platform.script.resolve("native/out/").path); + DynamicLibrary ssl = dlopenPlatformSpecific("ssl", + path: Platform.script.resolve("native/out/").path); + return ssl; +} + +final DynamicLibrary ssl = openSsl(); + +/// The following functions return EVP_MD objects that implement the named +/// hash function. +/// +/// ```c +/// const EVP_MD *EVP_sha512(void); +/// ``` +final Pointer Function() EVP_sha512 = + ssl.lookupFunction Function(), Pointer Function()>( + 'EVP_sha512'); + +/// EVP_MD_CTX_new allocates and initialises a fresh EVP_MD_CTX and returns it, +/// or NULL on allocation failure. The caller must use EVP_MD_CTX_free to +/// release the resulting object. +/// +/// ```c +/// EVP_MD_CTX *EVP_MD_CTX_new(void); +/// ``` +final Pointer Function() EVP_MD_CTX_new = ssl.lookupFunction< + Pointer Function(), + Pointer Function()>('EVP_MD_CTX_new'); + +/// EVP_MD_CTX_free calls EVP_MD_CTX_cleanup and then frees ctx itself. +/// +/// ```c +/// void EVP_MD_CTX_free(EVP_MD_CTX *ctx); +/// ``` +final void Function(Pointer) EVP_MD_CTX_free = ssl.lookupFunction< + Void Function(Pointer), + void Function(Pointer)>('EVP_MD_CTX_free'); + +/// EVP_DigestInit acts like EVP_DigestInit_ex except that ctx is initialised +/// before use. +/// +/// ```c +/// int EVP_DigestInit(EVP_MD_CTX *ctx, const EVP_MD *type); +/// ``` +final int Function(Pointer, Pointer) EVP_DigestInit = + ssl.lookupFunction, Pointer), + int Function(Pointer, Pointer)>('EVP_DigestInit'); + +/// EVP_DigestUpdate hashes len bytes from data into the hashing operation +/// in ctx. It returns one. +/// +/// ```c +/// int EVP_DigestUpdate(EVP_MD_CTX *ctx, const void *data, +/// size_t len); +/// ``` +final int Function(Pointer, Pointer, int) EVP_DigestUpdate = + ssl.lookupFunction< + Int32 Function(Pointer, Pointer, IntPtr), + int Function( + Pointer, Pointer, int)>('EVP_DigestUpdate'); + +/// EVP_DigestFinal acts like EVP_DigestFinal_ex except that EVP_MD_CTX_cleanup +/// is called on ctx before returning. +/// +/// ```c +/// int EVP_DigestFinal(EVP_MD_CTX *ctx, uint8_t *md_out, +/// unsigned int *out_size); +/// ``` +final int Function(Pointer, Pointer, Pointer) + EVP_DigestFinal = ssl.lookupFunction< + Int32 Function(Pointer, Pointer, Pointer), + int Function(Pointer, Pointer, + Pointer)>('EVP_DigestFinal'); + +/// EVP_MD_CTX_size returns the digest size of ctx, in bytes. It will crash if +/// a digest hasn't been set on ctx. +/// +/// ```c +/// size_t EVP_MD_CTX_size(const EVP_MD_CTX *ctx); +/// ``` +final int Function(Pointer) EVP_MD_CTX_size = ssl.lookupFunction< + IntPtr Function(Pointer), + int Function(Pointer)>('EVP_MD_CTX_size'); diff --git a/benchmarks/FfiBoringssl/dart/dlopen_helper.dart b/benchmarks/FfiBoringssl/dart/dlopen_helper.dart new file mode 100644 index 00000000000..b0310022ecb --- /dev/null +++ b/benchmarks/FfiBoringssl/dart/dlopen_helper.dart @@ -0,0 +1,58 @@ +// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:ffi'; +import 'dart:io'; + +const kArm = "arm"; +const kArm64 = "arm64"; +const kIa32 = "ia32"; +const kX64 = "x64"; + +// https://stackoverflow.com/questions/45125516/possible-values-for-uname-m +final _unames = { + "arm": kArm, + "aarch64_be": kArm64, + "aarch64": kArm64, + "armv8b": kArm64, + "armv8l": kArm64, + "i386": kIa32, + "i686": kIa32, + "x86_64": kX64, +}; + +String _checkRunningMode(String architecture) { + // Check if we're running in 32bit mode. + final int pointerSize = sizeOf(); + if (pointerSize == 4 && architecture == kX64) return kIa32; + if (pointerSize == 4 && architecture == kArm64) return kArm; + + return architecture; +} + +String _architecture() { + final String uname = Process.runSync("uname", ["-m"]).stdout.trim(); + final String architecture = _unames[uname]; + if (architecture == null) + throw Exception("Unrecognized architecture: '$uname'"); + + // Check if we're running in 32bit mode. + return _checkRunningMode(architecture); +} + +String _platformPath(String name, {String path = ""}) { + if (Platform.isMacOS || Platform.isIOS) + return "${path}mac/${_architecture()}/lib$name.dylib"; + + if (Platform.isWindows) + return "${path}win/${_checkRunningMode(kX64)}/$name.dll"; + + // Unknown platforms default to Unix implementation. + return "${path}linux/${_architecture()}/lib$name.so"; +} + +DynamicLibrary dlopenPlatformSpecific(String name, {String path}) { + final String fullPath = _platformPath(name, path: path); + return DynamicLibrary.open(fullPath); +} diff --git a/benchmarks/FfiBoringssl/dart/native/.gitignore b/benchmarks/FfiBoringssl/dart/native/.gitignore new file mode 100644 index 00000000000..44040287a6d --- /dev/null +++ b/benchmarks/FfiBoringssl/dart/native/.gitignore @@ -0,0 +1,7 @@ +# Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file +# for details. All rights reserved. Use of this source code is governed by a +# BSD-style license that can be found in the LICENSE file. + +build/ +out/ +src/ diff --git a/benchmarks/FfiBoringssl/dart/native/Makefile b/benchmarks/FfiBoringssl/dart/native/Makefile new file mode 100644 index 00000000000..149ded1f6bb --- /dev/null +++ b/benchmarks/FfiBoringssl/dart/native/Makefile @@ -0,0 +1,81 @@ +# Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file +# for details. All rights reserved. Use of this source code is governed by a +# BSD-style license that can be found in the LICENSE file. + +# TODO(37531): Remove this makefile and build with sdk instead when +# benchmark runner gets support for that. + +REVISION=a86c69888b9a416f5249aacb4690a765be064969 + +STRIPARM=arm-linux-gnueabihf-strip +STRIPARM64=aarch64-linux-gnu-strip + +.PHONY: all cipd build/linux/x64 build/linux/ia32 build/linux/arm build/linux/arm64 clean + +all: out/linux/x64/libssl.so out/linux/x64/libcrypto.so out/linux/ia32/libssl.so out/linux/ia32/libcrypto.so out/linux/arm/libssl.so out/linux/arm/libcrypto.so out/linux/arm64/libssl.so out/linux/arm64/libcrypto.so + +cipd: + cipd create -name dart/benchmarks/ffiboringssl -in out -install-mode copy -tag commit:$(REVISION) + +src: + test -e src || git clone https://boringssl.googlesource.com/boringssl src + cd src && git reset --hard $(REVISION) + +build/linux/x64: src + mkdir -p build/linux/x64 && cd build/linux/x64 && cmake -DBUILD_SHARED_LIBS=1 ../../../src && make + +out/linux/x64: + mkdir -p out/linux/x64 + +out/linux/x64/libssl.so: build/linux/x64 out/linux/x64 + cp build/linux/x64/ssl/libssl.so $@ + strip $@ + +out/linux/x64/libcrypto.so: build/linux/x64 out/linux/x64 + cp build/linux/x64/crypto/libcrypto.so $@ + strip $@ + +build/linux/ia32: src + mkdir -p build/linux/ia32 && cd build/linux/ia32 && cmake -DBUILD_SHARED_LIBS=1 -DCMAKE_TOOLCHAIN_FILE=../../../src/util/32-bit-toolchain.cmake ../../../src && make + +out/linux/ia32: + mkdir -p out/linux/ia32 + +out/linux/ia32/libssl.so: build/linux/ia32 out/linux/ia32 + cp build/linux/ia32/ssl/libssl.so $@ + strip $@ + +out/linux/ia32/libcrypto.so: build/linux/ia32 out/linux/ia32 + cp build/linux/ia32/crypto/libcrypto.so $@ + strip $@ + +build/linux/arm: src + mkdir -p build/linux/arm && cd build/linux/arm && cmake -DBUILD_SHARED_LIBS=1 -DCMAKE_TOOLCHAIN_FILE=../../../arm.cmake ../../../src && make + +out/linux/arm: + mkdir -p out/linux/arm + +out/linux/arm/libssl.so: build/linux/arm out/linux/arm + cp build/linux/arm/ssl/libssl.so $@ + $(STRIPARM) $@ + +out/linux/arm/libcrypto.so: build/linux/arm out/linux/arm + cp build/linux/arm/crypto/libcrypto.so $@ + $(STRIPARM) $@ + +build/linux/arm64: src + mkdir -p build/linux/arm64 && cd build/linux/arm64 && cmake -DBUILD_SHARED_LIBS=1 -DCMAKE_TOOLCHAIN_FILE=../../../arm64.cmake ../../../src && make + +out/linux/arm64: + mkdir -p out/linux/arm64 + +out/linux/arm64/libssl.so: build/linux/arm64 out/linux/arm64 + cp build/linux/arm64/ssl/libssl.so $@ + $(STRIPARM64) $@ + +out/linux/arm64/libcrypto.so: build/linux/arm64 out/linux/arm64 + cp build/linux/arm64/crypto/libcrypto.so $@ + $(STRIPARM64) $@ + +clean: + rm -rf build src out diff --git a/benchmarks/FfiBoringssl/dart/native/arm.cmake b/benchmarks/FfiBoringssl/dart/native/arm.cmake new file mode 100644 index 00000000000..7ead7fc1f53 --- /dev/null +++ b/benchmarks/FfiBoringssl/dart/native/arm.cmake @@ -0,0 +1,17 @@ +# Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file +# for details. All rights reserved. Use of this source code is governed by a +# BSD-style license that can be found in the LICENSE file. + +# TODO(37531): Remove this cmake file and build with sdk instead when +# benchmark runner gets support for that. + +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_VERSION 1) +set(CMAKE_SYSTEM_PROCESSOR "arm") +set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc) +set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++) +set(CMAKE_AS_COMPILER arm-linux-gnueabihf-as) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-error=attributes" CACHE STRING "c++ flags") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-error=attributes" CACHE STRING "c flags") +set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} " CACHE STRING "asm flags") diff --git a/benchmarks/FfiBoringssl/dart/native/arm64.cmake b/benchmarks/FfiBoringssl/dart/native/arm64.cmake new file mode 100644 index 00000000000..771a2a618de --- /dev/null +++ b/benchmarks/FfiBoringssl/dart/native/arm64.cmake @@ -0,0 +1,17 @@ +# Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file +# for details. All rights reserved. Use of this source code is governed by a +# BSD-style license that can be found in the LICENSE file. + +# TODO(37531): Remove this cmake file and build with sdk instead when +# benchmark runner gets support for that. + +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_VERSION 1) +set(CMAKE_SYSTEM_PROCESSOR "arm64") +set(CMAKE_C_COMPILER aarch64-linux-gnu-gcc) +set(CMAKE_CXX_COMPILER aarch64-linux-gnu-g++) +set(CMAKE_AS_COMPILER aarch64-linux-gnu-as) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-error=attributes" CACHE STRING "c++ flags") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-error=attributes" CACHE STRING "c flags") +set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} " CACHE STRING "asm flags") diff --git a/benchmarks/FfiBoringssl/dart/types.dart b/benchmarks/FfiBoringssl/dart/types.dart new file mode 100644 index 00000000000..c36c851628d --- /dev/null +++ b/benchmarks/FfiBoringssl/dart/types.dart @@ -0,0 +1,25 @@ +// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:ffi'; + +/// digest algorithm. +class EVP_MD extends Struct {} + +/// digest context. +class EVP_MD_CTX extends Struct {} + +/// Type for `void*` used to represent opaque data. +class Data extends Struct { + static Data fromUint8Pointer(Pointer p) => p.cast().load(); + + Pointer asUint8Pointer() => this.addressOf.cast(); +} + +/// Type for `uint8_t*` used to represent byte data. +class Bytes extends Struct { + static Data fromUint8Pointer(Pointer p) => p.cast().load(); + + Pointer asUint8Pointer() => this.addressOf.cast(); +} diff --git a/benchmarks/FfiCall/dart/FfiCall.dart b/benchmarks/FfiCall/dart/FfiCall.dart new file mode 100644 index 00000000000..d7e31c4b939 --- /dev/null +++ b/benchmarks/FfiCall/dart/FfiCall.dart @@ -0,0 +1,1150 @@ +// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +// TODO(37581): Generate this file. + +// These micro benchmarks track the speed of reading and writing C memory from +// Dart with a specific marshalling and unmarshalling of data. + +import 'dart:ffi'; +import 'dart:io'; + +import 'package:benchmark_harness/benchmark_harness.dart'; + +import 'dlopen_helper.dart'; + +// +// Trampoline functions. +// + +DynamicLibrary ffiTestFunctions = dlopenPlatformSpecific("native_functions", + path: Platform.script.resolve("native/out/").path); + +typedef NativeFunction1Uint8 = Uint8 Function(Uint8); +typedef Function1int = int Function(int); +Function1int function1Uint8 = ffiTestFunctions + .lookupFunction("Function1Uint8"); + +typedef NativeFunction1Uint16 = Uint16 Function(Uint16); +Function1int function1Uint16 = ffiTestFunctions + .lookupFunction("Function1Uint16"); + +typedef NativeFunction1Uint32 = Uint32 Function(Uint32); +Function1int function1Uint32 = ffiTestFunctions + .lookupFunction("Function1Uint32"); + +typedef NativeFunction1Uint64 = Uint64 Function(Uint64); +Function1int function1Uint64 = ffiTestFunctions + .lookupFunction("Function1Uint64"); + +typedef NativeFunction1Int8 = Int8 Function(Int8); +Function1int function1Int8 = ffiTestFunctions + .lookupFunction("Function1Int8"); + +typedef NativeFunction1Int16 = Int16 Function(Int16); +Function1int function1Int16 = ffiTestFunctions + .lookupFunction("Function1Int16"); + +typedef NativeFunction1Int32 = Int32 Function(Int32); +Function1int function1Int32 = ffiTestFunctions + .lookupFunction("Function1Int32"); + +typedef NativeFunction2Int32 = Int32 Function(Int32, Int32); +typedef Function2int = int Function(int, int); +Function2int function2Int32 = ffiTestFunctions + .lookupFunction("Function2Int32"); + +typedef NativeFunction4Int32 = Int32 Function(Int32, Int32, Int32, Int32); +typedef Function4int = int Function(int, int, int, int); +Function4int function4Int32 = ffiTestFunctions + .lookupFunction("Function4Int32"); + +typedef NativeFunction10Int32 = Int32 Function( + Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32); +typedef Function10int = int Function( + int, int, int, int, int, int, int, int, int, int); +Function10int function10Int32 = ffiTestFunctions + .lookupFunction("Function10Int32"); + +typedef NativeFunction20Int32 = Int32 Function( + Int32, + Int32, + Int32, + Int32, + Int32, + Int32, + Int32, + Int32, + Int32, + Int32, + Int32, + Int32, + Int32, + Int32, + Int32, + Int32, + Int32, + Int32, + Int32, + Int32); +typedef Function20int = int Function(int, int, int, int, int, int, int, int, + int, int, int, int, int, int, int, int, int, int, int, int); +Function20int function20Int32 = ffiTestFunctions + .lookupFunction("Function20Int32"); + +typedef NativeFunction1Int64 = Int64 Function(Int64); +Function1int function1Int64 = ffiTestFunctions + .lookupFunction("Function1Int64"); + +typedef NativeFunction2Int64 = Int64 Function(Int64, Int64); +Function2int function2Int64 = ffiTestFunctions + .lookupFunction("Function2Int64"); + +typedef NativeFunction4Int64 = Int64 Function(Int64, Int64, Int64, Int64); +Function4int function4Int64 = ffiTestFunctions + .lookupFunction("Function4Int64"); + +typedef NativeFunction10Int64 = Int64 Function( + Int64, Int64, Int64, Int64, Int64, Int64, Int64, Int64, Int64, Int64); +Function10int function10Int64 = ffiTestFunctions + .lookupFunction("Function10Int64"); + +typedef NativeFunction20Int64 = Int64 Function( + Int64, + Int64, + Int64, + Int64, + Int64, + Int64, + Int64, + Int64, + Int64, + Int64, + Int64, + Int64, + Int64, + Int64, + Int64, + Int64, + Int64, + Int64, + Int64, + Int64); +Function20int function20Int64 = ffiTestFunctions + .lookupFunction("Function20Int64"); + +typedef NativeFunction1Float = Float Function(Float); +typedef Function1double = double Function(double); +Function1double function1Float = ffiTestFunctions + .lookupFunction("Function1Float"); + +typedef NativeFunction2Float = Float Function(Float, Float); +typedef Function2double = double Function(double, double); +Function2double function2Float = ffiTestFunctions + .lookupFunction("Function2Float"); + +typedef NativeFunction4Float = Float Function(Float, Float, Float, Float); +typedef Function4double = double Function(double, double, double, double); +Function4double function4Float = ffiTestFunctions + .lookupFunction("Function4Float"); + +typedef NativeFunction10Float = Float Function( + Float, Float, Float, Float, Float, Float, Float, Float, Float, Float); +typedef Function10double = double Function(double, double, double, double, + double, double, double, double, double, double); +Function10double function10Float = ffiTestFunctions + .lookupFunction("Function10Float"); + +typedef NativeFunction20Float = Float Function( + Float, + Float, + Float, + Float, + Float, + Float, + Float, + Float, + Float, + Float, + Float, + Float, + Float, + Float, + Float, + Float, + Float, + Float, + Float, + Float); +typedef Function20double = double Function( + double, + double, + double, + double, + double, + double, + double, + double, + double, + double, + double, + double, + double, + double, + double, + double, + double, + double, + double, + double); +Function20double function20Float = ffiTestFunctions + .lookupFunction("Function20Float"); + +typedef NativeFunction1Double = Double Function(Double); +Function1double function1Double = ffiTestFunctions + .lookupFunction("Function1Double"); + +typedef NativeFunction2Double = Double Function(Double, Double); +Function2double function2Double = ffiTestFunctions + .lookupFunction("Function1Double"); + +typedef NativeFunction4Double = Double Function(Double, Double, Double, Double); +Function4double function4Double = ffiTestFunctions + .lookupFunction("Function1Double"); + +typedef NativeFunction10Double = Double Function(Double, Double, Double, Double, + Double, Double, Double, Double, Double, Double); +Function10double function10Double = + ffiTestFunctions.lookupFunction( + "Function10Double"); + +typedef NativeFunction20Double = Double Function( + Double, + Double, + Double, + Double, + Double, + Double, + Double, + Double, + Double, + Double, + Double, + Double, + Double, + Double, + Double, + Double, + Double, + Double, + Double, + Double); +Function20double function20Double = + ffiTestFunctions.lookupFunction( + "Function20Double"); + +typedef Function1PointerUint8 = Pointer Function(Pointer); +Function1PointerUint8 function1PointerUint8 = ffiTestFunctions.lookupFunction< + Function1PointerUint8, Function1PointerUint8>("Function1PointerUint8"); + +typedef Function2PointerUint8 = Pointer Function( + Pointer, Pointer); +Function2PointerUint8 function2PointerUint8 = ffiTestFunctions.lookupFunction< + Function2PointerUint8, Function2PointerUint8>("Function2PointerUint8"); + +typedef Function4PointerUint8 = Pointer Function( + Pointer, Pointer, Pointer, Pointer); +Function4PointerUint8 function4PointerUint8 = ffiTestFunctions.lookupFunction< + Function4PointerUint8, Function4PointerUint8>("Function4PointerUint8"); + +typedef Function10PointerUint8 = Pointer Function( + Pointer, + Pointer, + Pointer, + Pointer, + Pointer, + Pointer, + Pointer, + Pointer, + Pointer, + Pointer); +Function10PointerUint8 function10PointerUint8 = ffiTestFunctions.lookupFunction< + Function10PointerUint8, Function10PointerUint8>("Function10PointerUint8"); + +typedef Function20PointerUint8 = Pointer Function( + Pointer, + Pointer, + Pointer, + Pointer, + Pointer, + Pointer, + Pointer, + Pointer, + Pointer, + Pointer, + Pointer, + Pointer, + Pointer, + Pointer, + Pointer, + Pointer, + Pointer, + Pointer, + Pointer, + Pointer); +Function20PointerUint8 function20PointerUint8 = ffiTestFunctions.lookupFunction< + Function20PointerUint8, Function20PointerUint8>("Function20PointerUint8"); + +// +// Trampoline call. +// + +int doCall1Uint8(int length) { + int x = 0; + for (int i = 0; i < length; i++) { + x += function1Uint8(17); + } + return x; +} + +int doCall1Uint16(int length) { + int x = 0; + for (int i = 0; i < length; i++) { + x += function1Uint16(17); + } + return x; +} + +int doCall1Uint32(int length) { + int x = 0; + for (int i = 0; i < length; i++) { + x += function1Uint32(i); + } + return x; +} + +int doCall1Uint64(int length) { + int x = 0; + for (int i = 0; i < length; i++) { + x += function1Uint64(i); + } + return x; +} + +int doCall1Int8(int length) { + int x = 0; + for (int i = 0; i < length; i++) { + x += function1Int8(17); + } + return x; +} + +int doCall1Int16(int length) { + int x = 0; + for (int i = 0; i < length; i++) { + x += function1Int16(17); + } + return x; +} + +int doCall1Int32(int length) { + int x = 0; + for (int i = 0; i < length; i++) { + x += function1Int32(i); + } + return x; +} + +int doCall2Int32(int length) { + int x = 0; + for (int i = 0; i < length; i++) { + x += function2Int32(i, i); + } + return x; +} + +int doCall4Int32(int length) { + int x = 0; + for (int i = 0; i < length; i++) { + x += function4Int32(i, i, i, i); + } + return x; +} + +int doCall10Int32(int length) { + int x = 0; + for (int i = 0; i < length; i++) { + x += function10Int32(i, i, i, i, i, i, i, i, i, i); + } + return x; +} + +int doCall20Int32(int length) { + int x = 0; + for (int i = 0; i < length; i++) { + x += function20Int32( + i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i); + } + return x; +} + +int doCall1Int64(int length) { + int x = 0; + for (int i = 0; i < length; i++) { + x += function1Int64(i); + } + return x; +} + +int doCall2Int64(int length) { + int x = 0; + for (int i = 0; i < length; i++) { + x += function2Int64(i, i); + } + return x; +} + +int doCall4Int64(int length) { + int x = 0; + for (int i = 0; i < length; i++) { + x += function4Int64(i, i, i, i); + } + return x; +} + +int doCall10Int64(int length) { + int x = 0; + for (int i = 0; i < length; i++) { + x += function10Int64(i, i, i, i, i, i, i, i, i, i); + } + return x; +} + +int doCall20Int64(int length) { + int x = 0; + for (int i = 0; i < length; i++) { + x += function20Int64( + i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i); + } + return x; +} + +int doCall1Int64Mint(int length) { + int x = 0x7FFFFFFF00000000; + + for (int i = 0; i < length; i++) { + x = function1Int64(x); + } + return x; +} + +double doCall1Float(int length) { + double x = 0.0; + for (int i = 0; i < length; i++) { + x += function1Float(17.0); + } + return x; +} + +double doCall2Float(int length) { + double x = 0; + for (int i = 0; i < length; i++) { + x += function2Float(1.0, 2.0); + } + return x; +} + +double doCall4Float(int length) { + double x = 0; + for (int i = 0; i < length; i++) { + x += function4Float(1.0, 2.0, 3.0, 4.0); + } + return x; +} + +double doCall10Float(int length) { + double x = 0; + for (int i = 0; i < length; i++) { + x += function10Float(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0); + } + return x; +} + +double doCall20Float(int length) { + double x = 0; + for (int i = 0; i < length; i++) { + x += function20Float(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, + 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0); + } + return x; +} + +double doCall1Double(int length) { + double x = 0.0; + for (int i = 0; i < length; i++) { + x += function1Double(17.0); + } + return x; +} + +double doCall2Double(int length) { + double x = 0; + for (int i = 0; i < length; i++) { + x += function2Double(1.0, 2.0); + } + return x; +} + +double doCall4Double(int length) { + double x = 0; + for (int i = 0; i < length; i++) { + x += function4Double(1.0, 2.0, 3.0, 4.0); + } + return x; +} + +double doCall10Double(int length) { + double x = 0; + for (int i = 0; i < length; i++) { + x += function10Double(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0); + } + return x; +} + +double doCall20Double(int length) { + double x = 0; + for (int i = 0; i < length; i++) { + x += function20Double(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, + 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0); + } + return x; +} + +Pointer doCall1PointerUint8(int length, Pointer p1) { + Pointer x = p1; + for (int i = 0; i < length; i++) { + x = function1PointerUint8(x); + } + return x; +} + +Pointer doCall2PointerUint8( + int length, Pointer p1, Pointer p2) { + Pointer x = p1; + for (int i = 0; i < length; i++) { + x = function2PointerUint8(x, p2); + } + return x; +} + +Pointer doCall4PointerUint8(int length, Pointer p1, + Pointer p2, Pointer p3, Pointer p4) { + Pointer x = p1; + for (int i = 0; i < length; i++) { + x = function4PointerUint8(x, p2, p3, p4); + } + return x; +} + +Pointer doCall10PointerUint8( + int length, + Pointer p1, + Pointer p2, + Pointer p3, + Pointer p4, + Pointer p5, + Pointer p6, + Pointer p7, + Pointer p8, + Pointer p9, + Pointer p10) { + Pointer x = p1; + for (int i = 0; i < length; i++) { + x = function10PointerUint8(x, p2, p3, p4, p5, p6, p7, p8, p9, p10); + } + return x; +} + +Pointer doCall20PointerUint8( + int length, + Pointer p1, + Pointer p2, + Pointer p3, + Pointer p4, + Pointer p5, + Pointer p6, + Pointer p7, + Pointer p8, + Pointer p9, + Pointer p10, + Pointer p11, + Pointer p12, + Pointer p13, + Pointer p14, + Pointer p15, + Pointer p16, + Pointer p17, + Pointer p18, + Pointer p19, + Pointer p20) { + Pointer x = p1; + for (int i = 0; i < length; i++) { + x = function20PointerUint8(x, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, + p13, p14, p15, p16, p17, p18, p19, p20); + } + return x; +} + +// +// Benchmark fixtures. +// + +// Number of repeats: 1000 +// * CPU: Intel(R) Xeon(R) Gold 6154 +// * Architecture: x64 +// * 200 - 1100 us +// * Architecture: SimDBC64 +// * 2800 - 110000 us +const N = 1000; + +class Uint8x01 extends BenchmarkBase { + Uint8x01() : super("FfiCall.Uint8x01"); + + void run() { + final int x = doCall1Uint8(N); + if (x != N * 17 + N * 42) { + throw Exception("$name: Unexpected result: $x"); + } + } +} + +class Uint16x01 extends BenchmarkBase { + Uint16x01() : super("FfiCall.Uint16x01"); + + void run() { + final int x = doCall1Uint16(N); + if (x != N * 17 + N * 42) { + throw Exception("$name: Unexpected result: $x"); + } + } +} + +class Uint32x01 extends BenchmarkBase { + Uint32x01() : super("FfiCall.Uint32x01"); + + void run() { + final int x = doCall1Uint32(N); + if (x != N * (N - 1) / 2 + N * 42) { + throw Exception("$name: Unexpected result: $x"); + } + } +} + +class Uint64x01 extends BenchmarkBase { + Uint64x01() : super("FfiCall.Uint64x01"); + + void run() { + final int x = doCall1Uint64(N); + if (x != N * (N - 1) / 2 + N * 42) { + throw Exception("$name: Unexpected result: $x"); + } + } +} + +class Int8x01 extends BenchmarkBase { + Int8x01() : super("FfiCall.Int8x01"); + + void run() { + final int x = doCall1Int8(N); + if (x != N * 17 + N * 42) { + throw Exception("$name: Unexpected result: $x"); + } + } +} + +class Int16x01 extends BenchmarkBase { + Int16x01() : super("FfiCall.Int16x01"); + + void run() { + final int x = doCall1Int16(N); + if (x != N * 17 + N * 42) { + throw Exception("$name: Unexpected result: $x"); + } + } +} + +class Int32x01 extends BenchmarkBase { + Int32x01() : super("FfiCall.Int32x01"); + + void run() { + final int x = doCall1Int32(N); + if (x != N * (N - 1) / 2 + N * 42) { + throw Exception("$name: Unexpected result: $x"); + } + } +} + +class Int32x02 extends BenchmarkBase { + Int32x02() : super("FfiCall.Int32x02"); + + void run() { + final int x = doCall2Int32(N); + if (x != N * (N - 1) * 2 / 2) { + throw Exception("$name: Unexpected result: $x"); + } + } +} + +class Int32x04 extends BenchmarkBase { + Int32x04() : super("FfiCall.Int32x04"); + + void run() { + final int x = doCall4Int32(N); + if (x != N * (N - 1) * 4 / 2) { + throw Exception("$name: Unexpected result: $x"); + } + } +} + +class Int32x10 extends BenchmarkBase { + Int32x10() : super("FfiCall.Int32x10"); + + void run() { + final int x = doCall10Int32(N); + if (x != N * (N - 1) * 10 / 2) { + throw Exception("$name: Unexpected result: $x"); + } + } +} + +class Int32x20 extends BenchmarkBase { + Int32x20() : super("FfiCall.Int32x20"); + + void run() { + final int x = doCall20Int32(N); + if (x != N * (N - 1) * 20 / 2) { + throw Exception("$name: Unexpected result: $x"); + } + } +} + +class Int64x01 extends BenchmarkBase { + Int64x01() : super("FfiCall.Int64x01"); + + void run() { + final int x = doCall1Int64(N); + if (x != N * (N - 1) / 2 + N * 42) { + throw Exception("$name: Unexpected result: $x"); + } + } +} + +class Int64x02 extends BenchmarkBase { + Int64x02() : super("FfiCall.Int64x02"); + + void run() { + final int x = doCall2Int64(N); + if (x != N * (N - 1) * 2 / 2) { + throw Exception("$name: Unexpected result: $x"); + } + } +} + +class Int64x04 extends BenchmarkBase { + Int64x04() : super("FfiCall.Int64x04"); + + void run() { + final int x = doCall4Int64(N); + if (x != N * (N - 1) * 4 / 2) { + throw Exception("$name: Unexpected result: $x"); + } + } +} + +class Int64x10 extends BenchmarkBase { + Int64x10() : super("FfiCall.Int64x10"); + + void run() { + final int x = doCall10Int64(N); + if (x != N * (N - 1) * 10 / 2) { + throw Exception("$name: Unexpected result: $x"); + } + } +} + +class Int64x20 extends BenchmarkBase { + Int64x20() : super("FfiCall.Int64x20"); + + void run() { + final int x = doCall20Int64(N); + if (x != N * (N - 1) * 20 / 2) { + throw Exception("$name: Unexpected result: $x"); + } + } +} + +class Int64Mintx01 extends BenchmarkBase { + Int64Mintx01() : super("FfiCall.Int64Mintx01"); + + void run() { + final int x = doCall1Int64Mint(N); + if (x != 0x7FFFFFFF00000000 + N * 42) { + throw Exception("$name: Unexpected result: $x"); + } + } +} + +class Floatx01 extends BenchmarkBase { + Floatx01() : super("FfiCall.Floatx01"); + + void run() { + final double x = doCall1Float(N); + final double expected = N * (N - 1) / 2 + N * 42; + if (0.999 * expected > x && x > 1.001 * expected) { + throw Exception("$name: Unexpected result: $x"); + } + } +} + +class Floatx02 extends BenchmarkBase { + Floatx02() : super("FfiCall.Floatx02"); + + void run() { + final double x = doCall2Float(N); + final double expected = N * 55.0; + if (0.999 * expected > x && x > 1.001 * expected) { + throw Exception("$name: Unexpected result: $x"); + } + } +} + +class Floatx04 extends BenchmarkBase { + Floatx04() : super("FfiCall.Floatx04"); + + void run() { + final double x = doCall4Float(N); + final double expected = N * 55.0; + if (0.999 * expected > x && x > 1.001 * expected) { + throw Exception("$name: Unexpected result: $x"); + } + } +} + +class Floatx10 extends BenchmarkBase { + Floatx10() : super("FfiCall.Floatx10"); + + void run() { + final double x = doCall10Float(N); + final double expected = N * 55.0; + if (0.999 * expected > x && x > 1.001 * expected) { + throw Exception("$name: Unexpected result: $x"); + } + } +} + +class Floatx20 extends BenchmarkBase { + Floatx20() : super("FfiCall.Floatx20"); + + void run() { + final double x = doCall20Float(N); + final double expected = N * 220.0; + if (0.999 * expected > x && x > 1.001 * expected) { + throw Exception("$name: Unexpected result: $x"); + } + } +} + +class Doublex01 extends BenchmarkBase { + Doublex01() : super("FfiCall.Doublex01"); + + void run() { + final double x = doCall1Double(N); + final double expected = N * (N - 1) / 2 + N * 42; + if (0.999 * expected > x && x > 1.001 * expected) { + throw Exception("$name: Unexpected result: $x"); + } + } +} + +class Doublex02 extends BenchmarkBase { + Doublex02() : super("FfiCall.Doublex02"); + + void run() { + final double x = doCall2Double(N); + final double expected = N * 55.0; + if (0.999 * expected > x && x > 1.001 * expected) { + throw Exception("$name: Unexpected result: $x"); + } + } +} + +class Doublex04 extends BenchmarkBase { + Doublex04() : super("FfiCall.Doublex04"); + + void run() { + final double x = doCall4Double(N); + final double expected = N * 55.0; + if (0.999 * expected > x && x > 1.001 * expected) { + throw Exception("$name: Unexpected result: $x"); + } + } +} + +class Doublex10 extends BenchmarkBase { + Doublex10() : super("FfiCall.Doublex10"); + + void run() { + final double x = doCall10Double(N); + final double expected = N * 55.0; + if (0.999 * expected > x && x > 1.001 * expected) { + throw Exception("$name: Unexpected result: $x"); + } + } +} + +class Doublex20 extends BenchmarkBase { + Doublex20() : super("FfiCall.Doublex20"); + + void run() { + final double x = doCall20Double(N); + final double expected = N * 220.0; + if (0.999 * expected > x && x > 1.001 * expected) { + throw Exception("$name: Unexpected result: $x"); + } + } +} + +class PointerUint8x01 extends BenchmarkBase { + PointerUint8x01() : super("FfiCall.PointerUint8x01"); + + Pointer pointer; + void setup() => pointer = Pointer.allocate(count: N + 1); + void teardown() => pointer.free(); + + void run() { + final Pointer x = doCall1PointerUint8(N, pointer); + if (x.address != pointer.address + N) { + throw Exception("$name: Unexpected result: $x"); + } + } +} + +class PointerUint8x02 extends BenchmarkBase { + PointerUint8x02() : super("FfiCall.PointerUint8x02"); + + Pointer pointer, pointer2; + + void setup() { + pointer = Pointer.allocate(count: N + 1); + pointer2 = pointer.elementAt(1); + } + + void teardown() { + pointer.free(); + } + + void run() { + final Pointer x = doCall2PointerUint8(N, pointer, pointer2); + if (x.address != pointer.address + N * sizeOf()) { + throw Exception("$name: Unexpected result: $x"); + } + } +} + +class PointerUint8x04 extends BenchmarkBase { + PointerUint8x04() : super("FfiCall.PointerUint8x04"); + + Pointer pointer, pointer2, pointer3, pointer4; + + void setup() { + pointer = Pointer.allocate(count: N + 1); + pointer2 = pointer.elementAt(1); + pointer3 = pointer.elementAt(2); + pointer4 = pointer.elementAt(3); + } + + void teardown() { + pointer.free(); + } + + void run() { + final Pointer x = + doCall4PointerUint8(N, pointer, pointer2, pointer3, pointer4); + if (x.address != pointer.address + N * sizeOf()) { + throw Exception("$name: Unexpected result: $x"); + } + } +} + +class PointerUint8x10 extends BenchmarkBase { + PointerUint8x10() : super("FfiCall.PointerUint8x10"); + + Pointer pointer, + pointer2, + pointer3, + pointer4, + pointer5, + pointer6, + pointer7, + pointer8, + pointer9, + pointer10; + + void setup() { + pointer = Pointer.allocate(count: N + 1); + pointer2 = pointer.elementAt(1); + pointer3 = pointer.elementAt(2); + pointer4 = pointer.elementAt(3); + pointer5 = pointer.elementAt(4); + pointer6 = pointer.elementAt(5); + pointer7 = pointer.elementAt(6); + pointer8 = pointer.elementAt(7); + pointer9 = pointer.elementAt(8); + pointer10 = pointer.elementAt(9); + } + + void teardown() { + pointer.free(); + } + + void run() { + final Pointer x = doCall10PointerUint8( + N, + pointer, + pointer2, + pointer3, + pointer4, + pointer5, + pointer6, + pointer7, + pointer8, + pointer9, + pointer10); + if (x.address != pointer.address + N * sizeOf()) { + throw Exception("$name: Unexpected result: $x"); + } + } +} + +class PointerUint8x20 extends BenchmarkBase { + PointerUint8x20() : super("FfiCall.PointerUint8x20"); + + Pointer pointer, + pointer2, + pointer3, + pointer4, + pointer5, + pointer6, + pointer7, + pointer8, + pointer9, + pointer10, + pointer11, + pointer12, + pointer13, + pointer14, + pointer15, + pointer16, + pointer17, + pointer18, + pointer19, + pointer20; + + void setup() { + pointer = Pointer.allocate(count: N + 1); + pointer2 = pointer.elementAt(1); + pointer3 = pointer.elementAt(2); + pointer4 = pointer.elementAt(3); + pointer5 = pointer.elementAt(4); + pointer6 = pointer.elementAt(5); + pointer7 = pointer.elementAt(6); + pointer8 = pointer.elementAt(7); + pointer9 = pointer.elementAt(8); + pointer10 = pointer.elementAt(9); + pointer11 = pointer.elementAt(10); + pointer12 = pointer.elementAt(11); + pointer13 = pointer.elementAt(12); + pointer14 = pointer.elementAt(13); + pointer15 = pointer.elementAt(14); + pointer16 = pointer.elementAt(15); + pointer17 = pointer.elementAt(16); + pointer18 = pointer.elementAt(17); + pointer19 = pointer.elementAt(18); + pointer20 = pointer.elementAt(19); + } + + void teardown() { + pointer.free(); + } + + void run() { + final Pointer x = doCall20PointerUint8( + N, + pointer, + pointer2, + pointer3, + pointer4, + pointer5, + pointer6, + pointer7, + pointer8, + pointer9, + pointer10, + pointer11, + pointer12, + pointer13, + pointer14, + pointer15, + pointer16, + pointer17, + pointer18, + pointer19, + pointer20); + if (x.address != pointer.address + N * sizeOf()) { + throw Exception("$name: Unexpected result: $x"); + } + } +} + +// +// Main driver. +// + +main() { + final benchmarks = [ + () => Uint8x01(), + () => Uint16x01(), + () => Uint32x01(), + () => Uint64x01(), + () => Int8x01(), + () => Int16x01(), + () => Int32x01(), + () => Int32x02(), + () => Int32x04(), + () => Int32x10(), + () => Int32x20(), + () => Int64x01(), + () => Int64x02(), + () => Int64x04(), + () => Int64x10(), + () => Int64x20(), + () => Int64Mintx01(), + () => Floatx01(), + () => Floatx02(), + () => Floatx04(), + () => Floatx10(), + () => Floatx20(), + () => Doublex01(), + () => Doublex02(), + () => Doublex04(), + () => Doublex10(), + () => Doublex20(), + () => PointerUint8x01(), + () => PointerUint8x02(), + () => PointerUint8x04(), + () => PointerUint8x10(), + () => PointerUint8x20(), + ]; + benchmarks.forEach((benchmark) => benchmark().report()); +} diff --git a/benchmarks/FfiCall/dart/dlopen_helper.dart b/benchmarks/FfiCall/dart/dlopen_helper.dart new file mode 100644 index 00000000000..b0310022ecb --- /dev/null +++ b/benchmarks/FfiCall/dart/dlopen_helper.dart @@ -0,0 +1,58 @@ +// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:ffi'; +import 'dart:io'; + +const kArm = "arm"; +const kArm64 = "arm64"; +const kIa32 = "ia32"; +const kX64 = "x64"; + +// https://stackoverflow.com/questions/45125516/possible-values-for-uname-m +final _unames = { + "arm": kArm, + "aarch64_be": kArm64, + "aarch64": kArm64, + "armv8b": kArm64, + "armv8l": kArm64, + "i386": kIa32, + "i686": kIa32, + "x86_64": kX64, +}; + +String _checkRunningMode(String architecture) { + // Check if we're running in 32bit mode. + final int pointerSize = sizeOf(); + if (pointerSize == 4 && architecture == kX64) return kIa32; + if (pointerSize == 4 && architecture == kArm64) return kArm; + + return architecture; +} + +String _architecture() { + final String uname = Process.runSync("uname", ["-m"]).stdout.trim(); + final String architecture = _unames[uname]; + if (architecture == null) + throw Exception("Unrecognized architecture: '$uname'"); + + // Check if we're running in 32bit mode. + return _checkRunningMode(architecture); +} + +String _platformPath(String name, {String path = ""}) { + if (Platform.isMacOS || Platform.isIOS) + return "${path}mac/${_architecture()}/lib$name.dylib"; + + if (Platform.isWindows) + return "${path}win/${_checkRunningMode(kX64)}/$name.dll"; + + // Unknown platforms default to Unix implementation. + return "${path}linux/${_architecture()}/lib$name.so"; +} + +DynamicLibrary dlopenPlatformSpecific(String name, {String path}) { + final String fullPath = _platformPath(name, path: path); + return DynamicLibrary.open(fullPath); +} diff --git a/benchmarks/FfiCall/dart/native/.gitignore b/benchmarks/FfiCall/dart/native/.gitignore new file mode 100644 index 00000000000..4baa5ba98e9 --- /dev/null +++ b/benchmarks/FfiCall/dart/native/.gitignore @@ -0,0 +1,5 @@ +# Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file +# for details. All rights reserved. Use of this source code is governed by a +# BSD-style license that can be found in the LICENSE file. + +out/ diff --git a/benchmarks/FfiCall/dart/native/Makefile b/benchmarks/FfiCall/dart/native/Makefile new file mode 100644 index 00000000000..5e5d716e836 --- /dev/null +++ b/benchmarks/FfiCall/dart/native/Makefile @@ -0,0 +1,60 @@ +# Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file +# for details. All rights reserved. Use of this source code is governed by a +# BSD-style license that can be found in the LICENSE file. + +# TODO(37531): Remove this makefile and build with sdk instead when +# benchmark runner gets support for that. + +CC=gcc +CCARM=arm-linux-gnueabihf-gcc +CCARM64=aarch64-linux-gnu-gcc +CFLAGS=-Wall -g -O -fPIC + +# Bump this whenever the benchmark is updated. +VERSION=1 + +.PHONY: all clean + +all: out/linux/x64/libnative_functions.so out/linux/ia32/libnative_functions.so out/linux/arm64/libnative_functions.so out/linux/arm/libnative_functions.so + +cipd: + cipd create -name dart/benchmarks/fficall -in out -install-mode copy -tag version:$(VERSION) + +clean: + rm -rf *.o *.so out + +out/linux/x64: + mkdir -p out/linux/x64 + +out/linux/x64/native_functions.o: native_functions.c | out/linux/x64 + $(CC) $(CFLAGS) -c -o $@ native_functions.c + +out/linux/x64/libnative_functions.so: out/linux/x64/native_functions.o + $(CC) $(CFLAGS) -s -shared -o $@ out/linux/x64/native_functions.o + +out/linux/ia32: + mkdir -p out/linux/ia32 + +out/linux/ia32/native_functions.o: native_functions.c | out/linux/ia32 + $(CC) $(CFLAGS) -m32 -c -o $@ native_functions.c + +out/linux/ia32/libnative_functions.so: out/linux/ia32/native_functions.o + $(CC) $(CFLAGS) -m32 -s -shared -o $@ out/linux/ia32/native_functions.o + +out/linux/arm64: + mkdir -p out/linux/arm64 + +out/linux/arm64/native_functions.o: native_functions.c | out/linux/arm64 + $(CCARM64) $(CFLAGS) -c -o $@ native_functions.c + +out/linux/arm64/libnative_functions.so: out/linux/arm64/native_functions.o + $(CCARM64) $(CFLAGS) -s -shared -o $@ out/linux/arm64/native_functions.o + +out/linux/arm: + mkdir -p out/linux/arm + +out/linux/arm/native_functions.o: native_functions.c | out/linux/arm + $(CCARM) $(CFLAGS) -c -o $@ native_functions.c + +out/linux/arm/libnative_functions.so: out/linux/arm/native_functions.o + $(CCARM) $(CFLAGS) -s -shared -o $@ out/linux/arm/native_functions.o diff --git a/benchmarks/FfiCall/dart/native/native_functions.c b/benchmarks/FfiCall/dart/native/native_functions.c new file mode 100644 index 00000000000..9fcee4d357c --- /dev/null +++ b/benchmarks/FfiCall/dart/native/native_functions.c @@ -0,0 +1,132 @@ +// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +#include + +uint8_t Function1Uint8(uint8_t x) { return x + 42; } + +uint16_t Function1Uint16(uint16_t x) { return x + 42; } + +uint32_t Function1Uint32(uint32_t x) { return x + 42; } + +uint64_t Function1Uint64(uint64_t x) { return x + 42; } + +int8_t Function1Int8(int8_t x) { return x + 42; } + +int16_t Function1Int16(int16_t x) { return x + 42; } + +int32_t Function1Int32(int32_t x) { return x + 42; } + +int32_t Function2Int32(int32_t a, int32_t b) { + return a + b; +} + +int32_t Function4Int32(int32_t a, int32_t b, int32_t c, int32_t d) { + return a + b + c + d; +} + +int32_t Function10Int32(int32_t a, int32_t b, int32_t c, int32_t d, int32_t e, + int32_t f, int32_t g, int32_t h, int32_t i, int32_t j) { + return a + b + c + d + e + f + g + h + i + j; +} + +int32_t Function20Int32(int32_t a, int32_t b, int32_t c, int32_t d, int32_t e, + int32_t f, int32_t g, int32_t h, int32_t i, int32_t j, + int32_t k, int32_t l, int32_t m, int32_t n, int32_t o, + int32_t p, int32_t q, int32_t r, int32_t s, int32_t t) { + return a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + + p + q + r + s + t; +} + +int64_t Function1Int64(int64_t x) { return x + 42; } + +int64_t Function2Int64(int64_t a, int64_t b) { + return a + b; +} + +int64_t Function4Int64(int64_t a, int64_t b, int64_t c, int64_t d) { + return a + b + c + d; +} + +int64_t Function10Int64(int64_t a, int64_t b, int64_t c, int64_t d, int64_t e, + int64_t f, int64_t g, int64_t h, int64_t i, int64_t j) { + return a + b + c + d + e + f + g + h + i + j; +} + +int64_t Function20Int64(int64_t a, int64_t b, int64_t c, int64_t d, int64_t e, + int64_t f, int64_t g, int64_t h, int64_t i, int64_t j, + int64_t k, int64_t l, int64_t m, int64_t n, int64_t o, + int64_t p, int64_t q, int64_t r, int64_t s, int64_t t) { + return a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + + p + q + r + s + t; +} + +float Function1Float(float x) { return x + 42.0f; } + +float Function2Float(float a, float b) { + return a + b; +} + +float Function4Float(float a, float b, float c, float d) { + return a + b + c + d; +} + +float Function10Float(float a, float b, float c, float d, float e, float f, + float g, float h, float i, float j) { + return a + b + c + d + e + f + g + h + i + j; +} + +float Function20Float(float a, float b, float c, float d, float e, float f, + float g, float h, float i, float j, float k, float l, + float m, float n, float o, float p, float q, float r, + float s, float t) { + return a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p + + q + r + s + t; +} + +double Function1Double(double x) { return x + 42.0; } + +double Function2Double(double a, double b) { + return a + b; +} + +double Function4Double(double a, double b, double c, double d) { + return a + b + c + d; +} + +double Function10Double(double a, double b, double c, double d, double e, + double f, double g, double h, double i, double j) { + return a + b + c + d + e + f + g + h + i + j; +} + +double Function20Double(double a, double b, double c, double d, double e, + double f, double g, double h, double i, double j, + double k, double l, double m, double n, double o, + double p, double q, double r, double s, double t) { + return a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + + p + q + r + s + t; +} + +uint8_t *Function1PointerUint8(uint8_t *a) { return a + 1; } + +uint8_t *Function2PointerUint8(uint8_t *a, uint8_t *b) { return a + 1; } + +uint8_t *Function4PointerUint8(uint8_t *a, uint8_t *b, uint8_t *c, uint8_t *d) { + return a + 1; +} + +uint8_t *Function10PointerUint8(uint8_t *a, uint8_t *b, uint8_t *c, uint8_t *d, + uint8_t *e, uint8_t *f, uint8_t *g, uint8_t *h, + uint8_t *i, uint8_t *j) { + return a + 1; +} + +uint8_t *Function20PointerUint8(uint8_t *a, uint8_t *b, uint8_t *c, uint8_t *d, + uint8_t *e, uint8_t *f, uint8_t *g, uint8_t *h, + uint8_t *i, uint8_t *j, uint8_t *k, uint8_t *l, + uint8_t *m, uint8_t *n, uint8_t *o, uint8_t *p, + uint8_t *q, uint8_t *r, uint8_t *s, + uint8_t *t) { + return a + 1; +} diff --git a/benchmarks/FfiMemory/dart/FfiMemory.dart b/benchmarks/FfiMemory/dart/FfiMemory.dart new file mode 100644 index 00000000000..39c053f73dc --- /dev/null +++ b/benchmarks/FfiMemory/dart/FfiMemory.dart @@ -0,0 +1,431 @@ +// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +// TODO(37581): Generate this file. + +// Micro-benchmarks for ffi memory stores and loads. +// +// These micro benchmarks track the speed of reading and writing C memory from +// Dart with a specific marshalling and unmarshalling of data. + +import 'dart:ffi'; + +import 'package:benchmark_harness/benchmark_harness.dart'; + +// +// Pointer store. +// + +void doStoreInt8(Pointer pointer, int length) { + for (int i = 0; i < length; i++) { + pointer.elementAt(i).store(1); + } +} + +void doStoreUint8(Pointer pointer, int length) { + for (int i = 0; i < length; i++) { + pointer.elementAt(i).store(1); + } +} + +void doStoreInt16(Pointer pointer, int length) { + for (int i = 0; i < length; i++) { + pointer.elementAt(i).store(1); + } +} + +void doStoreUint16(Pointer pointer, int length) { + for (int i = 0; i < length; i++) { + pointer.elementAt(i).store(1); + } +} + +void doStoreInt32(Pointer pointer, int length) { + for (int i = 0; i < length; i++) { + pointer.elementAt(i).store(1); + } +} + +void doStoreUint32(Pointer pointer, int length) { + for (int i = 0; i < length; i++) { + pointer.elementAt(i).store(1); + } +} + +void doStoreInt64(Pointer pointer, int length) { + for (int i = 0; i < length; i++) { + pointer.elementAt(i).store(1); + } +} + +void doStoreUint64(Pointer pointer, int length) { + for (int i = 0; i < length; i++) { + pointer.elementAt(i).store(1); + } +} + +void doStoreFloat(Pointer pointer, int length) { + for (int i = 0; i < length; i++) { + pointer.elementAt(i).store(1.0); + } +} + +void doStoreDouble(Pointer pointer, int length) { + for (int i = 0; i < length; i++) { + pointer.elementAt(i).store(1.0); + } +} + +void doStorePointer( + Pointer> pointer, int length, Pointer data) { + for (int i = 0; i < length; i++) { + pointer.elementAt(i).store(data); + } +} + +void doStoreInt64Mint(Pointer pointer, int length) { + for (int i = 0; i < length; i++) { + pointer.elementAt(i).store(0x7FFFFFFFFFFFFFFF); + } +} + +// +// Pointer load. +// + +int doLoadInt8(Pointer pointer, int length) { + int x = 0; + for (int i = 0; i < length; i++) { + x += pointer.elementAt(i).load(); + } + return x; +} + +int doLoadUint8(Pointer pointer, int length) { + int x = 0; + for (int i = 0; i < length; i++) { + x += pointer.elementAt(i).load(); + } + return x; +} + +int doLoadInt16(Pointer pointer, int length) { + int x = 0; + for (int i = 0; i < length; i++) { + x += pointer.elementAt(i).load(); + } + return x; +} + +int doLoadUint16(Pointer pointer, int length) { + int x = 0; + for (int i = 0; i < length; i++) { + x += pointer.elementAt(i).load(); + } + return x; +} + +int doLoadInt32(Pointer pointer, int length) { + int x = 0; + for (int i = 0; i < length; i++) { + x += pointer.elementAt(i).load(); + } + return x; +} + +int doLoadUint32(Pointer pointer, int length) { + int x = 0; + for (int i = 0; i < length; i++) { + x += pointer.elementAt(i).load(); + } + return x; +} + +int doLoadInt64(Pointer pointer, int length) { + int x = 0; + for (int i = 0; i < length; i++) { + x += pointer.elementAt(i).load(); + } + return x; +} + +int doLoadUint64(Pointer pointer, int length) { + int x = 0; + for (int i = 0; i < length; i++) { + x += pointer.elementAt(i).load(); + } + return x; +} + +double doLoadFloat(Pointer pointer, int length) { + double x = 0; + for (int i = 0; i < length; i++) { + x += pointer.elementAt(i).load(); + } + return x; +} + +double doLoadDouble(Pointer pointer, int length) { + double x = 0; + for (int i = 0; i < length; i++) { + x += pointer.elementAt(i).load(); + } + return x; +} + +// Aggregates pointers through aggregrating their addresses. +int doLoadPointer(Pointer> pointer, int length) { + Pointer x; + int address_xor = 0; + for (int i = 0; i < length; i++) { + x = pointer.elementAt(i).load(); + address_xor ^= x.address; + } + return address_xor; +} + +int doLoadInt64Mint(Pointer pointer, int length) { + int x = 0; + for (int i = 0; i < length; i++) { + x += pointer.elementAt(i).load(); + } + return x; +} + +// +// Benchmark fixtures. +// + +// Number of repeats: 1000 +// * CPU: Intel(R) Xeon(R) Gold 6154 +// * Architecture: x64 +// * 48000 - 125000 us (without optimizations) +// * 14 - ??? us (expected with optimizations, on par with typed data) +// * Architecture: SimDBC64 +// * 52000 - 130000 us (without optimizations) +// * 300 - ??? us (expected with optimizations, on par with typed data) +const N = 1000; + +class PointerInt8 extends BenchmarkBase { + Pointer pointer; + PointerInt8() : super("FfiMemory.PointerInt8"); + + void setup() => pointer = Pointer.allocate(count: N); + void teardown() => pointer.free(); + + void run() { + doStoreInt8(pointer, N); + final int x = doLoadInt8(pointer, N); + if (x != N) { + throw Exception("$name: Unexpected result: $x"); + } + } +} + +class PointerUint8 extends BenchmarkBase { + Pointer pointer; + PointerUint8() : super("FfiMemory.PointerUint8"); + + void setup() => pointer = Pointer.allocate(count: N); + void teardown() => pointer.free(); + + void run() { + doStoreUint8(pointer, N); + final int x = doLoadUint8(pointer, N); + if (x != N) { + throw Exception("$name: Unexpected result: $x"); + } + } +} + +class PointerInt16 extends BenchmarkBase { + Pointer pointer; + PointerInt16() : super("FfiMemory.PointerInt16"); + + void setup() => pointer = Pointer.allocate(count: N); + void teardown() => pointer.free(); + + void run() { + doStoreInt16(pointer, N); + final int x = doLoadInt16(pointer, N); + if (x != N) { + throw Exception("$name: Unexpected result: $x"); + } + } +} + +class PointerUint16 extends BenchmarkBase { + Pointer pointer; + PointerUint16() : super("FfiMemory.PointerUint16"); + + void setup() => pointer = Pointer.allocate(count: N); + void teardown() => pointer.free(); + + void run() { + doStoreUint16(pointer, N); + final int x = doLoadUint16(pointer, N); + if (x != N) { + throw Exception("$name: Unexpected result: $x"); + } + } +} + +class PointerInt32 extends BenchmarkBase { + Pointer pointer; + PointerInt32() : super("FfiMemory.PointerInt32"); + + void setup() => pointer = Pointer.allocate(count: N); + void teardown() => pointer.free(); + + void run() { + doStoreInt32(pointer, N); + final int x = doLoadInt32(pointer, N); + if (x != N) { + throw Exception("$name: Unexpected result: $x"); + } + } +} + +class PointerUint32 extends BenchmarkBase { + Pointer pointer; + PointerUint32() : super("FfiMemory.PointerUint32"); + + void setup() => pointer = Pointer.allocate(count: N); + void teardown() => pointer.free(); + + void run() { + doStoreUint32(pointer, N); + final int x = doLoadUint32(pointer, N); + if (x != N) { + throw Exception("$name: Unexpected result: $x"); + } + } +} + +class PointerInt64 extends BenchmarkBase { + Pointer pointer; + PointerInt64() : super("FfiMemory.PointerInt64"); + + void setup() => pointer = Pointer.allocate(count: N); + void teardown() => pointer.free(); + + void run() { + doStoreInt64(pointer, N); + final int x = doLoadInt64(pointer, N); + if (x != N) { + throw Exception("$name: Unexpected result: $x"); + } + } +} + +class PointerUint64 extends BenchmarkBase { + Pointer pointer; + PointerUint64() : super("FfiMemory.PointerUint64"); + + void setup() => pointer = Pointer.allocate(count: N); + void teardown() => pointer.free(); + + void run() { + doStoreUint64(pointer, N); + final int x = doLoadUint64(pointer, N); + if (x != N) { + throw Exception("$name: Unexpected result: $x"); + } + } +} + +class PointerFloat extends BenchmarkBase { + Pointer pointer; + PointerFloat() : super("FfiMemory.PointerFloat"); + + void setup() => pointer = Pointer.allocate(count: N); + void teardown() => pointer.free(); + + void run() { + doStoreFloat(pointer, N); + final double x = doLoadFloat(pointer, N); + if (0.99 * N > x || x > 1.01 * N) { + throw Exception("$name: Unexpected result: $x"); + } + } +} + +class PointerDouble extends BenchmarkBase { + Pointer pointer; + PointerDouble() : super("FfiMemory.PointerDouble"); + + void setup() => pointer = Pointer.allocate(count: N); + void teardown() => pointer.free(); + + void run() { + doStoreDouble(pointer, N); + final double x = doLoadDouble(pointer, N); + if (0.99 * N > x || x > 1.01 * N) { + throw Exception("$name: Unexpected result: $x"); + } + } +} + +class PointerPointer extends BenchmarkBase { + Pointer> pointer; + Pointer data; + PointerPointer() : super("FfiMemory.PointerPointer"); + + void setup() { + pointer = Pointer.allocate(count: N); + data = Pointer.allocate(); + } + + void teardown() { + pointer.free(); + data.free(); + } + + void run() { + doStorePointer(pointer, N, data); + final int x = doLoadPointer(pointer, N); + if (x != 0 || x == data.address) { + throw Exception("$name: Unexpected result: $x"); + } + } +} + +class PointerInt64Mint extends BenchmarkBase { + Pointer pointer; + PointerInt64Mint() : super("FfiMemory.PointerInt64Mint"); + + void setup() => pointer = Pointer.allocate(count: N); + void teardown() => pointer.free(); + + void run() { + doStoreInt64Mint(pointer, N); + final int x = doLoadInt64Mint(pointer, N); + // Using overflow semantics in aggregation. + if (x != -N) { + throw Exception("$name: Unexpected result: $x"); + } + } +} + +// +// Main driver. +// + +main() { + final benchmarks = [ + () => PointerInt8(), + () => PointerUint8(), + () => PointerInt16(), + () => PointerUint16(), + () => PointerInt32(), + () => PointerUint32(), + () => PointerInt64(), + () => PointerInt64Mint(), + () => PointerUint64(), + () => PointerFloat(), + () => PointerDouble(), + () => PointerPointer(), + ]; + benchmarks.forEach((benchmark) => benchmark().report()); +} diff --git a/benchmarks/FfiStruct/dart/FfiStruct.dart b/benchmarks/FfiStruct/dart/FfiStruct.dart new file mode 100644 index 00000000000..ede799b26fa --- /dev/null +++ b/benchmarks/FfiStruct/dart/FfiStruct.dart @@ -0,0 +1,120 @@ +// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +// Micro-benchmark for ffi struct field stores and loads. +// +// Only tests a single field because the FfiMemory benchmark already tests loads +// and stores of different field sizes. + +import 'dart:ffi'; + +import 'package:benchmark_harness/benchmark_harness.dart'; + +// +// Struct field store (plus Pointer elementAt and load). +// + +void doStoreInt32(Pointer pointer, int length) { + for (int i = 0; i < length; i++) { + pointer.elementAt(i).load().c = 1; + } +} + +// +// Struct field load (plus Pointer elementAt and load). +// + +int doLoadInt32(Pointer pointer, int length) { + int x = 0; + for (int i = 0; i < length; i++) { + x += pointer.elementAt(i).load().c; + } + return x; +} + +// +// Benchmark fixture. +// + +// Number of repeats: 1000 +// * CPU: Intel(R) Xeon(R) Gold 6154 +// * Architecture: x64 +// * 150000 - 465000 us (without optimizations) +// * 14 - ??? us (expected with optimizations, on par with typed data) +const N = 1000; + +class FieldLoadStore extends BenchmarkBase { + Pointer pointer; + FieldLoadStore() : super("FfiStruct.FieldLoadStore"); + + void setup() => pointer = Pointer.allocate(count: N); + void teardown() => pointer.free(); + + void run() { + doStoreInt32(pointer, N); + final int x = doLoadInt32(pointer, N); + if (x != N) { + throw Exception("$name: Unexpected result: $x"); + } + } +} + +// +// Main driver. +// + +main() { + final benchmarks = [ + () => FieldLoadStore(), + ]; + benchmarks.forEach((benchmark) => benchmark().report()); +} + +// +// Test struct. +// +class VeryLargeStruct extends Struct { + @Int8() + int a; + + @Int16() + int b; + + @Int32() + int c; + + @Int64() + int d; + + @Uint8() + int e; + + @Uint16() + int f; + + @Uint32() + int g; + + @Uint64() + int h; + + @IntPtr() + int i; + + @Double() + double j; + + @Float() + double k; + + Pointer parent; + + @IntPtr() + int numChildren; + + Pointer children; + + @Int8() + int smallLastField; +} diff --git a/tests/ffi/function_structs_test.dart b/tests/ffi/function_structs_test.dart index 875f621847d..bf41a08529d 100644 --- a/tests/ffi/function_structs_test.dart +++ b/tests/ffi/function_structs_test.dart @@ -105,11 +105,11 @@ void testFunctionWithVeryLargeStruct() { struct.smallLastField = 1; } vls1.parent = vls2.addressOf; - vls1.numChidlren = 2; + vls1.numChildren = 2; vls1.children = vls1.addressOf; vls2.parent = vls2.addressOf; vls2.parent = ffi.nullptr.cast(); - vls2.numChidlren = 0; + vls2.numChildren = 0; vls2.children = ffi.nullptr.cast(); int result = f(vls1.addressOf); diff --git a/tests/ffi/very_large_struct.dart b/tests/ffi/very_large_struct.dart index c7bb261b353..36202f64525 100644 --- a/tests/ffi/very_large_struct.dart +++ b/tests/ffi/very_large_struct.dart @@ -2,8 +2,6 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. -library FfiTestCoordinateBare; - import 'dart:ffi'; /// Large sample struct for dart:ffi library. @@ -44,7 +42,7 @@ class VeryLargeStruct extends Struct { Pointer parent; @IntPtr() - int numChidlren; + int numChildren; Pointer children; diff --git a/tools/bots/try_benchmarks.sh b/tools/bots/try_benchmarks.sh index c463b12b7cc..e30eeb2b3d0 100755 --- a/tools/bots/try_benchmarks.sh +++ b/tools/bots/try_benchmarks.sh @@ -222,6 +222,10 @@ EOF out/ReleaseIA32/run_vm_tests GenKernelKernelLoadKernel out/ReleaseIA32/run_vm_tests KernelServiceCompileAll out/ReleaseIA32/dart --profile-period=10000 --packages=.packages benchmarks/Example/dart/Example.dart + out/ReleaseIA32/dart benchmarks/FfiBoringssl/dart/FfiBoringssl.dart + out/ReleaseIA32/dart benchmarks/FfiCall/dart/FfiCall.dart + out/ReleaseIA32/dart benchmarks/FfiMemory/dart/FfiMemory.dart + out/ReleaseIA32/dart benchmarks/FfiStruct/dart/FfiStruct.dart cd .. rm -rf tmp elif [ "$command" = linux-x64-build ] ||