[benchmark] Adds native call benchmark.

Adds new benchmarks for native calls, parallel to the
existing benchmark for FFI calls.

This makes it possible (with some caveats) to compare
overheads of calling through native and FFI.

Local results on Linux, x64, AOT (for reference):

NativeCall.Uint8x01(RunTime): 585.9797891036907 us.
NativeCall.Int64x20(RunTime): 1340.2451440053583 us.
NativeCall.Doublex01(RunTime): 694.4875 us.
NativeCall.Doublex20(RunTime): 1610.102172164119 us.
NativeCall.Handlex01(RunTime): 735.7863184994483 us.
NativeCall.Handlex20(RunTime): 836.6783772480134 us.

FfiCall.Uint8x01(RunTime): 202.5837131570951 us.
FfiCall.Int64x20(RunTime): 328.16931911402787 us.
FfiCall.Doublex01(RunTime): 220.58028231142478 us.
FfiCall.Doublex20(RunTime): 373.4350261389096 us.
FfiCall.Handlex01(RunTime): 357.4213724088635 us.
FfiCall.Handlex20(RunTime): 1152.427995391705 us.

TEST=Manually ran benchmark locally.
Change-Id: Ib28455fbd9f739c1e3ba487b932b464fc12b7e04
Cq-Include-Trybots: luci.dart.try:benchmark-linux-try
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/218920
Commit-Queue: Clement Skau <cskau@google.com>
Reviewed-by: Daco Harkes <dacoharkes@google.com>
This commit is contained in:
Clement Skau 2021-11-04 15:16:24 +00:00 committed by commit-bot@chromium.org
parent 6732808c40
commit 36652d3b1a
9 changed files with 872 additions and 0 deletions

9
DEPS
View file

