|
1 | 1 | import 'dart:ffi'; |
2 | | -import 'dart:io' show Platform; |
3 | 2 | import 'dart:typed_data'; |
4 | 3 |
|
5 | 4 | import 'package:ffi/ffi.dart'; |
6 | 5 |
|
7 | 6 | import '../../../flatbuffers/flat_buffers.dart' as fb; |
| 7 | +import 'nativemem.dart'; |
8 | 8 |
|
9 | 9 | // ignore_for_file: public_member_api_docs |
10 | 10 |
|
@@ -42,12 +42,6 @@ class BuilderWithCBuffer { |
42 | 42 | Allocator get allocator => _allocator; |
43 | 43 | } |
44 | 44 |
|
45 | | -// FFI signature |
46 | | -typedef _dart_memset = void Function(Pointer<Uint8>, int, int); |
47 | | -typedef _c_memset = Void Function(Pointer<Uint8>, Int32, IntPtr); |
48 | | - |
49 | | -_dart_memset? fbMemset; |
50 | | - |
51 | 45 | class Allocator extends fb.Allocator { |
52 | 46 | // We may, in practice, have only two active allocations: one used and one |
53 | 47 | // for resizing. Therefore, we use a ring buffer of a fixed size (2). |
@@ -98,34 +92,46 @@ class Allocator extends fb.Allocator { |
98 | 92 | void clear(ByteData data, bool isFresh) { |
99 | 93 | if (isFresh) return; // freshly allocated data is zero-ed out (see [calloc]) |
100 | 94 |
|
101 | | - if (fbMemset == null) { |
102 | | - if (Platform.isWindows) { |
103 | | - try { |
104 | | - // DynamicLibrary.process() is not available on Windows, let's load a |
105 | | - // lib that defines 'memset()' it - should be mscvr100 or mscvrt DLL. |
106 | | - // mscvr100.dll is in the frequently installed MSVC Redistributable. |
107 | | - fbMemset = DynamicLibrary.open('msvcr100.dll') |
108 | | - .lookupFunction<_c_memset, _dart_memset>('memset'); |
109 | | - } catch (_) { |
110 | | - // fall back if we can't load a native memset() |
111 | | - fbMemset = (Pointer<Uint8> ptr, int byte, int size) => |
112 | | - ptr.cast<Uint8>().asTypedList(size).fillRange(0, size, byte); |
113 | | - } |
114 | | - } else { |
115 | | - fbMemset = DynamicLibrary.process() |
116 | | - .lookupFunction<_c_memset, _dart_memset>('memset'); |
117 | | - } |
118 | | - } |
119 | | - |
120 | 95 | // only used for sanity checks: |
121 | 96 | assert(_data[_index] == data); |
122 | 97 | assert(_allocs[_index].address != 0); |
123 | 98 |
|
124 | | - fbMemset!(_allocs[_index], 0, data.lengthInBytes); |
| 99 | + // TODO - there are other options to clear the builder, see how other |
| 100 | + // FlatBuffer implementations do it. |
| 101 | + memset(_allocs[_index], 0, data.lengthInBytes); |
125 | 102 | } |
126 | 103 |
|
127 | 104 | void freeAll() { |
128 | 105 | if (_allocs[0].address != 0) calloc.free(_allocs[0]); |
129 | 106 | if (_allocs[1].address != 0) calloc.free(_allocs[1]); |
130 | 107 | } |
131 | 108 | } |
| 109 | + |
| 110 | +/// Implements a native data access wrapper to circumvent Pointer.asTypedList() |
| 111 | +/// slowness. The idea is to reuse the same buffer and rather memcpy the data, |
| 112 | +/// which ends up being faster than calling asTypedList(). Hopefully, we will |
| 113 | +/// be able to remove this if (when) asTypedList() gets optimized in Dart SDK. |
| 114 | +class ReaderWithCBuffer { |
| 115 | + // See /benchmark/bin/native_pointers.dart for the max buffer size where it |
| 116 | + // still makes sense to use memcpy. On Linux, memcpy starts to be slower at |
| 117 | + // about 10-15 KiB. TODO test on other platforms to find an optimal limit. |
| 118 | + static const _maxBuffer = 4 * 1024; |
| 119 | + final _bufferPtr = malloc<Uint8>(_maxBuffer); |
| 120 | + late final ByteBuffer _buffer = _bufferPtr.asTypedList(_maxBuffer).buffer; |
| 121 | + |
| 122 | + ReaderWithCBuffer() { |
| 123 | + assert(_bufferPtr.asTypedList(_maxBuffer).offsetInBytes == 0); |
| 124 | + } |
| 125 | + |
| 126 | + void clear() => malloc.free(_bufferPtr); |
| 127 | + |
| 128 | + ByteData access(Pointer<Uint8> dataPtr, int size) { |
| 129 | + if (size > _maxBuffer) { |
| 130 | + final uint8List = dataPtr.asTypedList(size); |
| 131 | + return ByteData.view(uint8List.buffer, uint8List.offsetInBytes, size); |
| 132 | + } else { |
| 133 | + memcpy(_bufferPtr, dataPtr, size); |
| 134 | + return ByteData.view(_buffer, 0, size); |
| 135 | + } |
| 136 | + } |
| 137 | +} |
0 commit comments