Skip to content

Commit c36028b

Browse files
dcharkescommit-bot@chromium.org
authored andcommitted
[vm/ffi] Migrate benchmarks/Ffi* to CallocAllocator
This CL does not yet roll `package:ffi` to use `Allocator`, because that breaks the checked in Dart in Flutter in g3. Instead, this copies `_CallocAllocator` from `package:ffi` into the benchmarks. (We need a copy per benchmark such that file-copying before running benchmarks works properly.) The copies can be deleted when we can update `package:ffi` in the DEPS file to contain `_CallocAllocator`. New API landed in: https://dart-review.googlesource.com/c/sdk/+/177705 Issue: #44621 Issue: #38721 Change-Id: I546de7ec65ceb6f05644a5f269b83f64656892e5 Cq-Include-Trybots: luci.dart.try:benchmark-linux-try Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/178995 Commit-Queue: Daco Harkes <[email protected]> Reviewed-by: Aske Simon Christensen <[email protected]>
1 parent c7306aa commit c36028b

File tree

16 files changed

+984
-92
lines changed

16 files changed

+984
-92
lines changed

benchmarks/FfiBoringssl/dart/FfiBoringssl.dart

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import 'dart:typed_data';
1111
import 'package:benchmark_harness/benchmark_harness.dart';
1212
import 'package:ffi/ffi.dart';
1313

14+
import 'calloc.dart';
1415
import 'digest.dart';
1516
import 'types.dart';
1617

@@ -48,11 +49,11 @@ String hash(Pointer<Data> data, int length, Pointer<EVP_MD> hashAlgorithm) {
4849
EVP_DigestInit(context, hashAlgorithm);
4950
EVP_DigestUpdate(context, data, length);
5051
final int resultSize = EVP_MD_CTX_size(context);
51-
final Pointer<Bytes> result = allocate<Uint8>(count: resultSize).cast();
52+
final Pointer<Bytes> result = calloc<Uint8>(resultSize).cast();
5253
EVP_DigestFinal(context, result, nullptr);
5354
EVP_MD_CTX_free(context);
5455
final String hash = base64Encode(toUint8List(result.ref, resultSize));
55-
free(result);
56+
calloc.free(result);
5657
return hash;
5758
}
5859

