koffi 1.3.5 → 1.3.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CMakeLists.txt +1 -1
- package/ChangeLog.md +36 -0
- package/benchmark/atoi_koffi.js +3 -4
- package/benchmark/atoi_napi.js +2 -3
- package/benchmark/atoi_node_ffi.js +3 -4
- package/benchmark/raylib_cc.cc +3 -4
- package/benchmark/raylib_cc.js +31 -0
- package/benchmark/raylib_koffi.js +8 -9
- package/benchmark/raylib_node_ffi.js +4 -5
- package/benchmark/raylib_node_raylib.js +4 -5
- package/build/qemu/1.3.8/koffi_darwin_arm64.tar.gz +0 -0
- package/build/qemu/1.3.8/koffi_darwin_x64.tar.gz +0 -0
- package/build/qemu/1.3.8/koffi_freebsd_arm64.tar.gz +0 -0
- package/build/qemu/1.3.8/koffi_freebsd_ia32.tar.gz +0 -0
- package/build/qemu/1.3.8/koffi_freebsd_x64.tar.gz +0 -0
- package/build/qemu/1.3.8/koffi_linux_arm32hf.tar.gz +0 -0
- package/build/qemu/1.3.8/koffi_linux_arm64.tar.gz +0 -0
- package/build/qemu/1.3.8/koffi_linux_ia32.tar.gz +0 -0
- package/build/qemu/1.3.8/koffi_linux_riscv64hf64.tar.gz +0 -0
- package/build/qemu/1.3.8/koffi_linux_x64.tar.gz +0 -0
- package/build/qemu/1.3.8/koffi_openbsd_ia32.tar.gz +0 -0
- package/build/qemu/1.3.8/koffi_openbsd_x64.tar.gz +0 -0
- package/build/qemu/1.3.8/koffi_win32_arm64.tar.gz +0 -0
- package/build/qemu/1.3.8/koffi_win32_ia32.tar.gz +0 -0
- package/build/qemu/1.3.8/koffi_win32_x64.tar.gz +0 -0
- package/doc/_static/perf_linux_20220627.png +0 -0
- package/doc/_static/perf_linux_20220628.png +0 -0
- package/doc/_static/perf_windows_20220627.png +0 -0
- package/doc/_static/perf_windows_20220628.png +0 -0
- package/doc/benchmarks.md +78 -58
- package/doc/benchmarks.xlsx +0 -0
- package/doc/conf.py +1 -1
- package/doc/contribute.md +8 -11
- package/doc/dist/html/_sources/benchmarks.md.txt +78 -58
- package/doc/dist/html/_sources/contribute.md.txt +8 -11
- package/doc/dist/html/_sources/functions.md.txt +9 -8
- package/doc/dist/html/_sources/index.rst.txt +3 -0
- package/doc/dist/html/_sources/platforms.md.txt +17 -5
- package/doc/dist/html/_sources/start.md.txt +14 -3
- package/doc/dist/html/_sources/types.md.txt +15 -11
- package/doc/dist/html/_static/basic.css +12 -14
- package/doc/dist/html/_static/perf_linux_20220627.png +0 -0
- package/doc/dist/html/_static/perf_linux_20220628.png +0 -0
- package/doc/dist/html/_static/perf_windows_20220627.png +0 -0
- package/doc/dist/html/_static/perf_windows_20220628.png +0 -0
- package/doc/dist/html/benchmarks.html +148 -159
- package/doc/dist/html/changes.html +44 -2
- package/doc/dist/html/contribute.html +30 -33
- package/doc/dist/html/functions.html +19 -18
- package/doc/dist/html/genindex.html +2 -2
- package/doc/dist/html/index.html +19 -10
- package/doc/dist/html/memory.html +2 -2
- package/doc/dist/html/objects.inv +0 -0
- package/doc/dist/html/platforms.html +44 -10
- package/doc/dist/html/search.html +2 -2
- package/doc/dist/html/searchindex.js +1 -1
- package/doc/dist/html/start.html +25 -12
- package/doc/dist/html/types.html +31 -11
- package/doc/functions.md +9 -8
- package/doc/index.rst +3 -0
- package/doc/platforms.md +17 -5
- package/doc/start.md +14 -3
- package/doc/types.md +15 -11
- package/package.json +7 -4
- package/qemu/qemu.js +30 -19
- package/qemu/registry/machines.json +19 -19
- package/qemu/registry/sha256sum.txt +5 -5
- package/src/abi_arm32.cc +9 -2
- package/src/abi_arm32_fwd.S +7 -7
- package/src/abi_arm64.cc +9 -2
- package/src/abi_arm64_fwd.S +11 -7
- package/src/abi_arm64_fwd.asm +7 -7
- package/src/abi_riscv64.cc +9 -2
- package/src/abi_riscv64_fwd.S +11 -11
- package/src/abi_x64_sysv.cc +9 -2
- package/src/abi_x64_sysv_fwd.S +11 -11
- package/src/abi_x64_win.cc +9 -2
- package/src/abi_x64_win_fwd.asm +7 -7
- package/src/abi_x86.cc +9 -2
- package/src/abi_x86_fwd.S +3 -0
- package/src/abi_x86_fwd.asm +3 -0
- package/src/call.cc +20 -10
- package/src/ffi.cc +17 -8
- package/src/ffi.hh +4 -3
- package/src/util.cc +1 -1
- package/test/async.js +1 -1
- package/test/callbacks.js +25 -2
- package/test/misc.c +57 -2
- package/test/raylib.js +4 -4
- package/test/sqlite.js +5 -5
- package/test/sync.js +22 -7
- package/build/qemu/1.3.5/koffi_darwin_arm64.tar.gz +0 -0
- package/build/qemu/1.3.5/koffi_darwin_x64.tar.gz +0 -0
- package/build/qemu/1.3.5/koffi_freebsd_arm64.tar.gz +0 -0
- package/build/qemu/1.3.5/koffi_freebsd_ia32.tar.gz +0 -0
- package/build/qemu/1.3.5/koffi_freebsd_x64.tar.gz +0 -0
- package/build/qemu/1.3.5/koffi_linux_arm32hf.tar.gz +0 -0
- package/build/qemu/1.3.5/koffi_linux_arm64.tar.gz +0 -0
- package/build/qemu/1.3.5/koffi_linux_ia32.tar.gz +0 -0
- package/build/qemu/1.3.5/koffi_linux_riscv64hf64.tar.gz +0 -0
- package/build/qemu/1.3.5/koffi_linux_x64.tar.gz +0 -0
- package/build/qemu/1.3.5/koffi_openbsd_ia32.tar.gz +0 -0
- package/build/qemu/1.3.5/koffi_openbsd_x64.tar.gz +0 -0
- package/build/qemu/1.3.5/koffi_win32_arm64.tar.gz +0 -0
- package/build/qemu/1.3.5/koffi_win32_ia32.tar.gz +0 -0
- package/build/qemu/1.3.5/koffi_win32_x64.tar.gz +0 -0
package/CMakeLists.txt
CHANGED
|
@@ -110,7 +110,7 @@ if(WIN32)
|
|
|
110
110
|
target_compile_definitions(koffi PRIVATE _CRT_SECURE_NO_WARNINGS _CRT_NONSTDC_NO_DEPRECATE)
|
|
111
111
|
target_link_libraries(koffi PRIVATE ws2_32)
|
|
112
112
|
endif()
|
|
113
|
-
if(NOT MSVC)
|
|
113
|
+
if(NOT MSVC OR CMAKE_C_COMPILER_ID MATCHES "[Cc]lang")
|
|
114
114
|
# Restore C/C++ compiler sanity
|
|
115
115
|
|
|
116
116
|
target_compile_options(koffi PRIVATE -fno-exceptions -fno-strict-aliasing -fwrapv
|
package/ChangeLog.md
CHANGED
|
@@ -1,5 +1,41 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## Koffi 1.3.8
|
|
4
|
+
|
|
5
|
+
**Main changes:**
|
|
6
|
+
|
|
7
|
+
- Prevent callback reuse beyond FFI call
|
|
8
|
+
- Add BTI support for AAarch64 platforms (except Windows)
|
|
9
|
+
|
|
10
|
+
**Other changes:**
|
|
11
|
+
|
|
12
|
+
- Fix and harmonize a few error messages
|
|
13
|
+
|
|
14
|
+
## Koffi 1.3.7
|
|
15
|
+
|
|
16
|
+
**Main fixes:**
|
|
17
|
+
|
|
18
|
+
- Fix crash when using callbacks inside structs
|
|
19
|
+
- Support for null strings in record members
|
|
20
|
+
|
|
21
|
+
**Other changes:**
|
|
22
|
+
|
|
23
|
+
- Add intptr_t and uintptr_t primitive types
|
|
24
|
+
- Add str/str16 type aliases for string/string16
|
|
25
|
+
- Various documentation fixes and improvements
|
|
26
|
+
|
|
27
|
+
## Koffi 1.3.6
|
|
28
|
+
|
|
29
|
+
**Main fixes:**
|
|
30
|
+
|
|
31
|
+
- Fix install error with Node < 15 on Windows (build system bug)
|
|
32
|
+
|
|
33
|
+
**Other changes:**
|
|
34
|
+
|
|
35
|
+
- Detect incompatible Node.js versions when installing Koffi
|
|
36
|
+
- Prebuild with Clang for Windows x64 and Linux x64 binaries
|
|
37
|
+
- Various documentation improvements
|
|
38
|
+
|
|
3
39
|
## Koffi 1.3.5
|
|
4
40
|
|
|
5
41
|
**Main changes:**
|
package/benchmark/atoi_koffi.js
CHANGED
|
@@ -35,11 +35,10 @@ function main() {
|
|
|
35
35
|
if (iterations < 1)
|
|
36
36
|
throw new Error('Value must be positive');
|
|
37
37
|
}
|
|
38
|
-
console.log('Iterations:', iterations);
|
|
39
38
|
|
|
40
39
|
let lib = koffi.load(process.platform == 'win32' ? 'msvcrt.dll' : null);
|
|
41
40
|
|
|
42
|
-
const atoi = lib.cdecl('atoi', 'int', ['
|
|
41
|
+
const atoi = lib.cdecl('atoi', 'int', ['str']);
|
|
43
42
|
|
|
44
43
|
let start = performance.now();
|
|
45
44
|
|
|
@@ -47,6 +46,6 @@ function main() {
|
|
|
47
46
|
sum += atoi(strings[i % strings.length]);
|
|
48
47
|
}
|
|
49
48
|
|
|
50
|
-
let time = performance.now()- start;
|
|
51
|
-
console.log(
|
|
49
|
+
let time = performance.now() - start;
|
|
50
|
+
console.log(JSON.stringify({ iterations: iterations, time: Math.round(time) }));
|
|
52
51
|
}
|
package/benchmark/atoi_napi.js
CHANGED
|
@@ -35,7 +35,6 @@ function main() {
|
|
|
35
35
|
if (iterations < 1)
|
|
36
36
|
throw new Error('Value must be positive');
|
|
37
37
|
}
|
|
38
|
-
console.log('Iterations:', iterations);
|
|
39
38
|
|
|
40
39
|
let start = performance.now();
|
|
41
40
|
|
|
@@ -43,6 +42,6 @@ function main() {
|
|
|
43
42
|
sum += atoi.atoi(strings[i % strings.length]);
|
|
44
43
|
}
|
|
45
44
|
|
|
46
|
-
let time = performance.now()- start;
|
|
47
|
-
console.log(
|
|
45
|
+
let time = performance.now() - start;
|
|
46
|
+
console.log(JSON.stringify({ iterations: iterations, time: Math.round(time) }));
|
|
48
47
|
}
|
|
@@ -28,7 +28,7 @@ let sum = 0;
|
|
|
28
28
|
main();
|
|
29
29
|
|
|
30
30
|
async function main() {
|
|
31
|
-
let iterations =
|
|
31
|
+
let iterations = 200000;
|
|
32
32
|
|
|
33
33
|
if (process.argv.length >= 3) {
|
|
34
34
|
iterations = parseInt(process.argv[2], 10);
|
|
@@ -37,7 +37,6 @@ async function main() {
|
|
|
37
37
|
if (iterations < 1)
|
|
38
38
|
throw new Error('Value must be positive');
|
|
39
39
|
}
|
|
40
|
-
console.log('Iterations:', iterations);
|
|
41
40
|
|
|
42
41
|
const lib = ffi.Library(process.platform == 'win32' ? 'msvcrt.dll' : null, {
|
|
43
42
|
atoi: ['int', ['string']]
|
|
@@ -52,6 +51,6 @@ async function main() {
|
|
|
52
51
|
sum += lib.atoi(strings[i % strings.length]);
|
|
53
52
|
}
|
|
54
53
|
|
|
55
|
-
let time = performance.now()- start;
|
|
56
|
-
console.log(
|
|
54
|
+
let time = performance.now() - start;
|
|
55
|
+
console.log(JSON.stringify({ iterations: iterations, time: Math.round(time) }));
|
|
57
56
|
}
|
package/benchmark/raylib_cc.cc
CHANGED
|
@@ -18,13 +18,12 @@ namespace RG {
|
|
|
18
18
|
|
|
19
19
|
int Main(int argc, char **argv)
|
|
20
20
|
{
|
|
21
|
-
int iterations =
|
|
21
|
+
int iterations = 360000;
|
|
22
22
|
|
|
23
23
|
if (argc >= 2) {
|
|
24
24
|
if (!ParseInt(argv[1], &iterations))
|
|
25
25
|
return 1;
|
|
26
26
|
}
|
|
27
|
-
LogInfo("Iterations: %1", iterations);
|
|
28
27
|
|
|
29
28
|
// We need to call InitWindow before using anything else (such as fonts)
|
|
30
29
|
SetTraceLogLevel(LOG_WARNING);
|
|
@@ -36,7 +35,7 @@ int Main(int argc, char **argv)
|
|
|
36
35
|
|
|
37
36
|
int64_t start = GetMonotonicTime();
|
|
38
37
|
|
|
39
|
-
for (int i = 0; i < iterations; i
|
|
38
|
+
for (int i = 0; i < iterations; i += 3600) {
|
|
40
39
|
ImageClearBackground(&img, Color { 0, 0, 0, 255 });
|
|
41
40
|
|
|
42
41
|
for (int j = 0; j < 3600; j++) {
|
|
@@ -60,7 +59,7 @@ int Main(int argc, char **argv)
|
|
|
60
59
|
}
|
|
61
60
|
|
|
62
61
|
int64_t time = GetMonotonicTime() - start;
|
|
63
|
-
|
|
62
|
+
PrintLn("{\"iterations\": %1,\"time\": %2}", iterations, time);
|
|
64
63
|
|
|
65
64
|
return 0;
|
|
66
65
|
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// This program is free software: you can redistribute it and/or modify
|
|
4
|
+
// it under the terms of the GNU Affero General Public License as published by
|
|
5
|
+
// the Free Software Foundation, either version 3 of the License, or
|
|
6
|
+
// (at your option) any later version.
|
|
7
|
+
//
|
|
8
|
+
// This program is distributed in the hope that it will be useful,
|
|
9
|
+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
10
|
+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
11
|
+
// GNU Affero General Public License for more details.
|
|
12
|
+
//
|
|
13
|
+
// You should have received a copy of the GNU Affero General Public License
|
|
14
|
+
// along with this program. If not, see https://www.gnu.org/licenses/.
|
|
15
|
+
|
|
16
|
+
const { spawnSync } = require('child_process');
|
|
17
|
+
const path = require('path');
|
|
18
|
+
|
|
19
|
+
main();
|
|
20
|
+
|
|
21
|
+
function main() {
|
|
22
|
+
let filename = path.join(__dirname, 'build/raylib_cc' + (process.platform == 'win32' ? '.exe' : ''));
|
|
23
|
+
let proc = spawnSync(filename, process.argv.slice(2), { stdio: 'inherit' });
|
|
24
|
+
|
|
25
|
+
if (proc.status == null) {
|
|
26
|
+
console.error(proc.error);
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
process.exit(proc.status);
|
|
31
|
+
}
|
|
@@ -71,7 +71,7 @@ const Font = koffi.struct('Font', {
|
|
|
71
71
|
main();
|
|
72
72
|
|
|
73
73
|
function main() {
|
|
74
|
-
let iterations =
|
|
74
|
+
let iterations = 360000;
|
|
75
75
|
|
|
76
76
|
if (process.argv.length >= 3) {
|
|
77
77
|
iterations = parseInt(process.argv[2], 10);
|
|
@@ -80,20 +80,19 @@ function main() {
|
|
|
80
80
|
if (iterations < 1)
|
|
81
81
|
throw new Error('Value must be positive');
|
|
82
82
|
}
|
|
83
|
-
console.log('Iterations:', iterations);
|
|
84
83
|
|
|
85
84
|
let lib_filename = path.dirname(__filename) + '/build/raylib' + koffi.extension;
|
|
86
85
|
let lib = koffi.load(lib_filename);
|
|
87
86
|
|
|
88
|
-
const InitWindow = lib.cdecl('InitWindow', 'void', ['int', 'int', '
|
|
87
|
+
const InitWindow = lib.cdecl('InitWindow', 'void', ['int', 'int', 'str']);
|
|
89
88
|
const SetTraceLogLevel = lib.cdecl('SetTraceLogLevel', 'void', ['int']);
|
|
90
89
|
const SetWindowState = lib.cdecl('SetWindowState', 'void', ['uint']);
|
|
91
90
|
const GenImageColor = lib.cdecl('GenImageColor', Image, ['int', 'int', Color]);
|
|
92
91
|
const GetFontDefault = lib.cdecl('GetFontDefault', Font, []);
|
|
93
|
-
const MeasureTextEx = lib.cdecl('MeasureTextEx', Vector2, [Font, '
|
|
92
|
+
const MeasureTextEx = lib.cdecl('MeasureTextEx', Vector2, [Font, 'str', 'float', 'float']);
|
|
94
93
|
const ImageClearBackground = lib.cdecl('ImageClearBackground', 'void', [koffi.pointer(Image), Color]);
|
|
95
|
-
const ImageDrawTextEx = lib.cdecl('ImageDrawTextEx', 'void', [koffi.pointer(Image), Font, '
|
|
96
|
-
const ExportImage = lib.cdecl('ExportImage', 'bool', [Image, '
|
|
94
|
+
const ImageDrawTextEx = lib.cdecl('ImageDrawTextEx', 'void', [koffi.pointer(Image), Font, 'str', Vector2, 'float', 'float', Color]);
|
|
95
|
+
const ExportImage = lib.cdecl('ExportImage', 'bool', [Image, 'str']);
|
|
97
96
|
|
|
98
97
|
// We need to call InitWindow before using anything else (such as fonts)
|
|
99
98
|
SetTraceLogLevel(4); // Warnings
|
|
@@ -105,7 +104,7 @@ function main() {
|
|
|
105
104
|
|
|
106
105
|
let start = performance.now();
|
|
107
106
|
|
|
108
|
-
for (let i = 0; i < iterations; i
|
|
107
|
+
for (let i = 0; i < iterations; i += 3600) {
|
|
109
108
|
ImageClearBackground(img, { r: 0, g: 0, b: 0, a: 255 });
|
|
110
109
|
|
|
111
110
|
for (let j = 0; j < 3600; j++) {
|
|
@@ -128,6 +127,6 @@ function main() {
|
|
|
128
127
|
}
|
|
129
128
|
}
|
|
130
129
|
|
|
131
|
-
let time = performance.now()- start;
|
|
132
|
-
console.log(
|
|
130
|
+
let time = performance.now() - start;
|
|
131
|
+
console.log(JSON.stringify({ iterations: iterations, time: Math.round(time) }));
|
|
133
132
|
}
|
|
@@ -87,7 +87,7 @@ const Font = struct({
|
|
|
87
87
|
main();
|
|
88
88
|
|
|
89
89
|
function main() {
|
|
90
|
-
let iterations =
|
|
90
|
+
let iterations = 180000;
|
|
91
91
|
|
|
92
92
|
if (process.argv.length >= 3) {
|
|
93
93
|
iterations = parseInt(process.argv[2], 10);
|
|
@@ -96,7 +96,6 @@ function main() {
|
|
|
96
96
|
if (iterations < 1)
|
|
97
97
|
throw new Error('Value must be positive');
|
|
98
98
|
}
|
|
99
|
-
console.log('Iterations:', iterations);
|
|
100
99
|
|
|
101
100
|
let lib_filename = path.dirname(__filename) + '/build/raylib' + koffi.extension;
|
|
102
101
|
|
|
@@ -123,7 +122,7 @@ function main() {
|
|
|
123
122
|
|
|
124
123
|
let start = performance.now();
|
|
125
124
|
|
|
126
|
-
for (let i = 0; i < iterations; i
|
|
125
|
+
for (let i = 0; i < iterations; i += 3600) {
|
|
127
126
|
r.ImageClearBackground(imgp, new Color({ r: 0, g: 0, b: 0, a: 255 }));
|
|
128
127
|
|
|
129
128
|
for (let j = 0; j < 3600; j++) {
|
|
@@ -146,6 +145,6 @@ function main() {
|
|
|
146
145
|
}
|
|
147
146
|
}
|
|
148
147
|
|
|
149
|
-
let time = performance.now()- start;
|
|
150
|
-
console.log(
|
|
148
|
+
let time = performance.now() - start;
|
|
149
|
+
console.log(JSON.stringify({ iterations: iterations, time: Math.round(time) }));
|
|
151
150
|
}
|
|
@@ -18,7 +18,7 @@ const r = require('raylib');
|
|
|
18
18
|
main();
|
|
19
19
|
|
|
20
20
|
function main() {
|
|
21
|
-
let iterations =
|
|
21
|
+
let iterations = 360000;
|
|
22
22
|
|
|
23
23
|
if (process.argv.length >= 3) {
|
|
24
24
|
iterations = parseInt(process.argv[2], 10);
|
|
@@ -27,7 +27,6 @@ function main() {
|
|
|
27
27
|
if (iterations < 1)
|
|
28
28
|
throw new Error('Value must be positive');
|
|
29
29
|
}
|
|
30
|
-
console.log('Iterations:', iterations);
|
|
31
30
|
|
|
32
31
|
// We need to call InitWindow before using anything else (such as fonts)
|
|
33
32
|
r.SetTraceLogLevel(4); // Warnings
|
|
@@ -39,7 +38,7 @@ function main() {
|
|
|
39
38
|
|
|
40
39
|
let start = performance.now();
|
|
41
40
|
|
|
42
|
-
for (let i = 0; i < iterations; i
|
|
41
|
+
for (let i = 0; i < iterations; i += 3600) {
|
|
43
42
|
r.ImageClearBackground(img, { r: 0, g: 0, b: 0, a: 255 });
|
|
44
43
|
|
|
45
44
|
for (let j = 0; j < 3600; j++) {
|
|
@@ -62,6 +61,6 @@ function main() {
|
|
|
62
61
|
}
|
|
63
62
|
}
|
|
64
63
|
|
|
65
|
-
let time = performance.now()- start;
|
|
66
|
-
console.log(
|
|
64
|
+
let time = performance.now() - start;
|
|
65
|
+
console.log(JSON.stringify({ iterations: iterations, time: Math.round(time) }));
|
|
67
66
|
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/doc/benchmarks.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# Benchmarks
|
|
2
2
|
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
3
5
|
Here is a quick overview of the execution time of Koffi calls on three benchmarks, where it is compared to a theoretical ideal FFI implementation (approximated with pre-compiled static N-API glue code):
|
|
4
6
|
|
|
5
7
|
- The first benchmark is based on `rand()` calls
|
|
@@ -8,14 +10,18 @@ Here is a quick overview of the execution time of Koffi calls on three benchmark
|
|
|
8
10
|
|
|
9
11
|
<table style="margin: 0 auto;">
|
|
10
12
|
<tr>
|
|
11
|
-
<td><a href="_static/
|
|
12
|
-
<td><a href="_static/
|
|
13
|
+
<td><a href="_static/perf_linux_20220628.png" target="_blank"><img src="_static/perf_linux_20220628.png" alt="Linux performance" style="width: 350px;"/></a></td>
|
|
14
|
+
<td><a href="_static/perf_windows_20220628.png" target="_blank"><img src="_static/perf_windows_20220628.png" alt="Windows performance" style="width: 350px;"/></a></td>
|
|
13
15
|
</tr>
|
|
14
16
|
</table>
|
|
15
17
|
|
|
16
18
|
These results are detailed and explained below, and compared to node-ffi/node-ffi-napi.
|
|
17
19
|
|
|
18
|
-
##
|
|
20
|
+
## Linux x86_64
|
|
21
|
+
|
|
22
|
+
The results presented below were measured on my x86_64 Linux machine (Intel® Core™ i5-4460).
|
|
23
|
+
|
|
24
|
+
### rand results
|
|
19
25
|
|
|
20
26
|
This test is based around repeated calls to a simple standard C function atoi, and has three implementations:
|
|
21
27
|
|
|
@@ -23,95 +29,109 @@ This test is based around repeated calls to a simple standard C function atoi, a
|
|
|
23
29
|
- the second one calls atoi through Koffi
|
|
24
30
|
- the third one uses the official Node.js FFI implementation, node-ffi-napi
|
|
25
31
|
|
|
32
|
+
Benchmark | Iteration time | Relative performance | Overhead
|
|
33
|
+
------------- | -------------- | -------------------- | --------
|
|
34
|
+
rand_napi | 644 ns | x1.00 | (ref)
|
|
35
|
+
rand_koffi | 950 ns | x0.68 | +48%
|
|
36
|
+
rand_node_ffi | 30350 ns | x0.02 | +4613%
|
|
37
|
+
|
|
26
38
|
Because rand is a pretty small function, the FFI overhead is clearly visible.
|
|
27
39
|
|
|
28
|
-
###
|
|
40
|
+
### atoi results
|
|
29
41
|
|
|
30
|
-
|
|
42
|
+
This test is similar to the rand one, but it is based on atoi, which takes a string parameter. Javascript (V8) to C string conversion is relatively slow and heavy.
|
|
31
43
|
|
|
32
|
-
Benchmark |
|
|
33
|
-
------------- |
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
44
|
+
Benchmark | Iteration time | Relative performance | Overhead
|
|
45
|
+
------------- | -------------- | -------------------- | --------
|
|
46
|
+
atoi_napi | 1104 ns | x1.00 | (ref)
|
|
47
|
+
atoi_koffi | 1778 ns | x0.62 | +61%
|
|
48
|
+
atoi_node_ffi | 125300 ns | x0.009 | +11250%
|
|
37
49
|
|
|
38
|
-
|
|
50
|
+
Because atoi is a pretty small function, the FFI overhead is clearly visible.
|
|
39
51
|
|
|
40
|
-
|
|
52
|
+
### Raylib results
|
|
53
|
+
|
|
54
|
+
This benchmark uses the CPU-based image drawing functions in Raylib. The calls are much heavier than in the atoi benchmark, thus the FFI overhead is reduced. In this implementation, Koffi is compared to:
|
|
41
55
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
rand_napi | 20000000 | 2.10s | (baseline) | (baseline)
|
|
45
|
-
rand_koffi | 20000000 | 3.87s | x0.54 | +84%
|
|
46
|
-
rand_node_ffi | 20000000 | 87.84s | x0.02 | +4100%
|
|
56
|
+
- Baseline: Full C++ version of the code (no JS)
|
|
57
|
+
- [node-raylib](https://github.com/RobLoach/node-raylib): This is a native wrapper implemented with N-API
|
|
47
58
|
|
|
48
|
-
|
|
59
|
+
Benchmark | Iteration time | Relative performance | Overhead
|
|
60
|
+
------------------ | -------------- | -------------------- | --------
|
|
61
|
+
raylib_cc | 215.7 µs | x1.20 | -17%
|
|
62
|
+
raylib_node_raylib | 258.9 µs | x1.00 | (ref)
|
|
63
|
+
raylib_koffi | 311.6 µs | x0.83 | +20%
|
|
64
|
+
raylib_node_ffi | 928.4 µs | x0.28 | +259%
|
|
49
65
|
|
|
50
|
-
|
|
66
|
+
## Windows x86_64
|
|
51
67
|
|
|
52
|
-
|
|
68
|
+
The results presented below were measured on my x86_64 Windows machine (Intel® Core™ i5-4460).
|
|
69
|
+
|
|
70
|
+
### rand results
|
|
53
71
|
|
|
54
|
-
|
|
72
|
+
This test is based around repeated calls to a simple standard C function atoi, and has three implementations:
|
|
55
73
|
|
|
56
|
-
|
|
74
|
+
- the first one is the reference, it calls atoi through an N-API module, and is close to the theoretical limit of a perfect (no overhead) Node.js > C FFI implementation (pre-compiled static glue code)
|
|
75
|
+
- the second one calls atoi through Koffi
|
|
76
|
+
- the third one uses the official Node.js FFI implementation, node-ffi-napi
|
|
57
77
|
|
|
58
|
-
Benchmark |
|
|
59
|
-
------------- |
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
78
|
+
Benchmark | Iteration time | Relative performance | Overhead
|
|
79
|
+
------------- | -------------- | -------------------- | --------
|
|
80
|
+
rand_napi | 965 ns | x1.00 | (ref)
|
|
81
|
+
rand_koffi | 1248 ns | x0.77 | +29%
|
|
82
|
+
rand_node_ffi | 41500 ns | x0.02 | +4203%
|
|
63
83
|
|
|
64
|
-
|
|
84
|
+
Because rand is a pretty small function, the FFI overhead is clearly visible.
|
|
65
85
|
|
|
66
|
-
|
|
86
|
+
### atoi results
|
|
67
87
|
|
|
68
|
-
|
|
69
|
-
------------- | ---------- | ----------- | -------------------- | ----------
|
|
70
|
-
atoi_napi | 20000000 | 2.97s | (baseline) | (baseline)
|
|
71
|
-
atoi_koffi | 20000000 | 5.91s | x0.50 | +99%
|
|
72
|
-
atoi_node_ffi | 20000000 | 479.34s | x0.006 | +16000%
|
|
88
|
+
This test is similar to the rand one, but it is based on atoi, which takes a string parameter. Javascript (V8) to C string conversion is relatively slow and heavy.
|
|
73
89
|
|
|
74
|
-
|
|
90
|
+
The results below were measured on my x86_64 Windows machine (Intel® Core™ i5-4460):
|
|
75
91
|
|
|
76
|
-
|
|
92
|
+
Benchmark | Iteration time | Relative performance | Overhead
|
|
93
|
+
------------- | -------------- | -------------------- | --------
|
|
94
|
+
atoi_napi | 1393 ns | x1.00 | (ref)
|
|
95
|
+
atoi_koffi | 2246 ns | x0.62 | +61%
|
|
96
|
+
atoi_node_ffi | 157550 ns | x0.009 | +11210%
|
|
77
97
|
|
|
78
|
-
|
|
79
|
-
- [node-raylib](https://github.com/RobLoach/node-raylib): This is a native wrapper implemented with N-API
|
|
98
|
+
Because atoi is a pretty small function, the FFI overhead is clearly visible.
|
|
80
99
|
|
|
81
|
-
###
|
|
100
|
+
### Raylib results
|
|
82
101
|
|
|
83
|
-
The
|
|
102
|
+
This benchmark uses the CPU-based image drawing functions in Raylib. The calls are much heavier than in the atoi benchmark, thus the FFI overhead is reduced. In this implementation, Koffi is compared to:
|
|
84
103
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
raylib_cc | 100 | 9.31s | x1.17 | -15%
|
|
88
|
-
raylib_node_raylib | 100 | 10.90s | (baseline) | (baseline)
|
|
89
|
-
raylib_koffi | 100 | 12.86s | x0.84 | +18%
|
|
90
|
-
raylib_node_ffi | 100 | 35.76s | x0.30 | +228%
|
|
104
|
+
- [node-raylib](https://github.com/RobLoach/node-raylib) (baseline): This is a native wrapper implemented with N-API
|
|
105
|
+
- raylib_cc: C++ implementation of the benchmark, without any Javascript
|
|
91
106
|
|
|
92
|
-
|
|
107
|
+
Benchmark | Iteration time | Relative performance | Overhead
|
|
108
|
+
------------------ | -------------- | -------------------- | --------
|
|
109
|
+
raylib_cc | 211.8 µs | x1.25 | -20%
|
|
110
|
+
raylib_node_raylib | 264.4 µs | x1.00 | (ref)
|
|
111
|
+
raylib_koffi | 318.9 µs | x0.83 | +21%
|
|
112
|
+
raylib_node_ffi | 1146.2 µs | x0.23 | +334%
|
|
93
113
|
|
|
94
|
-
|
|
114
|
+
Please note that in order to get fair numbers for raylib_node_raylib, it was recompiled with clang-cl before running the benchmark with the following commands:
|
|
95
115
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
raylib_node_ffi | 100 | 44.63s | x0.27 | +270%
|
|
116
|
+
```batch
|
|
117
|
+
cd node_modules\raylib
|
|
118
|
+
rmdir /S /Q bin build
|
|
119
|
+
npx cmake-js compile -t ClangCL
|
|
120
|
+
```
|
|
102
121
|
|
|
103
122
|
## Running benchmarks
|
|
104
123
|
|
|
105
124
|
Open a console, go to `koffi/benchmark` and run `../../cnoke/cnoke.js` (or `node ..\..\cnoke\cnoke.js` on Windows) before doing anything else.
|
|
106
125
|
|
|
126
|
+
Please note that all benchmark results are made with Clang-built binaries.
|
|
127
|
+
|
|
107
128
|
```sh
|
|
108
129
|
cd koffi/benchmark
|
|
109
|
-
node ../../cnoke/cnoke.js
|
|
130
|
+
node ../../cnoke/cnoke.js --prefer-clang
|
|
110
131
|
```
|
|
111
132
|
|
|
112
|
-
Once
|
|
133
|
+
Once everything is built and ready, run:
|
|
113
134
|
|
|
114
135
|
```sh
|
|
115
|
-
node
|
|
116
|
-
node ./atoi_koffi.js
|
|
136
|
+
node benchmark.js
|
|
117
137
|
```
|
package/doc/benchmarks.xlsx
CHANGED
|
Binary file
|
package/doc/conf.py
CHANGED
package/doc/contribute.md
CHANGED
|
@@ -69,7 +69,7 @@ Note that the machine disk content may change each time the machine runs, so the
|
|
|
69
69
|
And now you can run the tests with:
|
|
70
70
|
|
|
71
71
|
```sh
|
|
72
|
-
node qemu.js # Several options are available, use --help
|
|
72
|
+
node qemu.js test # Several options are available, use --help
|
|
73
73
|
```
|
|
74
74
|
|
|
75
75
|
And be patient, this can be pretty slow for emulated machines. The Linux machines have and use ccache to build Koffi, so subsequent build steps will get much more tolerable.
|
|
@@ -78,8 +78,8 @@ By default, machines are started and stopped for each test. But you can start th
|
|
|
78
78
|
|
|
79
79
|
```sh
|
|
80
80
|
node qemu.js start # Start the machines
|
|
81
|
-
node qemu.js # Test (without shutting down)
|
|
82
|
-
node qemu.js # Test again
|
|
81
|
+
node qemu.js test # Test (without shutting down)
|
|
82
|
+
node qemu.js test # Test again
|
|
83
83
|
node qemu.js stop # Stop everything
|
|
84
84
|
```
|
|
85
85
|
|
|
@@ -109,18 +109,15 @@ node qemu.js info debian_x64
|
|
|
109
109
|
|
|
110
110
|
## Todo list
|
|
111
111
|
|
|
112
|
-
|
|
112
|
+
The following features and improvements are planned, not necessarily in that order:
|
|
113
113
|
|
|
114
|
-
-
|
|
115
|
-
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
- Optimize passing of structs and arrays, with separate HFA-specific helper functions
|
|
114
|
+
- Provide better ways to automatically deal with caller/heap-allocated memory (strings, etc.)
|
|
115
|
+
- Optimize passing of structs and arrays (avoid setting named properties one by one? separate HFA-specific helper functions?)
|
|
116
|
+
- Automate Windows/AArch64 (qemu) and macOS/AArch64 (how? ... thanks Apple) tests
|
|
117
|
+
- Create a real-world example, using several libraries (Raylib, SQLite, libsodium) to illustrate various C API styles
|
|
120
118
|
- Add simple struct type parser
|
|
121
119
|
- Add more ways to manually encode and decode various types to and from byte arrays
|
|
122
120
|
- Add support for unions
|
|
123
|
-
- Provide better ways to automatically deal with caller/heap-allocated memory (strings, etc.)
|
|
124
121
|
- Port Koffi to PowerPC (POWER9+) ABI
|
|
125
122
|
- Fix assembly unwind and CFI directives for better debugging experience
|
|
126
123
|
|