mirror of
https://github.com/dart-lang/sdk
synced 2024-10-07 09:11:55 +00:00
[benchmarks/ffi] Memory access with asTypedList
Adds benchmarks using `asTypedList` on Pointers to investigate from where it pays of to do construct a TypedData to do memory access instead of on the Pointer directly. x64 JIT results: - Memory access on TypedData (int8) is ~2,5 faster than on Pointer. FfiMemory.PointerInt8(RunTime): 72.23885718413639 us. FfiMemory.PointerInt8TypedDataReuse(RunTime): 28.239710263614928 us. - Constructing the TypedData for 1000 reads + 1000 writes takes ~20% of the total runtime, 400 reads or writes on TypedData, 160 reads or writes on Pointer. FfiMemory.PointerInt8TypedDataNew(RunTime): 34.345480148372026 us. FfiMemory.PointerInt8TypedDataReuse(RunTime): 28.239710263614928 us. x64 AOT results: FfiMemory.PointerInt8(RunTime): 13.862134213116345 us. FfiMemory.PointerInt8TypedDataNew(RunTime): 26.149628021913365 us. FfiMemory.PointerInt8TypedDataReuse(RunTime): 24.73322780505299 us. - Using asTypedList is slower. (Some optimizations fail to kick in.) Change-Id: I401edb88baf3a3c5094ecae808f122adf258da28 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/186289 Reviewed-by: Clement Skau <cskau@google.com> Commit-Queue: Daco Harkes <dacoharkes@google.com>
This commit is contained in:
parent
a8b42efa1a
commit
c7422d5277
|
@ -10,6 +10,7 @@
|
|||
// Dart with a specific marshalling and unmarshalling of data.
|
||||
|
||||
import 'dart:ffi';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:ffi/ffi.dart';
|
||||
import 'package:benchmark_harness/benchmark_harness.dart';
|
||||
|
@ -24,6 +25,12 @@ void doStoreInt8(Pointer<Int8> pointer, int length) {
|
|||
}
|
||||
}
|
||||
|
||||
void doStoreInt8TypedData(Int8List typedData, int length) {
|
||||
for (int i = 0; i < length; i++) {
|
||||
typedData[i] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void doStoreUint8(Pointer<Uint8> pointer, int length) {
|
||||
for (int i = 0; i < length; i++) {
|
||||
pointer[i] = 1;
|
||||
|
@ -103,6 +110,14 @@ int doLoadInt8(Pointer<Int8> pointer, int length) {
|
|||
return x;
|
||||
}
|
||||
|
||||
int doLoadInt8TypedData(Int8List typedData, int length) {
|
||||
int x = 0;
|
||||
for (int i = 0; i < length; i++) {
|
||||
x += typedData[i];
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
int doLoadUint8(Pointer<Uint8> pointer, int length) {
|
||||
int x = 0;
|
||||
for (int i = 0; i < length; i++) {
|
||||
|
@ -224,6 +239,62 @@ class PointerInt8 extends BenchmarkBase {
|
|||
}
|
||||
}
|
||||
|
||||
class PointerInt8TypedDataNew extends BenchmarkBase {
|
||||
Pointer<Int8> pointer = nullptr;
|
||||
PointerInt8TypedDataNew() : super('FfiMemory.PointerInt8TypedDataNew');
|
||||
|
||||
@override
|
||||
void setup() {
|
||||
pointer = calloc(N);
|
||||
}
|
||||
|
||||
@override
|
||||
void teardown() {
|
||||
calloc.free(pointer);
|
||||
pointer = nullptr;
|
||||
}
|
||||
|
||||
@override
|
||||
void run() {
|
||||
final typedData = pointer.asTypedList(N);
|
||||
doStoreInt8TypedData(typedData, N);
|
||||
final int x = doLoadInt8TypedData(typedData, N);
|
||||
if (x != N) {
|
||||
throw Exception('$name: Unexpected result: $x, expected $N');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final emptyTypedData = Int8List(0);
|
||||
|
||||
class PointerInt8TypedDataReuse extends BenchmarkBase {
|
||||
Pointer<Int8> pointer = nullptr;
|
||||
Int8List typedData = emptyTypedData;
|
||||
PointerInt8TypedDataReuse() : super('FfiMemory.PointerInt8TypedDataReuse');
|
||||
|
||||
@override
|
||||
void setup() {
|
||||
pointer = calloc(N);
|
||||
typedData = pointer.asTypedList(N);
|
||||
}
|
||||
|
||||
@override
|
||||
void teardown() {
|
||||
calloc.free(pointer);
|
||||
pointer = nullptr;
|
||||
typedData = emptyTypedData;
|
||||
}
|
||||
|
||||
@override
|
||||
void run() {
|
||||
doStoreInt8TypedData(typedData, N);
|
||||
final int x = doLoadInt8TypedData(typedData, N);
|
||||
if (x != N) {
|
||||
throw Exception('$name: Unexpected result: $x, expected $N');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class PointerUint8 extends BenchmarkBase {
|
||||
Pointer<Uint8> pointer = nullptr;
|
||||
PointerUint8() : super('FfiMemory.PointerUint8');
|
||||
|
@ -449,6 +520,8 @@ class PointerInt64Mint extends BenchmarkBase {
|
|||
void main() {
|
||||
final benchmarks = [
|
||||
() => PointerInt8(),
|
||||
() => PointerInt8TypedDataNew(),
|
||||
() => PointerInt8TypedDataReuse(),
|
||||
() => PointerUint8(),
|
||||
() => PointerInt16(),
|
||||
() => PointerUint16(),
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
// @dart=2.9
|
||||
|
||||
import 'dart:ffi';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:ffi/ffi.dart';
|
||||
import 'package:benchmark_harness/benchmark_harness.dart';
|
||||
|
@ -26,6 +27,12 @@ void doStoreInt8(Pointer<Int8> pointer, int length) {
|
|||
}
|
||||
}
|
||||
|
||||
void doStoreInt8TypedData(Int8List typedData, int length) {
|
||||
for (int i = 0; i < length; i++) {
|
||||
typedData[i] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void doStoreUint8(Pointer<Uint8> pointer, int length) {
|
||||
for (int i = 0; i < length; i++) {
|
||||
pointer[i] = 1;
|
||||
|
@ -105,6 +112,14 @@ int doLoadInt8(Pointer<Int8> pointer, int length) {
|
|||
return x;
|
||||
}
|
||||
|
||||
int doLoadInt8TypedData(Int8List typedData, int length) {
|
||||
int x = 0;
|
||||
for (int i = 0; i < length; i++) {
|
||||
x += typedData[i];
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
int doLoadUint8(Pointer<Uint8> pointer, int length) {
|
||||
int x = 0;
|
||||
for (int i = 0; i < length; i++) {
|
||||
|
@ -226,6 +241,60 @@ class PointerInt8 extends BenchmarkBase {
|
|||
}
|
||||
}
|
||||
|
||||
class PointerInt8TypedDataNew extends BenchmarkBase {
|
||||
Pointer<Int8> pointer;
|
||||
PointerInt8TypedDataNew() : super('FfiMemory.PointerInt8TypedDataNew');
|
||||
|
||||
@override
|
||||
void setup() {
|
||||
pointer = calloc(N);
|
||||
}
|
||||
|
||||
@override
|
||||
void teardown() {
|
||||
calloc.free(pointer);
|
||||
pointer = null;
|
||||
}
|
||||
|
||||
@override
|
||||
void run() {
|
||||
final typedData = pointer.asTypedList(N);
|
||||
doStoreInt8TypedData(typedData, N);
|
||||
final int x = doLoadInt8TypedData(typedData, N);
|
||||
if (x != N) {
|
||||
throw Exception('$name: Unexpected result: $x, expected $N');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class PointerInt8TypedDataReuse extends BenchmarkBase {
|
||||
Pointer<Int8> pointer;
|
||||
Int8List typedData;
|
||||
PointerInt8TypedDataReuse() : super('FfiMemory.PointerInt8TypedDataReuse');
|
||||
|
||||
@override
|
||||
void setup() {
|
||||
pointer = calloc(N);
|
||||
typedData = pointer.asTypedList(N);
|
||||
}
|
||||
|
||||
@override
|
||||
void teardown() {
|
||||
calloc.free(pointer);
|
||||
pointer = null;
|
||||
typedData = null;
|
||||
}
|
||||
|
||||
@override
|
||||
void run() {
|
||||
doStoreInt8TypedData(typedData, N);
|
||||
final int x = doLoadInt8TypedData(typedData, N);
|
||||
if (x != N) {
|
||||
throw Exception('$name: Unexpected result: $x, expected $N');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class PointerUint8 extends BenchmarkBase {
|
||||
Pointer<Uint8> pointer;
|
||||
PointerUint8() : super('FfiMemory.PointerUint8');
|
||||
|
@ -451,6 +520,8 @@ class PointerInt64Mint extends BenchmarkBase {
|
|||
void main() {
|
||||
final benchmarks = [
|
||||
() => PointerInt8(),
|
||||
() => PointerInt8TypedDataNew(),
|
||||
() => PointerInt8TypedDataReuse(),
|
||||
() => PointerUint8(),
|
||||
() => PointerInt16(),
|
||||
() => PointerUint16(),
|
||||
|
|
Loading…
Reference in a new issue