@ -656,6 +656,15 @@ deps = {
],
"dep_type": "cipd",
},
Var("dart_root") + "/benchmarks/NativeCall/native/out/": {
"packages": [
{
"package": "dart/benchmarks/nativecall",
"version": "w1JKzCIHSfDNIjqnioMUPq0moCXKwX67aUfhyrvw4E0C",
},
],
"dep_type": "cipd",
},
Var("dart_root") + "/third_party/browsers/chrome": {
"packages": [
{

View file

@ -0,0 +1,277 @@
// Copyright (c) 2021, 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.
// These micro benchmarks track the speed of native calls.
import 'dart:ffi';
import 'dart:io';
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.
final nativeFunctionsLib = dlopenPlatformSpecific('native_functions',
path: Platform.script.resolve('../native/out/').path);
final getRootLibraryUrl = nativeFunctionsLib
.lookupFunction<Handle Function(), Object Function()>('GetRootLibraryUrl');
final setNativeResolverForTest = nativeFunctionsLib.lookupFunction<
Void Function(Handle), void Function(Object)>('SetNativeResolverForTest');
//
// Benchmark fixtures.
//
abstract class NativeCallBenchmarkBase extends BenchmarkBase {
NativeCallBenchmarkBase(String name) : super(name);
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 NativeCallBenchmarkBase {
Uint8x01() : super('NativeCall.Uint8x01');
@pragma('vm:external-name', 'Function1Uint8')
external static int f(int a);
@override
void run() {
int x = 0;
for (int i = 0; i < N; i++) {
x += f(17);
}
expectEquals(x, N * 17 + N * 42);
}
}
class Int64x20 extends NativeCallBenchmarkBase {
Int64x20() : super('NativeCall.Int64x20');
@pragma('vm:external-name', 'Function20Int64')
external static int f(
int a,
int b,
int c,
int d,
int e,
int f,
int g,
int h,
int i,
int j,
int k,
int l,
int m,
int n,
int o,
int p,
int q,
int r,
int s,
int t);
@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 Doublex01 extends NativeCallBenchmarkBase {
Doublex01() : super('NativeCall.Doublex01');
@pragma('vm:external-name', 'Function1Double')
external static double f(double a);
@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 Doublex20 extends NativeCallBenchmarkBase {
Doublex20() : super('NativeCall.Doublex20');
@pragma('vm:external-name', 'Function20Double')
external static double f(
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);
@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 MyClass {
int a;
MyClass(this.a);
}
class Handlex01 extends NativeCallBenchmarkBase {
Handlex01() : super('NativeCall.Handlex01');
@pragma('vm:external-name', 'Function1Handle')
external static Object f(Object a);
@override
void run() {
final p1 = MyClass(123);
Object x = p1;
for (int i = 0; i < N; i++) {
x = f(x);
}
expectIdentical(x, p1);
}
}
class Handlex20 extends NativeCallBenchmarkBase {
Handlex20() : super('NativeCall.Handlex20');
@pragma('vm:external-name', 'Function20Handle')
external static Object f(
Object a,
Object b,
Object c,
Object d,
Object e,
Object f,
Object g,
Object h,
Object i,
Object j,
Object k,
Object l,
Object m,
Object n,
Object o,
Object p,
Object q,
Object r,
Object s,
Object t);
@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() {
setNativeResolverForTest(getRootLibraryUrl());
final benchmarks = [
() => Uint8x01(),
() => Int64x20(),
() => Doublex01(),
() => Doublex20(),
() => Handlex01(),
() => Handlex20(),
];
for (final benchmark in benchmarks) {
benchmark().report();
}
}

View file

@ -0,0 +1,61 @@
// Copyright (c) 2021, 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 arm = 'arm';
const arm64 = 'arm64';
const ia32 = 'ia32';
const x64 = 'x64';
// https://stackoverflow.com/questions/45125516/possible-values-for-uname-m
final _unames = {
'arm': arm,
'aarch64_be': arm64,
'aarch64': arm64,
'armv8b': arm64,
'armv8l': arm64,
'i386': ia32,
'i686': ia32,
'x86_64': x64,
};
String _checkRunningMode(String architecture) {
// Check if we're running in 32bit mode.
final int pointerSize = sizeOf<IntPtr>();
if (pointerSize == 4 && architecture == x64) return ia32;
if (pointerSize == 4 && architecture == arm64) return arm;
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(x64)}/$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);
return DynamicLibrary.open(fullPath);
}

View file

@ -0,0 +1,279 @@
// Copyright (c) 2021, 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.
// These micro benchmarks track the speed of native calls.
// @dart=2.9
import 'dart:ffi';
import 'dart:io';
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.
final nativeFunctionsLib = dlopenPlatformSpecific('native_functions',
path: Platform.script.resolve('../native/out/').path);
final getRootLibraryUrl = nativeFunctionsLib
.lookupFunction<Handle Function(), Object Function()>('GetRootLibraryUrl');
final setNativeResolverForTest = nativeFunctionsLib.lookupFunction<
Void Function(Handle), void Function(Object)>('SetNativeResolverForTest');
//
// Benchmark fixtures.
//
abstract class NativeCallBenchmarkBase extends BenchmarkBase {
NativeCallBenchmarkBase(String name) : super(name);
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 NativeCallBenchmarkBase {
Uint8x01() : super('NativeCall.Uint8x01');
@pragma('vm:external-name', 'Function1Uint8')
external static int f(int a);
@override
void run() {
int x = 0;
for (int i = 0; i < N; i++) {
x += f(17);
}
expectEquals(x, N * 17 + N * 42);
}
}
class Int64x20 extends NativeCallBenchmarkBase {
Int64x20() : super('NativeCall.Int64x20');
@pragma('vm:external-name', 'Function20Int64')
external static int f(
int a,
int b,
int c,
int d,
int e,
int f,
int g,
int h,
int i,
int j,
int k,
int l,
int m,
int n,
int o,
int p,
int q,
int r,
int s,
int t);
@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 Doublex01 extends NativeCallBenchmarkBase {
Doublex01() : super('NativeCall.Doublex01');
@pragma('vm:external-name', 'Function1Double')
external static double f(double a);
@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 Doublex20 extends NativeCallBenchmarkBase {
Doublex20() : super('NativeCall.Doublex20');
@pragma('vm:external-name', 'Function20Double')
external static double f(
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);
@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 MyClass {
int a;
MyClass(this.a);
}
class Handlex01 extends NativeCallBenchmarkBase {
Handlex01() : super('NativeCall.Handlex01');
@pragma('vm:external-name', 'Function1Handle')
external static Object f(Object a);
@override
void run() {
final p1 = MyClass(123);
Object x = p1;
for (int i = 0; i < N; i++) {
x = f(x);
}
expectIdentical(x, p1);
}
}
class Handlex20 extends NativeCallBenchmarkBase {
Handlex20() : super('NativeCall.Handlex20');
@pragma('vm:external-name', 'Function20Handle')
external static Object f(
Object a,
Object b,
Object c,
Object d,
Object e,
Object f,
Object g,
Object h,
Object i,
Object j,
Object k,
Object l,
Object m,
Object n,
Object o,
Object p,
Object q,
Object r,
Object s,
Object t);
@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() {
setNativeResolverForTest(getRootLibraryUrl());
final benchmarks = [
() => Uint8x01(),
() => Int64x20(),
() => Doublex01(),
() => Doublex20(),
() => Handlex01(),
() => Handlex20(),
];
for (final benchmark in benchmarks) {
benchmark().report();
}
}

View file

@ -0,0 +1,63 @@
// Copyright (c) 2021, 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.
// @dart=2.9
import 'dart:ffi';
import 'dart:io';
const arm = 'arm';
const arm64 = 'arm64';
const ia32 = 'ia32';
const x64 = 'x64';
// https://stackoverflow.com/questions/45125516/possible-values-for-uname-m
final _unames = {
'arm': arm,
'aarch64_be': arm64,
'aarch64': arm64,
'armv8b': arm64,
'armv8l': arm64,
'i386': ia32,
'i686': ia32,
'x86_64': x64,
};
String _checkRunningMode(String architecture) {
// Check if we're running in 32bit mode.
final int pointerSize = sizeOf<IntPtr>();
if (pointerSize == 4 && architecture == x64) return ia32;
if (pointerSize == 4 && architecture == arm64) return arm;
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(x64)}/$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);
}

View file

@ -0,0 +1,5 @@
# Copyright (c) 2021, 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/

View file

@ -0,0 +1,57 @@
# Copyright (c) 2021, 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 -I../../../runtime/
.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/nativecall -in out -install-mode copy
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

View file

@ -0,0 +1,119 @@
// Copyright (c) 2021, 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
// TODO(dartbug.com/40579): This requires static linking to either link
// dart.exe or dart_precompiled_runtime.exe on Windows.
// The sample currently fails on Windows in AOT mode.
#include "include/dart_api.h"
#define ENSURE(X) \
if (!(X)) { \
fprintf(stderr, "%s:%d: %s\n", __FILE__, __LINE__, "Check failed: " #X); \
exit(1); \
}
#define ENSURE_VALID(X) ENSURE(!Dart_IsError(X))
//
// Functions under test.
//
void Function1Uint8(Dart_NativeArguments args) {
int64_t arg = 0;
Dart_GetNativeIntegerArgument(args, /*index=*/0, &arg);
Dart_SetIntegerReturnValue(args, arg + 42);
}
void Function20Int64(Dart_NativeArguments args) {
int64_t arg = 0;
int64_t result = 0;
for (int i = 0; i < 20; i++) {
Dart_GetNativeIntegerArgument(args, /*index=*/i, &arg);
result += arg;
}
Dart_SetIntegerReturnValue(args, result);
}
void Function1Double(Dart_NativeArguments args) {
double arg = 0.0;
Dart_GetNativeDoubleArgument(args, /*index=*/0, &arg);
Dart_SetDoubleReturnValue(args, arg + 42.0);
}
void Function20Double(Dart_NativeArguments args) {
double arg = 0;
double result = 0;
for (int i = 0; i < 20; i++) {
Dart_GetNativeDoubleArgument(args, /*index=*/i, &arg);
result += arg;
}
Dart_SetDoubleReturnValue(args, result);
}
void Function1Handle(Dart_NativeArguments args) {
Dart_Handle arg = Dart_GetNativeArgument(args, /*index=*/0);
Dart_SetReturnValue(args, arg);
}
void Function20Handle(Dart_NativeArguments args) {
Dart_Handle arg = Dart_GetNativeArgument(args, /*index=*/0);
Dart_SetReturnValue(args, arg);
}
//
// Test helpers.
//
DART_EXPORT Dart_Handle GetRootLibraryUrl() {
Dart_Handle root_lib = Dart_RootLibrary();
Dart_Handle lib_url = Dart_LibraryUrl(root_lib);
ENSURE_VALID(lib_url);
return lib_url;
}
Dart_NativeFunction NativeEntryResolver(Dart_Handle name,
int num_of_arguments,
bool* auto_setup_scope) {
ENSURE(Dart_IsString(name));
ENSURE(auto_setup_scope != NULL);
*auto_setup_scope = true;
const char* name_str = NULL;
ENSURE_VALID(Dart_StringToCString(name, &name_str));
if (strcmp(name_str, "Function1Uint8") == 0 && num_of_arguments == 1) {
return &Function1Uint8;
} else if (strcmp(name_str, "Function20Int64") == 0 &&
num_of_arguments == 20) {
return &Function20Int64;
} else if (strcmp(name_str, "Function1Double") == 0 &&
num_of_arguments == 1) {
return &Function1Double;
} else if (strcmp(name_str, "Function20Double") == 0 &&
num_of_arguments == 20) {
return &Function20Double;
} else if (strcmp(name_str, "Function1Handle") == 0 &&
num_of_arguments == 1) {
return &Function1Handle;
} else if (strcmp(name_str, "Function20Handle") == 0 &&
num_of_arguments == 20) {
return &Function20Handle;
}
// Unreachable in benchmark.
ENSURE(false);
}
DART_EXPORT void SetNativeResolverForTest(Dart_Handle url) {
Dart_Handle library = Dart_LookupLibrary(url);
ENSURE_VALID(library);
Dart_Handle result =
Dart_SetNativeResolver(library, &NativeEntryResolver, NULL);
ENSURE_VALID(result);
}

View file

@ -184,6 +184,8 @@ EOF
out/ReleaseIA32/run_vm_tests --dfe=out/ReleaseIA32/kernel-service.dart.snapshot --sound-null-safety UseDartApi
out/ReleaseIA32/dart --profile-period=10000 --packages=.packages benchmarks/Example/dart2/Example.dart
out/ReleaseIA32/dart --sound-null-safety --profile-period=10000 --packages=.packages benchmarks/Example/dart/Example.dart
out/ReleaseIA32/dart benchmarks/NativeCall/dart2/NativeCall.dart
out/ReleaseIA32/dart --sound-null-safety benchmarks/NativeCall/dart/NativeCall.dart
out/ReleaseIA32/dart benchmarks/FfiBoringssl/dart2/FfiBoringssl.dart
out/ReleaseIA32/dart --sound-null-safety benchmarks/FfiBoringssl/dart/FfiBoringssl.dart
out/ReleaseIA32/dart benchmarks/FfiCall/dart2/FfiCall.dart