@@ -83,14 +84,14 @@ class DigestCMemory extends BenchmarkBase {
8384

8485
@override
8586
void setup() {
86-
data = allocate<Uint8>(count: L).cast();
87+
data = calloc<Uint8>(L).cast();
8788
copyFromUint8ListToTarget(inventData(L), data.ref);
8889
hash(data, L, hashAlgorithm);
8990
}
9091

9192
@override
9293
void teardown() {
93-
free(data);
94+
calloc.free(data);
9495
}
9596

9697
@override
@@ -113,21 +114,21 @@ class DigestDartMemory extends BenchmarkBase {
113114
@override
114115
void setup() {
115116
data = inventData(L);
116-
final Pointer<Data> dataInC = allocate<Uint8>(count: L).cast();
117+
final Pointer<Data> dataInC = calloc<Uint8>(L).cast();
117118
copyFromUint8ListToTarget(data, dataInC.ref);
118119
hash(dataInC, L, hashAlgorithm);
119-
free(dataInC);
120+
calloc.free(dataInC);
120121
}
121122

122123
@override
123124
void teardown() {}
124125

125126
@override
126127
void run() {
127-
final Pointer<Data> dataInC = allocate<Uint8>(count: L).cast();
128+
final Pointer<Data> dataInC = calloc<Uint8>(L).cast();
128129
copyFromUint8ListToTarget(data, dataInC.ref);
129130
final String result = hash(dataInC, L, hashAlgorithm);
130-
free(dataInC);
131+
calloc.free(dataInC);
131132
if (result != expectedHash) {
132133
throw Exception('$name: Unexpected result: $result');
133134
}
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
// TODO(https://dartbug.com/44621): Remove this copy when package:ffi can be
6+
// rolled. We need to wait until the `Allocator` interface has rolled into
7+
// Flutter.
8+
9+
import 'dart:ffi';
10+
import 'dart:io';
11+
12+
final DynamicLibrary stdlib = Platform.isWindows
13+
? DynamicLibrary.open('kernel32.dll')
14+
: DynamicLibrary.process();
15+
16+
typedef PosixCallocNative = Pointer Function(IntPtr num, IntPtr size);
17+
typedef PosixCalloc = Pointer Function(int num, int size);
18+
final PosixCalloc posixCalloc =
19+
stdlib.lookupFunction<PosixCallocNative, PosixCalloc>('calloc');
20+
21+
typedef PosixFreeNative = Void Function(Pointer);
22+
typedef PosixFree = void Function(Pointer);
23+
final PosixFree posixFree =
24+
stdlib.lookupFunction<PosixFreeNative, PosixFree>('free');
25+
26+
typedef WinGetProcessHeapFn = Pointer Function();
27+
final WinGetProcessHeapFn winGetProcessHeap = stdlib
28+
.lookupFunction<WinGetProcessHeapFn, WinGetProcessHeapFn>('GetProcessHeap');
29+
final Pointer processHeap = winGetProcessHeap();
30+
31+
typedef WinHeapAllocNative = Pointer Function(Pointer, Uint32, IntPtr);
32+
typedef WinHeapAlloc = Pointer Function(Pointer, int, int);
33+
final WinHeapAlloc winHeapAlloc =
34+
stdlib.lookupFunction<WinHeapAllocNative, WinHeapAlloc>('HeapAlloc');
35+
36+
typedef WinHeapFreeNative = Int32 Function(
37+
Pointer heap, Uint32 flags, Pointer memory);
38+
typedef WinHeapFree = int Function(Pointer heap, int flags, Pointer memory);
39+
final WinHeapFree winHeapFree =
40+
stdlib.lookupFunction<WinHeapFreeNative, WinHeapFree>('HeapFree');
41+
42+
const int HEAP_ZERO_MEMORY = 8;
43+
44+
/// Manages memory on the native heap.
45+
///
46+
/// Initializes newly allocated memory to zero.
47+
///
48+
/// For POSIX-based systems, this uses `calloc` and `free`. On Windows, it uses
49+
/// `HeapAlloc` with [HEAP_ZERO_MEMORY] and `HeapFree` against the default
50+
/// public heap.
51+
class _CallocAllocator implements Allocator {
52+
const _CallocAllocator();
53+
54+
/// Allocates [byteCount] bytes of zero-initialized of memory on the native
55+
/// heap.
56+
///
57+
/// For POSIX-based systems, this uses `calloc`. On Windows, it uses
58+
/// `HeapAlloc` against the default public heap.
59+
///
60+
/// Throws an [ArgumentError] if the number of bytes or alignment cannot be
61+
/// satisfied.
62+
// TODO: Stop ignoring alignment if it's large, for example for SSE data.
63+
@override
64+
Pointer<T> allocate<T extends NativeType>(int byteCount, {int? alignment}) {
65+
Pointer<T> result;
66+
if (Platform.isWindows) {
67+
result = winHeapAlloc(processHeap, /*flags=*/ HEAP_ZERO_MEMORY, byteCount)
68+
.cast();
69+
} else {
70+
result = posixCalloc(byteCount, 1).cast();
71+
}
72+
if (result.address == 0) {
73+
throw ArgumentError('Could not allocate $byteCount bytes.');
74+
}
75+
return result;
76+
}
77+
78+
/// Releases memory allocated on the native heap.
79+
///
80+
/// For POSIX-based systems, this uses `free`. On Windows, it uses `HeapFree`
81+
/// against the default public heap. It may only be used against pointers
82+
/// allocated in a manner equivalent to [allocate].
83+
///
84+
/// Throws an [ArgumentError] if the memory pointed to by [pointer] cannot be
85+
/// freed.
86+
///
87+
// TODO(dartbug.com/36855): Once we have a ffi.Bool type we can use it instead
88+
// of testing the return integer to be non-zero.
89+
@override
90+
void free(Pointer pointer) {
91+
if (Platform.isWindows) {
92+
if (winHeapFree(processHeap, /*flags=*/ 0, pointer) == 0) {
93+
throw ArgumentError('Could not free $pointer.');
94+
}
95+
} else {
96+
posixFree(pointer);
97+
}
98+
}
99+
}
100+
101+
/// Manages memory on the native heap.
102+
///
103+
/// Initializes newly allocated memory to zero. Use [malloc] for unintialized
104+
/// memory allocation.
105+
///
106+
/// For POSIX-based systems, this uses `calloc` and `free`. On Windows, it uses
107+
/// `HeapAlloc` with [HEAP_ZERO_MEMORY] and `HeapFree` against the default
108+
/// public heap.
109+
const Allocator calloc = _CallocAllocator();

benchmarks/FfiBoringssl/dart2/FfiBoringssl.dart

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import 'dart:typed_data';
1313
import 'package:benchmark_harness/benchmark_harness.dart';
1414
import 'package:ffi/ffi.dart';
1515

16+
import 'calloc.dart';
1617
import 'digest.dart';
1718
import 'types.dart';
1819

@@ -50,11 +51,11 @@ String hash(Pointer<Data> data, int length, Pointer<EVP_MD> hashAlgorithm) {
5051
EVP_DigestInit(context, hashAlgorithm);
5152
EVP_DigestUpdate(context, data, length);
5253
final int resultSize = EVP_MD_CTX_size(context);
53-
final Pointer<Bytes> result = allocate<Uint8>(count: resultSize).cast();
54+
final Pointer<Bytes> result = calloc<Uint8>(resultSize).cast();
5455
EVP_DigestFinal(context, result, nullptr);
5556
EVP_MD_CTX_free(context);
5657
final String hash = base64Encode(toUint8List(result.ref, resultSize));
57-
free(result);
58+
calloc.free(result);
5859
return hash;
5960
}
6061

@@ -85,14 +86,14 @@ class DigestCMemory extends BenchmarkBase {
8586

8687
@override
8788
void setup() {
88-
data = allocate<Uint8>(count: L).cast();
89+
data = calloc<Uint8>(L).cast();
8990
copyFromUint8ListToTarget(inventData(L), data.ref);
9091
hash(data, L, hashAlgorithm);
9192
}
9293

9394
@override
9495
void teardown() {
95-
free(data);
96+
calloc.free(data);
9697
}
9798

9899
@override
@@ -115,21 +116,21 @@ class DigestDartMemory extends BenchmarkBase {
115116
@override
116117
void setup() {
117118
data = inventData(L);
118-
final Pointer<Data> dataInC = allocate<Uint8>(count: L).cast();
119+
final Pointer<Data> dataInC = calloc<Uint8>(L).cast();
119120
copyFromUint8ListToTarget(data, dataInC.ref);
120121
hash(dataInC, L, hashAlgorithm);
121-
free(dataInC);
122+
calloc.free(dataInC);
122123
}
123124

124125
@override
125126
void teardown() {}
126127

127128
@override
128129
void run() {
129-
final Pointer<Data> dataInC = allocate<Uint8>(count: L).cast();
130+
final Pointer<Data> dataInC = calloc<Uint8>(L).cast();
130131
copyFromUint8ListToTarget(data, dataInC.ref);
131132
final String result = hash(dataInC, L, hashAlgorithm);
132-
free(dataInC);
133+
calloc.free(dataInC);
133134
if (result != expectedHash) {
134135
throw Exception('$name: Unexpected result: $result');
135136
}
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
// TODO(https://dartbug.com/44621): Remove this copy when package:ffi can be
6+
// rolled. We need to wait until the `Allocator` interface has rolled into
7+
// Flutter.
8+
9+
// @dart=2.9
10+
11+
import 'dart:ffi';
12+
import 'dart:io';
13+
14+
final DynamicLibrary stdlib = Platform.isWindows
15+
? DynamicLibrary.open('kernel32.dll')
16+
: DynamicLibrary.process();
17+
18+
typedef PosixCallocNative = Pointer Function(IntPtr num, IntPtr size);
19+
typedef PosixCalloc = Pointer Function(int num, int size);
20+
final PosixCalloc posixCalloc =
21+
stdlib.lookupFunction<PosixCallocNative, PosixCalloc>('calloc');
22+
23+
typedef PosixFreeNative = Void Function(Pointer);
24+
typedef PosixFree = void Function(Pointer);
25+
final PosixFree posixFree =
26+
stdlib.lookupFunction<PosixFreeNative, PosixFree>('free');
27+
28+
typedef WinGetProcessHeapFn = Pointer Function();
29+
final WinGetProcessHeapFn winGetProcessHeap = stdlib
30+
.lookupFunction<WinGetProcessHeapFn, WinGetProcessHeapFn>('GetProcessHeap');
31+
final Pointer processHeap = winGetProcessHeap();
32+
33+
typedef WinHeapAllocNative = Pointer Function(Pointer, Uint32, IntPtr);
34+
typedef WinHeapAlloc = Pointer Function(Pointer, int, int);
35+
final WinHeapAlloc winHeapAlloc =
36+
stdlib.lookupFunction<WinHeapAllocNative, WinHeapAlloc>('HeapAlloc');
37+
38+
typedef WinHeapFreeNative = Int32 Function(
39+
Pointer heap, Uint32 flags, Pointer memory);
40+
typedef WinHeapFree = int Function(Pointer heap, int flags, Pointer memory);
41+
final WinHeapFree winHeapFree =
42+
stdlib.lookupFunction<WinHeapFreeNative, WinHeapFree>('HeapFree');
43+
44+
const int HEAP_ZERO_MEMORY = 8;
45+
46+
/// Manages memory on the native heap.
47+
///
48+
/// Initializes newly allocated memory to zero.
49+
///
50+
/// For POSIX-based systems, this uses `calloc` and `free`. On Windows, it uses
51+
/// `HeapAlloc` with [HEAP_ZERO_MEMORY] and `HeapFree` against the default
52+
/// public heap.
53+
class _CallocAllocator implements Allocator {
54+
const _CallocAllocator();
55+
56+
/// Allocates [byteCount] bytes of zero-initialized of memory on the native
57+
/// heap.
58+
///
59+
/// For POSIX-based systems, this uses `calloc`. On Windows, it uses
60+
/// `HeapAlloc` against the default public heap.
61+
///
62+
/// Throws an [ArgumentError] if the number of bytes or alignment cannot be
63+
/// satisfied.
64+
// TODO: Stop ignoring alignment if it's large, for example for SSE data.
65+
@override
66+
Pointer<T> allocate<T extends NativeType>(int byteCount, {int alignment}) {
67+
Pointer<T> result;
68+
if (Platform.isWindows) {
69+
result = winHeapAlloc(processHeap, /*flags=*/ HEAP_ZERO_MEMORY, byteCount)
70+
.cast();
71+
} else {
72+
result = posixCalloc(byteCount, 1).cast();
73+
}
74+
if (result.address == 0) {
75+
throw ArgumentError('Could not allocate $byteCount bytes.');
76+
}
77+
return result;
78+
}
79+
80+
/// Releases memory allocated on the native heap.
81+
///
82+
/// For POSIX-based systems, this uses `free`. On Windows, it uses `HeapFree`
83+
/// against the default public heap. It may only be used against pointers
84+
/// allocated in a manner equivalent to [allocate].
85+
///
86+
/// Throws an [ArgumentError] if the memory pointed to by [pointer] cannot be
87+
/// freed.
88+
///
89+
// TODO(dartbug.com/36855): Once we have a ffi.Bool type we can use it instead
90+
// of testing the return integer to be non-zero.
91+
@override
92+
void free(Pointer pointer) {
93+
if (Platform.isWindows) {
94+
if (winHeapFree(processHeap, /*flags=*/ 0, pointer) == 0) {
95+
throw ArgumentError('Could not free $pointer.');
96+
}
97+
} else {
98+
posixFree(pointer);
99+
}
100+
}
101+
}
102+
103+
/// Manages memory on the native heap.
104+
///
105+
/// Initializes newly allocated memory to zero. Use [malloc] for unintialized
106+
/// memory allocation.
107+
///
108+
/// For POSIX-based systems, this uses `calloc` and `free`. On Windows, it uses
109+
/// `HeapAlloc` with [HEAP_ZERO_MEMORY] and `HeapFree` against the default
110+
/// public heap.
111+
const Allocator calloc = _CallocAllocator();

0 commit comments

Comments
 (0)