Files
sdk/benchmarks/FfiMemory/dart/FfiMemory.dart
T
Daco Harkes fbf13f561f [benchmarks/ffi] Add micro and macro benchmarks for dart:ffi
Adds micro benchmarks to measure low level (1) C memory reads and writes from Dart and (2) calls from Dart into C. This CL also adds a macro benchmark to measure overall performance using BoringSSL to digest data. The shared libraries are precompiled for Linux and live in cipd packages. The benchmarks run on all hardware architectures (with the exception of Linux'es hardfp on Arm32: https://github.com/dart-lang/sdk/issues/36309).

Issue: https://github.com/dart-lang/sdk/issues/36247

Change-Id: I8dfb30cc66a26a2942bb09194c5eb0da0b6ca1b5
Cq-Include-Trybots: luci.dart.try:benchmark-linux-try
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/108724
Commit-Queue: Daco Harkes <dacoharkes@google.com>
Reviewed-by: Jonas Termansen <sortie@google.com>
Auto-Submit: Daco Harkes <dacoharkes@google.com>
2019-07-19 14:59:57 +00:00

432 lines
10 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.
// 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<Int8> pointer, int length) {
for (int i = 0; i < length; i++) {
pointer.elementAt(i).store(1);
}
}
void doStoreUint8(Pointer<Uint8> pointer, int length) {
for (int i = 0; i < length; i++) {
pointer.elementAt(i).store(1);
}
}
void doStoreInt16(Pointer<Int16> pointer, int length) {
for (int i = 0; i < length; i++) {
pointer.elementAt(i).store(1);
}
}
void doStoreUint16(Pointer<Uint16> pointer, int length) {
for (int i = 0; i < length; i++) {
pointer.elementAt(i).store(1);
}
}
void doStoreInt32(Pointer<Int32> pointer, int length) {
for (int i = 0; i < length; i++) {
pointer.elementAt(i).store(1);
}
}
void doStoreUint32(Pointer<Uint32> pointer, int length) {
for (int i = 0; i < length; i++) {
pointer.elementAt(i).store(1);
}
}
void doStoreInt64(Pointer<Int64> pointer, int length) {
for (int i = 0; i < length; i++) {
pointer.elementAt(i).store(1);
}
}
void doStoreUint64(Pointer<Uint64> pointer, int length) {
for (int i = 0; i < length; i++) {
pointer.elementAt(i).store(1);
}
}
void doStoreFloat(Pointer<Float> pointer, int length) {
for (int i = 0; i < length; i++) {
pointer.elementAt(i).store(1.0);
}
}
void doStoreDouble(Pointer<Double> pointer, int length) {
for (int i = 0; i < length; i++) {
pointer.elementAt(i).store(1.0);
}
}
void doStorePointer(
Pointer<Pointer<Int8>> pointer, int length, Pointer<Int8> data) {
for (int i = 0; i < length; i++) {
pointer.elementAt(i).store(data);
}
}
void doStoreInt64Mint(Pointer<Int64> pointer, int length) {
for (int i = 0; i < length; i++) {
pointer.elementAt(i).store(0x7FFFFFFFFFFFFFFF);
}
}
//
// Pointer load.
//
int doLoadInt8(Pointer<Int8> pointer, int length) {
int x = 0;
for (int i = 0; i < length; i++) {
x += pointer.elementAt(i).load<int>();
}
return x;
}
int doLoadUint8(Pointer<Uint8> pointer, int length) {
int x = 0;
for (int i = 0; i < length; i++) {
x += pointer.elementAt(i).load<int>();
}
return x;
}
int doLoadInt16(Pointer<Int16> pointer, int length) {
int x = 0;
for (int i = 0; i < length; i++) {
x += pointer.elementAt(i).load<int>();
}
return x;
}
int doLoadUint16(Pointer<Uint16> pointer, int length) {
int x = 0;
for (int i = 0; i < length; i++) {
x += pointer.elementAt(i).load<int>();
}
return x;
}
int doLoadInt32(Pointer<Int32> pointer, int length) {
int x = 0;
for (int i = 0; i < length; i++) {
x += pointer.elementAt(i).load<int>();
}
return x;
}
int doLoadUint32(Pointer<Uint32> pointer, int length) {
int x = 0;
for (int i = 0; i < length; i++) {
x += pointer.elementAt(i).load<int>();
}
return x;
}
int doLoadInt64(Pointer<Int64> pointer, int length) {
int x = 0;
for (int i = 0; i < length; i++) {
x += pointer.elementAt(i).load<int>();
}
return x;
}
int doLoadUint64(Pointer<Uint64> pointer, int length) {
int x = 0;
for (int i = 0; i < length; i++) {
x += pointer.elementAt(i).load<int>();
}
return x;
}
double doLoadFloat(Pointer<Float> pointer, int length) {
double x = 0;
for (int i = 0; i < length; i++) {
x += pointer.elementAt(i).load<double>();
}
return x;
}
double doLoadDouble(Pointer<Double> pointer, int length) {
double x = 0;
for (int i = 0; i < length; i++) {
x += pointer.elementAt(i).load<double>();
}
return x;
}
// Aggregates pointers through aggregrating their addresses.
int doLoadPointer(Pointer<Pointer<Int8>> pointer, int length) {
Pointer<Int8> 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<Int64> pointer, int length) {
int x = 0;
for (int i = 0; i < length; i++) {
x += pointer.elementAt(i).load<int>();
}
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<Int8> 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<Uint8> 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<Int16> 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<Uint16> 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<Int32> 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<Uint32> 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<Int64> 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<Uint64> 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<Float> 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<Double> 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<Int8>> pointer;
Pointer<Int8> 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<Int64> 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());
}