mirror of
https://github.com/dart-lang/sdk
synced 2024-09-15 22:59:47 +00:00
b113fffb65
Fix: Check handle contents for Smi. Closes: https://github.com/flutter/flutter/issues/112726 Orignal CL description: Makes `Dart_Handle` FFI returns behave as the following snippet: ``` Dart_Handle ExampleSnippet() { Dart_Handle result = ...; if (Dart_IsError(result)) { Dart_PropagateError(result); } return result; } ``` Also makes FFI consistent with Dart_NativeFunctions, which will automatically throw upon return if Dart_SetReturnValue set the result to an error. `UnhandledExceptions` cannot flow out into Dart generated code. So, the implementation needs to be in `FfiCallInstr::EmitNativeCode`. Using `Dart_IsError` is slow compared to a machine code class id check. So, we should do the handle unwrapping and class id check in machine code. Unwrapping Handles in machine code is only safe when the GC is guaranteed to not run: Either (1) in `kThreadInGenerated`, or (2) in `kThreadInNative`, but only when transitioned into safepoint. So, the handle cannot be unwrapped immediately after the FFI call in machine code. We first need to transition back to generated. This means we need to transition again to native to do the actual `Dart_PropagateError` call. We can do so without the stub in JIT because we never return with normal control flow. Performance impact of this change is within benchmark noise in both JIT and AOT. Size impact is 42 bytes on x64, which is 10% in AOT and 12% in JIT. For more numbers see: go/dart-ffi-handle-error TEST=runtime/bin/ffi_test/ffi_test_functions_vmspecific.cc TEST=tests/ffi/vmspecific_handle_test.dart Closes: https://github.com/dart-lang/sdk/issues/49936 Change-Id: Id8edfd841a7d6246438386007d83747868a0a151 Cq-Include-Trybots: luci.dart.try:vm-canary-linux-debug-try,vm-ffi-android-debug-arm64c-try,vm-ffi-android-debug-arm-try,vm-kernel-gcc-linux-try,vm-kernel-linux-debug-x64-try,vm-kernel-linux-debug-x64c-try,vm-kernel-msvc-windows-try,vm-kernel-optcounter-threshold-linux-release-x64-try,vm-kernel-precomp-asan-linux-release-x64-try,vm-kernel-precomp-linux-debug-x64-try,vm-kernel-reload-linux-debug-x64-try,vm-kernel-reload-rollback-linux-debug-x64-try,vm-kernel-tsan-linux-release-x64-try,vm-kernel-win-debug-x64-try,vm-kernel-win-debug-ia32-try,vm-precomp-ffi-qemu-linux-release-arm-try,vm-precomp-ffi-qemu-linux-release-riscv64-try,vm-kernel-linux-debug-ia32-try,vm-kernel-mac-release-arm64-try,vm-kernel-precomp-win-debug-x64c-try Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/262342 Reviewed-by: Martin Kustermann <kustermann@google.com> Auto-Submit: Daco Harkes <dacoharkes@google.com> Commit-Queue: Daco Harkes <dacoharkes@google.com>
1349 lines
35 KiB
Dart
1349 lines
35 KiB
Dart
// 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:ffi/ffi.dart';
|
|
import 'package:benchmark_harness/benchmark_harness.dart';
|
|
|
|
import 'dlopen_helper.dart';
|
|
|
|
// Number of benchmark iterations per function.
|
|
const N = 1000;
|
|
|
|
// The native library that holds all the native functions being called.
|
|
DynamicLibrary ffiTestFunctions = dlopenPlatformSpecific('native_functions',
|
|
path: Platform.script.resolve('../native/out/').path);
|
|
|
|
//
|
|
// Native types and their Dart counterparts.
|
|
//
|
|
|
|
typedef NativeFunction1Uint8 = Uint8 Function(Uint8);
|
|
typedef NativeFunction1Uint16 = Uint16 Function(Uint16);
|
|
typedef NativeFunction1Uint32 = Uint32 Function(Uint32);
|
|
typedef NativeFunction1Uint64 = Uint64 Function(Uint64);
|
|
typedef NativeFunction1Int8 = Int8 Function(Int8);
|
|
typedef NativeFunction1Int16 = Int16 Function(Int16);
|
|
typedef NativeFunction1Int32 = Int32 Function(Int32);
|
|
typedef NativeFunction1Int64 = Int64 Function(Int64);
|
|
typedef Function1int = int Function(int);
|
|
|
|
typedef NativeFunction2Int32 = Int32 Function(Int32, Int32);
|
|
typedef NativeFunction2Int64 = Int64 Function(Int64, Int64);
|
|
typedef Function2int = int Function(int, int);
|
|
|
|
typedef NativeFunction4Int32 = Int32 Function(Int32, Int32, Int32, Int32);
|
|
typedef NativeFunction4Int64 = Int64 Function(Int64, Int64, Int64, Int64);
|
|
typedef Function4int = int Function(int, int, int, int);
|
|
|
|
typedef NativeFunction10Int32 = Int32 Function(
|
|
Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32);
|
|
typedef NativeFunction10Int64 = Int64 Function(
|
|
Int64, Int64, Int64, Int64, Int64, Int64, Int64, Int64, Int64, Int64);
|
|
typedef Function10int = int Function(
|
|
int, int, int, int, int, int, int, int, int, int);
|
|
|
|
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 NativeFunction20Int64 = Int64 Function(
|
|
Int64,
|
|
Int64,
|
|
Int64,
|
|
Int64,
|
|
Int64,
|
|
Int64,
|
|
Int64,
|
|
Int64,
|
|
Int64,
|
|
Int64,
|
|
Int64,
|
|
Int64,
|
|
Int64,
|
|
Int64,
|
|
Int64,
|
|
Int64,
|
|
Int64,
|
|
Int64,
|
|
Int64,
|
|
Int64);
|
|
typedef Function20int = int Function(int, int, int, int, int, int, int, int,
|
|
int, int, int, int, int, int, int, int, int, int, int, int);
|
|
|
|
typedef NativeFunction1Float = Float Function(Float);
|
|
typedef NativeFunction1Double = Double Function(Double);
|
|
typedef Function1double = double Function(double);
|
|
|
|
typedef NativeFunction2Float = Float Function(Float, Float);
|
|
typedef NativeFunction2Double = Double Function(Double, Double);
|
|
typedef Function2double = double Function(double, double);
|
|
|
|
typedef NativeFunction4Float = Float Function(Float, Float, Float, Float);
|
|
typedef NativeFunction4Double = Double Function(Double, Double, Double, Double);
|
|
typedef Function4double = double Function(double, double, double, double);
|
|
|
|
typedef NativeFunction10Float = Float Function(
|
|
Float, Float, Float, Float, Float, Float, Float, Float, Float, Float);
|
|
typedef NativeFunction10Double = Double Function(Double, Double, Double, Double,
|
|
Double, Double, Double, Double, Double, Double);
|
|
typedef Function10double = double Function(double, double, double, double,
|
|
double, double, double, double, double, double);
|
|
|
|
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 NativeFunction20Double = Double Function(
|
|
Double,
|
|
Double,
|
|
Double,
|
|
Double,
|
|
Double,
|
|
Double,
|
|
Double,
|
|
Double,
|
|
Double,
|
|
Double,
|
|
Double,
|
|
Double,
|
|
Double,
|
|
Double,
|
|
Double,
|
|
Double,
|
|
Double,
|
|
Double,
|
|
Double,
|
|
Double);
|
|
typedef Function20double = double Function(
|
|
double,
|
|
double,
|
|
double,
|
|
double,
|
|
double,
|
|
double,
|
|
double,
|
|
double,
|
|
double,
|
|
double,
|
|
double,
|
|
double,
|
|
double,
|
|
double,
|
|
double,
|
|
double,
|
|
double,
|
|
double,
|
|
double,
|
|
double);
|
|
|
|
typedef Function1PointerUint8 = Pointer<Uint8> Function(Pointer<Uint8>);
|
|
|
|
typedef Function2PointerUint8 = Pointer<Uint8> Function(
|
|
Pointer<Uint8>, Pointer<Uint8>);
|
|
|
|
typedef Function4PointerUint8 = Pointer<Uint8> Function(
|
|
Pointer<Uint8>, Pointer<Uint8>, Pointer<Uint8>, Pointer<Uint8>);
|
|
|
|
typedef Function10PointerUint8 = Pointer<Uint8> Function(
|
|
Pointer<Uint8>,
|
|
Pointer<Uint8>,
|
|
Pointer<Uint8>,
|
|
Pointer<Uint8>,
|
|
Pointer<Uint8>,
|
|
Pointer<Uint8>,
|
|
Pointer<Uint8>,
|
|
Pointer<Uint8>,
|
|
Pointer<Uint8>,
|
|
Pointer<Uint8>);
|
|
|
|
typedef Function20PointerUint8 = Pointer<Uint8> Function(
|
|
Pointer<Uint8>,
|
|
Pointer<Uint8>,
|
|
Pointer<Uint8>,
|
|
Pointer<Uint8>,
|
|
Pointer<Uint8>,
|
|
Pointer<Uint8>,
|
|
Pointer<Uint8>,
|
|
Pointer<Uint8>,
|
|
Pointer<Uint8>,
|
|
Pointer<Uint8>,
|
|
Pointer<Uint8>,
|
|
Pointer<Uint8>,
|
|
Pointer<Uint8>,
|
|
Pointer<Uint8>,
|
|
Pointer<Uint8>,
|
|
Pointer<Uint8>,
|
|
Pointer<Uint8>,
|
|
Pointer<Uint8>,
|
|
Pointer<Uint8>,
|
|
Pointer<Uint8>);
|
|
|
|
typedef NativeFunction1Handle = Handle Function(Handle);
|
|
typedef Function1Object = Object Function(Object);
|
|
|
|
typedef NativeFunction2Handle = Handle Function(Handle, Handle);
|
|
typedef Function2Object = Object Function(Object, Object);
|
|
|
|
typedef NativeFunction4Handle = Handle Function(Handle, Handle, Handle, Handle);
|
|
typedef Function4Object = Object Function(Object, Object, Object, Object);
|
|
|
|
typedef NativeFunction10Handle = Handle Function(Handle, Handle, Handle, Handle,
|
|
Handle, Handle, Handle, Handle, Handle, Handle);
|
|
typedef Function10Object = Object Function(Object, Object, Object, Object,
|
|
Object, Object, Object, Object, Object, Object);
|
|
|
|
typedef NativeFunction20Handle = Handle Function(
|
|
Handle,
|
|
Handle,
|
|
Handle,
|
|
Handle,
|
|
Handle,
|
|
Handle,
|
|
Handle,
|
|
Handle,
|
|
Handle,
|
|
Handle,
|
|
Handle,
|
|
Handle,
|
|
Handle,
|
|
Handle,
|
|
Handle,
|
|
Handle,
|
|
Handle,
|
|
Handle,
|
|
Handle,
|
|
Handle);
|
|
typedef Function20Object = Object Function(
|
|
Object,
|
|
Object,
|
|
Object,
|
|
Object,
|
|
Object,
|
|
Object,
|
|
Object,
|
|
Object,
|
|
Object,
|
|
Object,
|
|
Object,
|
|
Object,
|
|
Object,
|
|
Object,
|
|
Object,
|
|
Object,
|
|
Object,
|
|
Object,
|
|
Object,
|
|
Object);
|
|
|
|
//
|
|
// Benchmark fixtures.
|
|
//
|
|
|
|
abstract class FfiBenchmarkBase extends BenchmarkBase {
|
|
final bool isLeaf;
|
|
|
|
FfiBenchmarkBase(String name, {this.isLeaf: false})
|
|
: super('$name${isLeaf ? 'Leaf' : ''}');
|
|
|
|
void expectEquals(actual, expected) {
|
|
if (actual != expected) {
|
|
throw Exception('$name: Unexpected result: $actual, expected $expected');
|
|
}
|
|
}
|
|
|
|
void expectApprox(actual, expected) {
|
|
if (0.999 * expected > actual || actual > 1.001 * expected) {
|
|
throw Exception('$name: Unexpected result: $actual, expected $expected');
|
|
}
|
|
}
|
|
|
|
void expectIdentical(actual, expected) {
|
|
if (!identical(actual, expected)) {
|
|
throw Exception('$name: Unexpected result: $actual, expected $expected');
|
|
}
|
|
}
|
|
}
|
|
|
|
class Uint8x01 extends FfiBenchmarkBase {
|
|
final Function1int f;
|
|
|
|
Uint8x01({isLeaf: false})
|
|
: f = isLeaf
|
|
? ffiTestFunctions.lookupFunction<NativeFunction1Uint8,
|
|
Function1int>('Function1Uint8', isLeaf: true)
|
|
: ffiTestFunctions.lookupFunction<NativeFunction1Uint8,
|
|
Function1int>('Function1Uint8', isLeaf: false),
|
|
super('FfiCall.Uint8x01', isLeaf: isLeaf);
|
|
|
|
@override
|
|
void run() {
|
|
int x = 0;
|
|
for (int i = 0; i < N; i++) {
|
|
x += f(17);
|
|
}
|
|
expectEquals(x, N * 17 + N * 42);
|
|
}
|
|
}
|
|
|
|
class Uint16x01 extends FfiBenchmarkBase {
|
|
final Function1int f;
|
|
|
|
Uint16x01({isLeaf: false})
|
|
: f = isLeaf
|
|
? ffiTestFunctions.lookupFunction<NativeFunction1Uint16,
|
|
Function1int>('Function1Uint16', isLeaf: true)
|
|
: ffiTestFunctions.lookupFunction<NativeFunction1Uint16,
|
|
Function1int>('Function1Uint16', isLeaf: false),
|
|
super('FfiCall.Uint16x01', isLeaf: isLeaf);
|
|
|
|
@override
|
|
void run() {
|
|
int x = 0;
|
|
for (int i = 0; i < N; i++) {
|
|
x += f(17);
|
|
}
|
|
expectEquals(x, N * (17 + 42));
|
|
}
|
|
}
|
|
|
|
class Uint32x01 extends FfiBenchmarkBase {
|
|
final Function1int f;
|
|
|
|
Uint32x01({isLeaf: false})
|
|
: f = isLeaf
|
|
? ffiTestFunctions.lookupFunction<NativeFunction1Uint32,
|
|
Function1int>('Function1Uint32', isLeaf: true)
|
|
: ffiTestFunctions.lookupFunction<NativeFunction1Uint32,
|
|
Function1int>('Function1Uint32', isLeaf: false),
|
|
super('FfiCall.Uint32x01', isLeaf: isLeaf);
|
|
|
|
@override
|
|
void run() {
|
|
int x = 0;
|
|
for (int i = 0; i < N; i++) {
|
|
x += f(i);
|
|
}
|
|
expectEquals(x, N * (N - 1) / 2 + N * 42);
|
|
}
|
|
}
|
|
|
|
class Uint64x01 extends FfiBenchmarkBase {
|
|
final Function1int f;
|
|
|
|
Uint64x01({isLeaf: false})
|
|
: f = isLeaf
|
|
? ffiTestFunctions.lookupFunction<NativeFunction1Uint64,
|
|
Function1int>('Function1Uint64', isLeaf: true)
|
|
: ffiTestFunctions.lookupFunction<NativeFunction1Uint64,
|
|
Function1int>('Function1Uint64', isLeaf: false),
|
|
super('FfiCall.Uint64x01', isLeaf: isLeaf);
|
|
|
|
@override
|
|
void run() {
|
|
int x = 0;
|
|
for (int i = 0; i < N; i++) {
|
|
x += f(i);
|
|
}
|
|
expectEquals(x, N * (N - 1) / 2 + N * 42);
|
|
}
|
|
}
|
|
|
|
class Int8x01 extends FfiBenchmarkBase {
|
|
final Function1int f;
|
|
|
|
Int8x01({isLeaf: false})
|
|
: f = isLeaf
|
|
? ffiTestFunctions.lookupFunction<NativeFunction1Int8,
|
|
Function1int>('Function1Int8', isLeaf: true)
|
|
: ffiTestFunctions.lookupFunction<NativeFunction1Int8,
|
|
Function1int>('Function1Int8', isLeaf: false),
|
|
super('FfiCall.Int8x01', isLeaf: isLeaf);
|
|
|
|
@override
|
|
void run() {
|
|
int x = 0;
|
|
for (int i = 0; i < N; i++) {
|
|
x += f(17);
|
|
}
|
|
expectEquals(x, N * (17 + 42));
|
|
}
|
|
}
|
|
|
|
class Int16x01 extends FfiBenchmarkBase {
|
|
final Function1int f;
|
|
|
|
Int16x01({isLeaf: false})
|
|
: f = isLeaf
|
|
? ffiTestFunctions.lookupFunction<NativeFunction1Int16,
|
|
Function1int>('Function1Int16', isLeaf: true)
|
|
: ffiTestFunctions.lookupFunction<NativeFunction1Int16,
|
|
Function1int>('Function1Int16', isLeaf: false),
|
|
super('FfiCall.Int16x01', isLeaf: isLeaf);
|
|
|
|
@override
|
|
void run() {
|
|
int x = 0;
|
|
for (int i = 0; i < N; i++) {
|
|
x += f(17);
|
|
}
|
|
expectEquals(x, N * (17 + 42));
|
|
}
|
|
}
|
|
|
|
class Int32x01 extends FfiBenchmarkBase {
|
|
final Function1int f;
|
|
|
|
Int32x01({isLeaf: false})
|
|
: f = isLeaf
|
|
? ffiTestFunctions.lookupFunction<NativeFunction1Int32,
|
|
Function1int>('Function1Int32', isLeaf: true)
|
|
: ffiTestFunctions.lookupFunction<NativeFunction1Int32,
|
|
Function1int>('Function1Int32', isLeaf: false),
|
|
super('FfiCall.Int32x01', isLeaf: isLeaf);
|
|
|
|
@override
|
|
void run() {
|
|
int x = 0;
|
|
for (int i = 0; i < N; i++) {
|
|
x += f(i);
|
|
}
|
|
expectEquals(x, N * (N - 1) / 2 + N * 42);
|
|
}
|
|
}
|
|
|
|
class Int32x02 extends FfiBenchmarkBase {
|
|
final Function2int f;
|
|
|
|
Int32x02({isLeaf: false})
|
|
: f = isLeaf
|
|
? ffiTestFunctions.lookupFunction<NativeFunction2Int32,
|
|
Function2int>('Function2Int32', isLeaf: true)
|
|
: ffiTestFunctions.lookupFunction<NativeFunction2Int32,
|
|
Function2int>('Function2Int32', isLeaf: false),
|
|
super('FfiCall.Int32x02', isLeaf: isLeaf);
|
|
|
|
@override
|
|
void run() {
|
|
int x = 0;
|
|
for (int i = 0; i < N; i++) {
|
|
x += f(i, i);
|
|
}
|
|
expectEquals(x, N * (N - 1) * 2 / 2);
|
|
}
|
|
}
|
|
|
|
class Int32x04 extends FfiBenchmarkBase {
|
|
final Function4int f;
|
|
|
|
Int32x04({isLeaf: false})
|
|
: f = isLeaf
|
|
? ffiTestFunctions.lookupFunction<NativeFunction4Int32,
|
|
Function4int>('Function4Int32', isLeaf: true)
|
|
: ffiTestFunctions.lookupFunction<NativeFunction4Int32,
|
|
Function4int>('Function4Int32', isLeaf: false),
|
|
super('FfiCall.Int32x04', isLeaf: isLeaf);
|
|
|
|
@override
|
|
void run() {
|
|
int x = 0;
|
|
for (int i = 0; i < N; i++) {
|
|
x += f(i, i, i, i);
|
|
}
|
|
expectEquals(x, N * (N - 1) * 4 / 2);
|
|
}
|
|
}
|
|
|
|
class Int32x10 extends FfiBenchmarkBase {
|
|
final Function10int f;
|
|
|
|
Int32x10({isLeaf: false})
|
|
: f = isLeaf
|
|
? ffiTestFunctions.lookupFunction<NativeFunction10Int32,
|
|
Function10int>('Function10Int32', isLeaf: true)
|
|
: ffiTestFunctions.lookupFunction<NativeFunction10Int32,
|
|
Function10int>('Function10Int32', isLeaf: false),
|
|
super('FfiCall.Int32x10', isLeaf: isLeaf);
|
|
|
|
@override
|
|
void run() {
|
|
int x = 0;
|
|
for (int i = 0; i < N; i++) {
|
|
x += f(i, i, i, i, i, i, i, i, i, i);
|
|
}
|
|
expectEquals(x, N * (N - 1) * 10 / 2);
|
|
}
|
|
}
|
|
|
|
class Int32x20 extends FfiBenchmarkBase {
|
|
final Function20int f;
|
|
|
|
Int32x20({isLeaf: false})
|
|
: f = isLeaf
|
|
? ffiTestFunctions.lookupFunction<NativeFunction20Int32,
|
|
Function20int>('Function20Int32', isLeaf: true)
|
|
: ffiTestFunctions.lookupFunction<NativeFunction20Int32,
|
|
Function20int>('Function20Int32', isLeaf: false),
|
|
super('FfiCall.Int32x20', isLeaf: isLeaf);
|
|
|
|
@override
|
|
void run() {
|
|
int x = 0;
|
|
for (int i = 0; i < N; i++) {
|
|
x += f(i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i);
|
|
}
|
|
expectEquals(x, N * (N - 1) * 20 / 2);
|
|
}
|
|
}
|
|
|
|
class Int64x01 extends FfiBenchmarkBase {
|
|
final Function1int f;
|
|
|
|
Int64x01({isLeaf: false})
|
|
: f = isLeaf
|
|
? ffiTestFunctions.lookupFunction<NativeFunction1Int64,
|
|
Function1int>('Function1Int64', isLeaf: true)
|
|
: ffiTestFunctions.lookupFunction<NativeFunction1Int64,
|
|
Function1int>('Function1Int64', isLeaf: false),
|
|
super('FfiCall.Int64x01', isLeaf: isLeaf);
|
|
|
|
@override
|
|
void run() {
|
|
int x = 0;
|
|
for (int i = 0; i < N; i++) {
|
|
x += f(i);
|
|
}
|
|
expectEquals(x, N * (N - 1) / 2 + N * 42);
|
|
}
|
|
}
|
|
|
|
class Int64x02 extends FfiBenchmarkBase {
|
|
final Function2int f;
|
|
|
|
Int64x02({isLeaf: false})
|
|
: f = isLeaf
|
|
? ffiTestFunctions.lookupFunction<NativeFunction2Int64,
|
|
Function2int>('Function2Int64', isLeaf: true)
|
|
: ffiTestFunctions.lookupFunction<NativeFunction2Int64,
|
|
Function2int>('Function2Int64', isLeaf: false),
|
|
super('FfiCall.Int64x02', isLeaf: isLeaf);
|
|
|
|
@override
|
|
void run() {
|
|
int x = 0;
|
|
for (int i = 0; i < N; i++) {
|
|
x += f(i, i);
|
|
}
|
|
expectEquals(x, N * (N - 1) * 2 / 2);
|
|
}
|
|
}
|
|
|
|
class Int64x04 extends FfiBenchmarkBase {
|
|
final Function4int f;
|
|
|
|
Int64x04({isLeaf: false})
|
|
: f = isLeaf
|
|
? ffiTestFunctions.lookupFunction<NativeFunction4Int64,
|
|
Function4int>('Function4Int64', isLeaf: true)
|
|
: ffiTestFunctions.lookupFunction<NativeFunction4Int64,
|
|
Function4int>('Function4Int64', isLeaf: false),
|
|
super('FfiCall.Int64x04', isLeaf: isLeaf);
|
|
|
|
@override
|
|
void run() {
|
|
int x = 0;
|
|
for (int i = 0; i < N; i++) {
|
|
x += f(i, i, i, i);
|
|
}
|
|
expectEquals(x, N * (N - 1) * 4 / 2);
|
|
}
|
|
}
|
|
|
|
class Int64x10 extends FfiBenchmarkBase {
|
|
final Function10int f;
|
|
|
|
Int64x10({isLeaf: false})
|
|
: f = isLeaf
|
|
? ffiTestFunctions.lookupFunction<NativeFunction10Int64,
|
|
Function10int>('Function10Int64', isLeaf: true)
|
|
: ffiTestFunctions.lookupFunction<NativeFunction10Int64,
|
|
Function10int>('Function10Int64', isLeaf: false),
|
|
super('FfiCall.Int64x10', isLeaf: isLeaf);
|
|
|
|
@override
|
|
void run() {
|
|
int x = 0;
|
|
for (int i = 0; i < N; i++) {
|
|
x += f(i, i, i, i, i, i, i, i, i, i);
|
|
}
|
|
expectEquals(x, N * (N - 1) * 10 / 2);
|
|
}
|
|
}
|
|
|
|
class Int64x20 extends FfiBenchmarkBase {
|
|
final Function20int f;
|
|
|
|
Int64x20({isLeaf: false})
|
|
: f = isLeaf
|
|
? ffiTestFunctions.lookupFunction<NativeFunction20Int64,
|
|
Function20int>('Function20Int64', isLeaf: true)
|
|
: ffiTestFunctions.lookupFunction<NativeFunction20Int64,
|
|
Function20int>('Function20Int64', isLeaf: false),
|
|
super('FfiCall.Int64x20', isLeaf: isLeaf);
|
|
|
|
@override
|
|
void run() {
|
|
int x = 0;
|
|
for (int i = 0; i < N; i++) {
|
|
x += f(i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i);
|
|
}
|
|
expectEquals(x, N * (N - 1) * 20 / 2);
|
|
}
|
|
}
|
|
|
|
class Int64Mintx01 extends FfiBenchmarkBase {
|
|
final Function1int f;
|
|
|
|
Int64Mintx01({isLeaf: false})
|
|
: f = isLeaf
|
|
? ffiTestFunctions.lookupFunction<NativeFunction1Int64,
|
|
Function1int>('Function1Int64', isLeaf: true)
|
|
: ffiTestFunctions.lookupFunction<NativeFunction1Int64,
|
|
Function1int>('Function1Int64', isLeaf: false),
|
|
super('FfiCall.Int64Mintx01', isLeaf: isLeaf);
|
|
|
|
@override
|
|
void run() {
|
|
int x = 0x7FFFFFFF00000000;
|
|
for (int i = 0; i < N; i++) {
|
|
x = f(x);
|
|
}
|
|
expectEquals(x, 0x7FFFFFFF00000000 + N * 42);
|
|
}
|
|
}
|
|
|
|
class Floatx01 extends FfiBenchmarkBase {
|
|
final Function1double f;
|
|
|
|
Floatx01({isLeaf: false})
|
|
: f = isLeaf
|
|
? ffiTestFunctions.lookupFunction<NativeFunction1Float,
|
|
Function1double>('Function1Float', isLeaf: true)
|
|
: ffiTestFunctions.lookupFunction<NativeFunction1Float,
|
|
Function1double>('Function1Float', isLeaf: false),
|
|
super('FfiCall.Floatx01', isLeaf: isLeaf);
|
|
|
|
@override
|
|
void run() {
|
|
double x = 0.0;
|
|
for (int i = 0; i < N; i++) {
|
|
x += f(17.0);
|
|
}
|
|
expectApprox(x, N * (17.0 + 42.0));
|
|
}
|
|
}
|
|
|
|
class Floatx02 extends FfiBenchmarkBase {
|
|
final Function2double f;
|
|
|
|
Floatx02({isLeaf: false})
|
|
: f = isLeaf
|
|
? ffiTestFunctions.lookupFunction<NativeFunction2Float,
|
|
Function2double>('Function2Float', isLeaf: true)
|
|
: ffiTestFunctions.lookupFunction<NativeFunction2Float,
|
|
Function2double>('Function2Float', isLeaf: false),
|
|
super('FfiCall.Floatx02', isLeaf: isLeaf);
|
|
|
|
@override
|
|
void run() {
|
|
double x = 0;
|
|
for (int i = 0; i < N; i++) {
|
|
x += f(1.0, 2.0);
|
|
}
|
|
expectApprox(x, N * (1.0 + 2.0));
|
|
}
|
|
}
|
|
|
|
class Floatx04 extends FfiBenchmarkBase {
|
|
final Function4double f;
|
|
|
|
Floatx04({isLeaf: false})
|
|
: f = isLeaf
|
|
? ffiTestFunctions.lookupFunction<NativeFunction4Float,
|
|
Function4double>('Function4Float', isLeaf: true)
|
|
: ffiTestFunctions.lookupFunction<NativeFunction4Float,
|
|
Function4double>('Function4Float', isLeaf: false),
|
|
super('FfiCall.Floatx04', isLeaf: isLeaf);
|
|
|
|
@override
|
|
void run() {
|
|
double x = 0;
|
|
for (int i = 0; i < N; i++) {
|
|
x += f(1.0, 2.0, 3.0, 4.0);
|
|
}
|
|
final double expected = N * (1.0 + 2.0 + 3.0 + 4.0);
|
|
expectApprox(x, expected);
|
|
}
|
|
}
|
|
|
|
class Floatx10 extends FfiBenchmarkBase {
|
|
final Function10double f;
|
|
|
|
Floatx10({isLeaf: false})
|
|
: f = isLeaf
|
|
? ffiTestFunctions.lookupFunction<NativeFunction10Float,
|
|
Function10double>('Function10Float', isLeaf: true)
|
|
: ffiTestFunctions.lookupFunction<NativeFunction10Float,
|
|
Function10double>('Function10Float', isLeaf: false),
|
|
super('FfiCall.Floatx10', isLeaf: isLeaf);
|
|
|
|
@override
|
|
void run() {
|
|
double x = 0;
|
|
for (int i = 0; i < N; i++) {
|
|
x += f(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0);
|
|
}
|
|
final double expected =
|
|
N * (1.0 + 2.0 + 3.0 + 4.0 + 5.0 + 6.0 + 7.0 + 8.0 + 9.0 + 10.0);
|
|
expectApprox(x, expected);
|
|
}
|
|
}
|
|
|
|
class Floatx20 extends FfiBenchmarkBase {
|
|
final Function20double f;
|
|
|
|
Floatx20({isLeaf: false})
|
|
: f = isLeaf
|
|
? ffiTestFunctions.lookupFunction<NativeFunction20Float,
|
|
Function20double>('Function20Float', isLeaf: true)
|
|
: ffiTestFunctions.lookupFunction<NativeFunction20Float,
|
|
Function20double>('Function20Float', isLeaf: false),
|
|
super('FfiCall.Floatx20', isLeaf: isLeaf);
|
|
|
|
@override
|
|
void run() {
|
|
double x = 0;
|
|
for (int i = 0; i < N; i++) {
|
|
x += f(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);
|
|
}
|
|
final double expected = N *
|
|
(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);
|
|
expectApprox(x, expected);
|
|
}
|
|
}
|
|
|
|
class Doublex01 extends FfiBenchmarkBase {
|
|
final Function1double f;
|
|
|
|
Doublex01({isLeaf: false})
|
|
: f = isLeaf
|
|
? ffiTestFunctions.lookupFunction<NativeFunction1Double,
|
|
Function1double>('Function1Double', isLeaf: true)
|
|
: ffiTestFunctions.lookupFunction<NativeFunction1Double,
|
|
Function1double>('Function1Double', isLeaf: false),
|
|
super('FfiCall.Doublex01', isLeaf: isLeaf);
|
|
|
|
@override
|
|
void run() {
|
|
double x = 0.0;
|
|
for (int i = 0; i < N; i++) {
|
|
x += f(17.0);
|
|
}
|
|
final double expected = N * (17.0 + 42.0);
|
|
expectApprox(x, expected);
|
|
}
|
|
}
|
|
|
|
class Doublex02 extends FfiBenchmarkBase {
|
|
final Function2double f;
|
|
|
|
Doublex02({isLeaf: false})
|
|
: f = isLeaf
|
|
? ffiTestFunctions.lookupFunction<NativeFunction2Double,
|
|
Function2double>('Function2Double', isLeaf: true)
|
|
: ffiTestFunctions.lookupFunction<NativeFunction2Double,
|
|
Function2double>('Function2Double', isLeaf: false),
|
|
super('FfiCall.Doublex02', isLeaf: isLeaf);
|
|
|
|
@override
|
|
void run() {
|
|
double x = 0;
|
|
for (int i = 0; i < N; i++) {
|
|
x += f(1.0, 2.0);
|
|
}
|
|
final double expected = N * (1.0 + 2.0);
|
|
expectApprox(x, expected);
|
|
}
|
|
}
|
|
|
|
class Doublex04 extends FfiBenchmarkBase {
|
|
final Function4double f;
|
|
|
|
Doublex04({isLeaf: false})
|
|
: f = isLeaf
|
|
? ffiTestFunctions.lookupFunction<NativeFunction4Double,
|
|
Function4double>('Function4Double', isLeaf: true)
|
|
: ffiTestFunctions.lookupFunction<NativeFunction4Double,
|
|
Function4double>('Function4Double', isLeaf: false),
|
|
super('FfiCall.Doublex04', isLeaf: isLeaf);
|
|
|
|
@override
|
|
void run() {
|
|
double x = 0;
|
|
for (int i = 0; i < N; i++) {
|
|
x += f(1.0, 2.0, 3.0, 4.0);
|
|
}
|
|
final double expected = N * (1.0 + 2.0 + 3.0 + 4.0);
|
|
expectApprox(x, expected);
|
|
}
|
|
}
|
|
|
|
class Doublex10 extends FfiBenchmarkBase {
|
|
final Function10double f;
|
|
|
|
Doublex10({isLeaf: false})
|
|
: f = isLeaf
|
|
? ffiTestFunctions.lookupFunction<NativeFunction10Double,
|
|
Function10double>('Function10Double', isLeaf: true)
|
|
: ffiTestFunctions.lookupFunction<NativeFunction10Double,
|
|
Function10double>('Function10Double', isLeaf: false),
|
|
super('FfiCall.Doublex10', isLeaf: isLeaf);
|
|
|
|
@override
|
|
void run() {
|
|
double x = 0;
|
|
for (int i = 0; i < N; i++) {
|
|
x += f(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0);
|
|
}
|
|
final double expected =
|
|
N * (1.0 + 2.0 + 3.0 + 4.0 + 5.0 + 6.0 + 7.0 + 8.0 + 9.0 + 10.0);
|
|
expectApprox(x, expected);
|
|
}
|
|
}
|
|
|
|
class Doublex20 extends FfiBenchmarkBase {
|
|
final Function20double f;
|
|
|
|
Doublex20({isLeaf: false})
|
|
: f = isLeaf
|
|
? ffiTestFunctions.lookupFunction<NativeFunction20Double,
|
|
Function20double>('Function20Double', isLeaf: true)
|
|
: ffiTestFunctions.lookupFunction<NativeFunction20Double,
|
|
Function20double>('Function20Double', isLeaf: false),
|
|
super('FfiCall.Doublex20', isLeaf: isLeaf);
|
|
|
|
@override
|
|
void run() {
|
|
double x = 0;
|
|
for (int i = 0; i < N; i++) {
|
|
x += f(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);
|
|
}
|
|
final double expected = N *
|
|
(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);
|
|
expectApprox(x, expected);
|
|
}
|
|
}
|
|
|
|
class PointerUint8x01 extends FfiBenchmarkBase {
|
|
final Function1PointerUint8 f;
|
|
|
|
PointerUint8x01({isLeaf: false})
|
|
: f = isLeaf
|
|
? ffiTestFunctions.lookupFunction<Function1PointerUint8,
|
|
Function1PointerUint8>('Function1PointerUint8', isLeaf: true)
|
|
: ffiTestFunctions.lookupFunction<Function1PointerUint8,
|
|
Function1PointerUint8>('Function1PointerUint8', isLeaf: false),
|
|
super('FfiCall.PointerUint8x01', isLeaf: isLeaf);
|
|
|
|
Pointer<Uint8> p1 = nullptr;
|
|
@override
|
|
void setup() => p1 = calloc(N + 1);
|
|
@override
|
|
void teardown() => calloc.free(p1);
|
|
|
|
@override
|
|
void run() {
|
|
Pointer<Uint8> x = p1;
|
|
for (int i = 0; i < N; i++) {
|
|
x = f(x);
|
|
}
|
|
expectApprox(x.address, p1.address + N);
|
|
}
|
|
}
|
|
|
|
class PointerUint8x02 extends FfiBenchmarkBase {
|
|
final Function2PointerUint8 f;
|
|
|
|
PointerUint8x02({isLeaf: false})
|
|
: f = isLeaf
|
|
? ffiTestFunctions.lookupFunction<Function2PointerUint8,
|
|
Function2PointerUint8>('Function2PointerUint8', isLeaf: true)
|
|
: ffiTestFunctions.lookupFunction<Function2PointerUint8,
|
|
Function2PointerUint8>('Function2PointerUint8', isLeaf: false),
|
|
super('FfiCall.PointerUint8x02', isLeaf: isLeaf);
|
|
|
|
Pointer<Uint8> p1 = nullptr;
|
|
Pointer<Uint8> p2 = nullptr;
|
|
|
|
@override
|
|
void setup() {
|
|
p1 = calloc(N + 1);
|
|
p2 = p1.elementAt(1);
|
|
}
|
|
|
|
@override
|
|
void teardown() {
|
|
calloc.free(p1);
|
|
}
|
|
|
|
@override
|
|
void run() {
|
|
Pointer<Uint8> x = p1;
|
|
for (int i = 0; i < N; i++) {
|
|
x = f(x, p2);
|
|
}
|
|
expectEquals(x.address, p1.address + N * sizeOf<Uint8>());
|
|
}
|
|
}
|
|
|
|
class PointerUint8x04 extends FfiBenchmarkBase {
|
|
final Function4PointerUint8 f;
|
|
|
|
PointerUint8x04({isLeaf: false})
|
|
: f = isLeaf
|
|
? ffiTestFunctions.lookupFunction<Function4PointerUint8,
|
|
Function4PointerUint8>('Function4PointerUint8', isLeaf: true)
|
|
: ffiTestFunctions.lookupFunction<Function4PointerUint8,
|
|
Function4PointerUint8>('Function4PointerUint8', isLeaf: false),
|
|
super('FfiCall.PointerUint8x04', isLeaf: isLeaf);
|
|
|
|
Pointer<Uint8> p1 = nullptr;
|
|
Pointer<Uint8> p2 = nullptr;
|
|
Pointer<Uint8> p3 = nullptr;
|
|
Pointer<Uint8> p4 = nullptr;
|
|
|
|
@override
|
|
void setup() {
|
|
p1 = calloc(N + 1);
|
|
p2 = p1.elementAt(1);
|
|
p3 = p1.elementAt(2);
|
|
p4 = p1.elementAt(3);
|
|
}
|
|
|
|
@override
|
|
void teardown() {
|
|
calloc.free(p1);
|
|
}
|
|
|
|
@override
|
|
void run() {
|
|
Pointer<Uint8> x = p1;
|
|
for (int i = 0; i < N; i++) {
|
|
x = f(x, p2, p3, p4);
|
|
}
|
|
expectEquals(x.address, p1.address + N * sizeOf<Uint8>());
|
|
}
|
|
}
|
|
|
|
class PointerUint8x10 extends FfiBenchmarkBase {
|
|
final Function10PointerUint8 f;
|
|
|
|
PointerUint8x10({isLeaf: false})
|
|
: f = isLeaf
|
|
? ffiTestFunctions.lookupFunction<Function10PointerUint8,
|
|
Function10PointerUint8>('Function10PointerUint8', isLeaf: true)
|
|
: ffiTestFunctions
|
|
.lookupFunction<Function10PointerUint8, Function10PointerUint8>(
|
|
'Function10PointerUint8',
|
|
isLeaf: false),
|
|
super('FfiCall.PointerUint8x10', isLeaf: isLeaf);
|
|
|
|
Pointer<Uint8> p1 = nullptr;
|
|
Pointer<Uint8> p2 = nullptr;
|
|
Pointer<Uint8> p3 = nullptr;
|
|
Pointer<Uint8> p4 = nullptr;
|
|
Pointer<Uint8> p5 = nullptr;
|
|
Pointer<Uint8> p6 = nullptr;
|
|
Pointer<Uint8> p7 = nullptr;
|
|
Pointer<Uint8> p8 = nullptr;
|
|
Pointer<Uint8> p9 = nullptr;
|
|
Pointer<Uint8> p10 = nullptr;
|
|
|
|
@override
|
|
void setup() {
|
|
p1 = calloc(N + 1);
|
|
p2 = p1.elementAt(1);
|
|
p3 = p1.elementAt(2);
|
|
p4 = p1.elementAt(3);
|
|
p5 = p1.elementAt(4);
|
|
p6 = p1.elementAt(5);
|
|
p7 = p1.elementAt(6);
|
|
p8 = p1.elementAt(7);
|
|
p9 = p1.elementAt(8);
|
|
p10 = p1.elementAt(9);
|
|
}
|
|
|
|
@override
|
|
void teardown() {
|
|
calloc.free(p1);
|
|
}
|
|
|
|
@override
|
|
void run() {
|
|
Pointer<Uint8> x = p1;
|
|
for (int i = 0; i < N; i++) {
|
|
x = f(x, p2, p3, p4, p5, p6, p7, p8, p9, p10);
|
|
}
|
|
expectEquals(x.address, p1.address + N * sizeOf<Uint8>());
|
|
}
|
|
}
|
|
|
|
class PointerUint8x20 extends FfiBenchmarkBase {
|
|
final Function20PointerUint8 f;
|
|
|
|
PointerUint8x20({isLeaf: false})
|
|
: f = isLeaf
|
|
? ffiTestFunctions.lookupFunction<Function20PointerUint8,
|
|
Function20PointerUint8>('Function20PointerUint8', isLeaf: true)
|
|
: ffiTestFunctions
|
|
.lookupFunction<Function20PointerUint8, Function20PointerUint8>(
|
|
'Function20PointerUint8',
|
|
isLeaf: false),
|
|
super('FfiCall.PointerUint8x20', isLeaf: isLeaf);
|
|
|
|
Pointer<Uint8> p1 = nullptr;
|
|
Pointer<Uint8> p2 = nullptr;
|
|
Pointer<Uint8> p3 = nullptr;
|
|
Pointer<Uint8> p4 = nullptr;
|
|
Pointer<Uint8> p5 = nullptr;
|
|
Pointer<Uint8> p6 = nullptr;
|
|
Pointer<Uint8> p7 = nullptr;
|
|
Pointer<Uint8> p8 = nullptr;
|
|
Pointer<Uint8> p9 = nullptr;
|
|
Pointer<Uint8> p10 = nullptr;
|
|
Pointer<Uint8> p11 = nullptr;
|
|
Pointer<Uint8> p12 = nullptr;
|
|
Pointer<Uint8> p13 = nullptr;
|
|
Pointer<Uint8> p14 = nullptr;
|
|
Pointer<Uint8> p15 = nullptr;
|
|
Pointer<Uint8> p16 = nullptr;
|
|
Pointer<Uint8> p17 = nullptr;
|
|
Pointer<Uint8> p18 = nullptr;
|
|
Pointer<Uint8> p19 = nullptr;
|
|
Pointer<Uint8> p20 = nullptr;
|
|
|
|
@override
|
|
void setup() {
|
|
p1 = calloc(N + 1);
|
|
p2 = p1.elementAt(1);
|
|
p3 = p1.elementAt(2);
|
|
p4 = p1.elementAt(3);
|
|
p5 = p1.elementAt(4);
|
|
p6 = p1.elementAt(5);
|
|
p7 = p1.elementAt(6);
|
|
p8 = p1.elementAt(7);
|
|
p9 = p1.elementAt(8);
|
|
p10 = p1.elementAt(9);
|
|
p11 = p1.elementAt(10);
|
|
p12 = p1.elementAt(11);
|
|
p13 = p1.elementAt(12);
|
|
p14 = p1.elementAt(13);
|
|
p15 = p1.elementAt(14);
|
|
p16 = p1.elementAt(15);
|
|
p17 = p1.elementAt(16);
|
|
p18 = p1.elementAt(17);
|
|
p19 = p1.elementAt(18);
|
|
p20 = p1.elementAt(19);
|
|
}
|
|
|
|
@override
|
|
void teardown() {
|
|
calloc.free(p1);
|
|
}
|
|
|
|
@override
|
|
void run() {
|
|
Pointer<Uint8> x = p1;
|
|
for (int i = 0; i < N; i++) {
|
|
x = f(x, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15,
|
|
p16, p17, p18, p19, p20);
|
|
}
|
|
expectEquals(x.address, p1.address + N * sizeOf<Uint8>());
|
|
}
|
|
}
|
|
|
|
class MyClass {
|
|
int a;
|
|
MyClass(this.a);
|
|
}
|
|
|
|
class Handlex01 extends FfiBenchmarkBase {
|
|
final Function1Object f;
|
|
|
|
Handlex01()
|
|
: f = ffiTestFunctions.lookupFunction<NativeFunction1Handle,
|
|
Function1Object>('Function1Handle', isLeaf: false),
|
|
super('FfiCall.Handlex01', isLeaf: false);
|
|
|
|
@override
|
|
void run() {
|
|
final p1 = MyClass(123);
|
|
Object x = p1;
|
|
for (int i = 0; i < N; i++) {
|
|
x = f(x);
|
|
}
|
|
expectIdentical(x, p1);
|
|
}
|
|
}
|
|
|
|
class Handlex02 extends FfiBenchmarkBase {
|
|
final Function2Object f;
|
|
|
|
Handlex02()
|
|
: f = ffiTestFunctions.lookupFunction<NativeFunction2Handle,
|
|
Function2Object>('Function2Handle', isLeaf: false),
|
|
super('FfiCall.Handlex02', isLeaf: false);
|
|
|
|
@override
|
|
void run() {
|
|
final p1 = MyClass(123);
|
|
final p2 = MyClass(2);
|
|
Object x = p1;
|
|
for (int i = 0; i < N; i++) {
|
|
x = f(x, p2);
|
|
}
|
|
expectIdentical(x, p1);
|
|
}
|
|
}
|
|
|
|
class Handlex04 extends FfiBenchmarkBase {
|
|
final Function4Object f;
|
|
|
|
Handlex04()
|
|
: f = ffiTestFunctions.lookupFunction<NativeFunction4Handle,
|
|
Function4Object>('Function4Handle', isLeaf: false),
|
|
super('FfiCall.Handlex04', isLeaf: false);
|
|
|
|
@override
|
|
void run() {
|
|
final p1 = MyClass(123);
|
|
final p2 = MyClass(2);
|
|
final p3 = MyClass(3);
|
|
final p4 = MyClass(4);
|
|
Object x = p1;
|
|
for (int i = 0; i < N; i++) {
|
|
x = f(x, p2, p3, p4);
|
|
}
|
|
expectIdentical(x, p1);
|
|
}
|
|
}
|
|
|
|
class Handlex10 extends FfiBenchmarkBase {
|
|
final Function10Object f;
|
|
|
|
Handlex10()
|
|
: f = ffiTestFunctions.lookupFunction<NativeFunction10Handle,
|
|
Function10Object>('Function10Handle', isLeaf: false),
|
|
super('FfiCall.Handlex10', isLeaf: false);
|
|
|
|
@override
|
|
void run() {
|
|
final p1 = MyClass(123);
|
|
final p2 = MyClass(2);
|
|
final p3 = MyClass(3);
|
|
final p4 = MyClass(4);
|
|
final p5 = MyClass(5);
|
|
final p6 = MyClass(6);
|
|
final p7 = MyClass(7);
|
|
final p8 = MyClass(8);
|
|
final p9 = MyClass(9);
|
|
final p10 = MyClass(10);
|
|
Object x = p1;
|
|
for (int i = 0; i < N; i++) {
|
|
x = f(x, p2, p3, p4, p5, p6, p7, p8, p9, p10);
|
|
}
|
|
expectIdentical(x, p1);
|
|
}
|
|
}
|
|
|
|
class Handlex20 extends FfiBenchmarkBase {
|
|
final Function20Object f;
|
|
|
|
Handlex20()
|
|
: f = ffiTestFunctions.lookupFunction<NativeFunction20Handle,
|
|
Function20Object>('Function20Handle', isLeaf: false),
|
|
super('FfiCall.Handlex20', isLeaf: false);
|
|
|
|
@override
|
|
void run() {
|
|
final p1 = MyClass(123);
|
|
final p2 = MyClass(2);
|
|
final p3 = MyClass(3);
|
|
final p4 = MyClass(4);
|
|
final p5 = MyClass(5);
|
|
final p6 = MyClass(6);
|
|
final p7 = MyClass(7);
|
|
final p8 = MyClass(8);
|
|
final p9 = MyClass(9);
|
|
final p10 = MyClass(10);
|
|
final p11 = MyClass(11);
|
|
final p12 = MyClass(12);
|
|
final p13 = MyClass(13);
|
|
final p14 = MyClass(14);
|
|
final p15 = MyClass(15);
|
|
final p16 = MyClass(16);
|
|
final p17 = MyClass(17);
|
|
final p18 = MyClass(18);
|
|
final p19 = MyClass(19);
|
|
final p20 = MyClass(20);
|
|
Object x = p1;
|
|
for (int i = 0; i < N; i++) {
|
|
x = f(x, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15,
|
|
p16, p17, p18, p19, p20);
|
|
}
|
|
expectIdentical(x, p1);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Main driver.
|
|
//
|
|
void main(List<String> args) {
|
|
final benchmarks = [
|
|
() => Uint8x01(),
|
|
() => Uint8x01(isLeaf: true),
|
|
() => Uint16x01(),
|
|
() => Uint32x01(),
|
|
() => Uint64x01(),
|
|
() => Int8x01(),
|
|
() => Int8x01(isLeaf: true),
|
|
() => Int16x01(),
|
|
() => Int32x01(),
|
|
() => Int32x02(),
|
|
() => Int32x04(),
|
|
() => Int32x10(),
|
|
() => Int32x20(),
|
|
() => Int64x01(),
|
|
() => Int64x02(),
|
|
() => Int64x04(),
|
|
() => Int64x10(),
|
|
() => Int64x20(),
|
|
() => Int64x20(isLeaf: true),
|
|
() => Int64Mintx01(),
|
|
() => Int64Mintx01(isLeaf: true),
|
|
() => Floatx01(),
|
|
() => Floatx02(),
|
|
() => Floatx04(),
|
|
() => Floatx10(),
|
|
() => Floatx20(),
|
|
() => Floatx20(isLeaf: true),
|
|
() => Doublex01(),
|
|
() => Doublex02(),
|
|
() => Doublex04(),
|
|
() => Doublex10(),
|
|
() => Doublex20(),
|
|
() => Doublex20(isLeaf: true),
|
|
() => PointerUint8x01(),
|
|
() => PointerUint8x02(),
|
|
() => PointerUint8x04(),
|
|
() => PointerUint8x10(),
|
|
() => PointerUint8x20(),
|
|
() => PointerUint8x20(isLeaf: true),
|
|
() => Handlex01(),
|
|
() => Handlex02(),
|
|
() => Handlex04(),
|
|
() => Handlex10(),
|
|
() => Handlex20(),
|
|
];
|
|
final filter = args.length == 1 ? args[0] : null;
|
|
for (final benchmark in benchmarks) {
|
|
final b = benchmark();
|
|
final run = (filter != null) ? b.name.contains(filter) : true;
|
|
if (run) {
|
|
b.report();
|
|
}
|
|
}
|
|
}
|