koffi 1.3.0 → 1.3.3

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.
Files changed (94) hide show
  1. package/CMakeLists.txt +32 -4
  2. package/ChangeLog.md +79 -0
  3. package/build/qemu/1.3.3/koffi_darwin_arm64.tar.gz +0 -0
  4. package/build/qemu/1.3.3/koffi_darwin_x64.tar.gz +0 -0
  5. package/build/qemu/1.3.3/koffi_freebsd_arm64.tar.gz +0 -0
  6. package/build/qemu/1.3.3/koffi_freebsd_ia32.tar.gz +0 -0
  7. package/build/qemu/1.3.3/koffi_freebsd_x64.tar.gz +0 -0
  8. package/build/qemu/1.3.3/koffi_linux_arm32hf.tar.gz +0 -0
  9. package/build/qemu/1.3.3/koffi_linux_arm64.tar.gz +0 -0
  10. package/build/qemu/1.3.3/koffi_linux_ia32.tar.gz +0 -0
  11. package/build/qemu/1.3.3/koffi_linux_riscv64hf64.tar.gz +0 -0
  12. package/build/qemu/1.3.3/koffi_linux_x64.tar.gz +0 -0
  13. package/build/qemu/1.3.3/koffi_openbsd_ia32.tar.gz +0 -0
  14. package/build/qemu/1.3.3/koffi_openbsd_x64.tar.gz +0 -0
  15. package/build/qemu/1.3.3/koffi_win32_arm64.tar.gz +0 -0
  16. package/build/qemu/1.3.3/koffi_win32_ia32.tar.gz +0 -0
  17. package/build/qemu/1.3.3/koffi_win32_x64.tar.gz +0 -0
  18. package/doc/_static/perf_linux_20220623.png +0 -0
  19. package/doc/_static/perf_linux_20220623_2.png +0 -0
  20. package/doc/_static/perf_windows_20220623.png +0 -0
  21. package/doc/_static/perf_windows_20220623_2.png +0 -0
  22. package/doc/benchmarks.md +40 -36
  23. package/doc/benchmarks.xlsx +0 -0
  24. package/doc/changes.md +2 -0
  25. package/doc/conf.py +10 -3
  26. package/doc/contribute.md +16 -0
  27. package/doc/dist/doctrees/benchmarks.doctree +0 -0
  28. package/doc/dist/doctrees/changes.doctree +0 -0
  29. package/doc/dist/doctrees/contribute.doctree +0 -0
  30. package/doc/dist/doctrees/environment.pickle +0 -0
  31. package/doc/dist/doctrees/functions.doctree +0 -0
  32. package/doc/dist/doctrees/index.doctree +0 -0
  33. package/doc/dist/doctrees/platforms.doctree +0 -0
  34. package/doc/dist/html/_sources/benchmarks.md.txt +40 -36
  35. package/doc/dist/html/_sources/changes.md.txt +2 -0
  36. package/doc/dist/html/_sources/contribute.md.txt +16 -0
  37. package/doc/dist/html/_sources/functions.md.txt +2 -0
  38. package/doc/dist/html/_sources/index.rst.txt +2 -1
  39. package/doc/dist/html/_sources/platforms.md.txt +2 -0
  40. package/doc/dist/html/_static/perf_linux_20220623.png +0 -0
  41. package/doc/dist/html/_static/perf_linux_20220623_2.png +0 -0
  42. package/doc/dist/html/_static/perf_windows_20220623.png +0 -0
  43. package/doc/dist/html/_static/perf_windows_20220623_2.png +0 -0
  44. package/doc/dist/html/benchmarks.html +52 -20
  45. package/doc/dist/html/changes.html +369 -0
  46. package/doc/dist/html/contribute.html +24 -2
  47. package/doc/dist/html/functions.html +2 -0
  48. package/doc/dist/html/genindex.html +1 -0
  49. package/doc/dist/html/index.html +15 -3
  50. package/doc/dist/html/memory.html +1 -0
  51. package/doc/dist/html/objects.inv +0 -0
  52. package/doc/dist/html/platforms.html +3 -1
  53. package/doc/dist/html/search.html +1 -0
  54. package/doc/dist/html/searchindex.js +1 -1
  55. package/doc/dist/html/start.html +1 -0
  56. package/doc/dist/html/types.html +1 -0
  57. package/doc/functions.md +2 -0
  58. package/doc/index.rst +2 -1
  59. package/doc/platforms.md +2 -0
  60. package/package.json +4 -3
  61. package/qemu/qemu.js +2 -1
  62. package/src/abi_arm32.cc +9 -9
  63. package/src/abi_arm64.cc +9 -9
  64. package/src/abi_riscv64.cc +9 -9
  65. package/src/abi_x64_sysv.cc +9 -9
  66. package/src/abi_x64_sysv_fwd.S +14 -4
  67. package/src/abi_x64_win.cc +9 -9
  68. package/src/abi_x86.cc +9 -9
  69. package/src/abi_x86_fwd.S +6 -4
  70. package/src/call.cc +10 -10
  71. package/src/call.hh +6 -0
  72. package/src/ffi.cc +3 -1
  73. package/src/parser.cc +1 -1
  74. package/src/util.hh +21 -1
  75. package/test/CMakeLists.txt +1 -1
  76. package/test/misc.c +20 -0
  77. package/test/sync.js +13 -3
  78. package/vendor/libcc/libcc.cc +17 -5
  79. package/vendor/libcc/libcc.hh +33 -1
  80. package/build/qemu/1.3.0/koffi_darwin_arm64.tar.gz +0 -0
  81. package/build/qemu/1.3.0/koffi_darwin_x64.tar.gz +0 -0
  82. package/build/qemu/1.3.0/koffi_freebsd_arm64.tar.gz +0 -0
  83. package/build/qemu/1.3.0/koffi_freebsd_ia32.tar.gz +0 -0
  84. package/build/qemu/1.3.0/koffi_freebsd_x64.tar.gz +0 -0
  85. package/build/qemu/1.3.0/koffi_linux_arm32hf.tar.gz +0 -0
  86. package/build/qemu/1.3.0/koffi_linux_arm64.tar.gz +0 -0
  87. package/build/qemu/1.3.0/koffi_linux_ia32.tar.gz +0 -0
  88. package/build/qemu/1.3.0/koffi_linux_riscv64hf64.tar.gz +0 -0
  89. package/build/qemu/1.3.0/koffi_linux_x64.tar.gz +0 -0
  90. package/build/qemu/1.3.0/koffi_openbsd_ia32.tar.gz +0 -0
  91. package/build/qemu/1.3.0/koffi_openbsd_x64.tar.gz +0 -0
  92. package/build/qemu/1.3.0/koffi_win32_arm64.tar.gz +0 -0
  93. package/build/qemu/1.3.0/koffi_win32_ia32.tar.gz +0 -0
  94. package/build/qemu/1.3.0/koffi_win32_x64.tar.gz +0 -0
package/CMakeLists.txt CHANGED
@@ -11,14 +11,25 @@
11
11
  # You should have received a copy of the GNU Affero General Public License
12
12
  # along with this program. If not, see https://www.gnu.org/licenses/.
13
13
 
14
- cmake_minimum_required(VERSION 3.12)
14
+ cmake_minimum_required(VERSION 3.6)
15
15
  project(koffi C CXX ASM)
16
16
 
17
+ include(CheckCXXCompilerFlag)
18
+ if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.9.0")
19
+ cmake_policy(SET CMP0069 NEW)
20
+ include(CheckIPOSupported)
21
+ check_ipo_supported(RESULT USE_LTO)
22
+ endif()
23
+
17
24
  find_package(CNoke)
18
25
 
19
- set(CMAKE_CXX_STANDARD 17)
26
+ if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.8.0")
27
+ set(CMAKE_CXX_STANDARD 17)
28
+ else()
29
+ set(CMAKE_CXX_STANDARD 14)
30
+ endif()
20
31
  if(MSVC)
21
- add_compile_options(/W4 /wd4200 /wd4458 /wd4706 /wd4100 /wd4127 /wd4702 /wd4201 /wd4324)
32
+ add_compile_options(/Zc:__cplusplus /W4 /wd4200 /wd4458 /wd4706 /wd4100 /wd4127 /wd4702 /wd4201 /wd4324)
22
33
 
23
34
  # ASM_MASM does not (yet) work on Windows ARM64
24
35
  if(NOT CMAKE_GENERATOR_PLATFORM MATCHES "ARM64")
@@ -47,6 +58,12 @@ if(CMAKE_SIZEOF_VOID_P EQUAL 8)
47
58
  if(WIN32)
48
59
  get_filename_component(cl_dir "${CMAKE_CXX_COMPILER}" DIRECTORY)
49
60
  file(TO_CMAKE_PATH "${cl_dir}/armasm64.exe" asm_compiler)
61
+
62
+ # Work around missing ARM64-native ARMASM64 compiler (at least in VS 17.3 Preview 2)
63
+ if(NOT EXISTS "${asm_compiler}")
64
+ file(TO_CMAKE_PATH "${cl_dir}/../../Hostx64/arm64/armasm64.exe" asm_compiler)
65
+ endif()
66
+
50
67
  message(STATUS "Using ARMASM64 compiler: ${asm_compiler}")
51
68
 
52
69
  file(TO_CMAKE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/src/abi_arm64_fwd.asm" asm_source)
@@ -94,5 +111,16 @@ if(WIN32)
94
111
  target_link_libraries(koffi PRIVATE ws2_32)
95
112
  endif()
96
113
  if(NOT MSVC)
97
- target_compile_options(koffi PRIVATE -fno-exceptions -fno-strict-aliasing)
114
+ # Restore C/C++ compiler sanity
115
+
116
+ target_compile_options(koffi PRIVATE -fno-exceptions -fno-strict-aliasing -fwrapv
117
+ -fno-delete-null-pointer-checks)
118
+
119
+ check_cxx_compiler_flag(-fno-finite-loops use_no_finite_loops)
120
+ if(use_no_finite_loops)
121
+ target_compile_options(koffi PRIVATE -fno-finite-loops)
122
+ endif()
123
+ endif()
124
+ if(USE_LTO)
125
+ set_target_properties(koffi PROPERTIES INTERPROCEDURAL_OPTIMIZATION TRUE)
98
126
  endif()
package/ChangeLog.md ADDED
@@ -0,0 +1,79 @@
1
+ # Changelog
2
+
3
+ ## Koffi 1.3.3
4
+
5
+ **Main fixes:**
6
+
7
+ - Fix misconversion of signed integer return value as unsigned
8
+
9
+ **Other changes:**
10
+
11
+ - Support `(void)` (empty) function signatures
12
+ - Disable unsafe compiler optimizations
13
+ - Various documentation improvements
14
+
15
+ ## Koffi 1.3.2
16
+
17
+ **Main fixes:**
18
+
19
+ - Support compilation in C++14 mode (graceful degradation)
20
+ - Support older toolchains on Linux (tested on Debian 9)
21
+
22
+ ## Koffi 1.3.1
23
+
24
+ **Main fixes:**
25
+
26
+ - The prebuilt binary is tested when Koffi is installed, and a rebuild happens if it fails to load
27
+
28
+ ## Koffi 1.3.0
29
+
30
+ **Major changes:**
31
+
32
+ - Expand and move documentation to https://koffi.dev/
33
+ - Support JS arrays and TypedArrays for pointer arguments (input, output and mixed)
34
+
35
+ **Other changes:**
36
+
37
+ - Convert NULL string pointers to null instead of crashing (return values, struct and array members, callbacks)
38
+ - Default to 'string' array hint for char, char16 and char16_t arrays
39
+ - Fix definition of long types on Windows x64 (LLP64 model)
40
+ - Restrict automatic string conversion to signed char types
41
+ - Detect floating-point ABI before using prebuilt binaries (ARM32, RISC-V)
42
+ - Forbid duplicate member names in struct types
43
+
44
+ ## Koffi 1.2.4
45
+
46
+ **New features:**
47
+
48
+ - Windows ARM64 is now supported
49
+
50
+ ## Koffi 1.2.3
51
+
52
+ **New features:**
53
+
54
+ - A prebuilt binary for macOS ARM64 (M1) is now included
55
+
56
+ ## Koffi 1.2.1
57
+
58
+ This entry documents changes since version 1.1.0.
59
+
60
+ **New features:**
61
+
62
+ - JS functions can be used as C callbacks (cdecl, stdcall) on all platforms
63
+ - RISC-V 64 LP64D ABI is supported (LP64 is untested)
64
+ - Expose settings for memory usage of synchronous and asynchronous calls
65
+ - Transparent conversion between C buffers and strings
66
+ - Tentative support for Windows ARM64 (untested)
67
+
68
+ **Main fixes:**
69
+
70
+ - Fix excessive stack alignment of structs on x86 platforms
71
+ - Fix potential problems with big int64_t/uint64_t values
72
+ - Fix possible struct layout errors in push/pop code
73
+ - Fix alignment issues in ARM32 push code
74
+ - Fix incomplete/buggy support for HFA structs on ARM32 and ARM64
75
+ - Fix crashes on OpenBSD caused by missing MAP_STACK flag
76
+ - Fix non-sense "duplicate array type" errors
77
+ - Fix value `koffi.internal` to false in module (normal) builds
78
+ - Make sure we have a redzone below the stack for all architectures
79
+ - Use slower allocation for big objects instead of failing
package/doc/benchmarks.md CHANGED
@@ -1,11 +1,15 @@
1
1
  # Benchmarks
2
2
 
3
- Here is a quick overview of the execution time of Koffi calls on three test cases (one based around rand, one based on atoi and one based on Raylib) compared to theoretical ideal implementations.
3
+ 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
+
5
+ - The first benchmark is based on `rand()` calls
6
+ - The second benchmark is based on `atoi()` calls
7
+ - The third benchmark is based on [Raylib](https://www.raylib.com/)
4
8
 
5
9
  <table style="margin: 0 auto;">
6
10
  <tr>
7
- <td><img src="_static/bench_linux.png" alt="Linux performance" style="width: 350px;"/></td>
8
- <td><img src="_static/bench_windows.png" alt="Windows performance" style="width: 350px;"/></td>
11
+ <td><a href="_static/perf_linux_20220623_2.png" target="_blank"><img src="_static/perf_linux_20220623_2.png" alt="Linux performance" style="width: 350px;"/></a></td>
12
+ <td><a href="_static/perf_windows_20220623_2.png" target="_blank"><img src="_static/perf_windows_20220623_2.png" alt="Windows performance" style="width: 350px;"/></a></td>
9
13
  </tr>
10
14
  </table>
11
15
 
@@ -15,7 +19,7 @@ These results are detailed and explained below, and compared to node-ffi/node-ff
15
19
 
16
20
  This test is based around repeated calls to a simple standard C function atoi, and has three implementations:
17
21
 
18
- - 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.
22
+ - 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)
19
23
  - the second one calls atoi through Koffi
20
24
  - the third one uses the official Node.js FFI implementation, node-ffi-napi
21
25
 
@@ -25,21 +29,21 @@ Because rand is a pretty small function, the FFI overhead is clearly visible.
25
29
 
26
30
  The results below were measured on my x86_64 Linux machine (AMD® Ryzen™ 7 4700U):
27
31
 
28
- Benchmark | Iterations | Total time | Overhead
29
- ------------- | ---------- | ----------- | ----------
30
- rand_napi | 20000000 | 1.44s | (baseline)
31
- rand_koffi | 20000000 | 2.60s | x1.81
32
- rand_node_ffi | 20000000 | 107.58s | x75
32
+ Benchmark | Iterations | Total time | Relative performance | Overhead
33
+ ------------- | ---------- | ----------- | -------------------- | ----------
34
+ rand_napi | 20000000 | 1.44s | (baseline) | (baseline)
35
+ rand_koffi | 20000000 | 2.60s | x0.55 | +81%
36
+ rand_node_ffi | 20000000 | 107.58s | x0.01 | +7400%
33
37
 
34
38
  ### Windows x86_64
35
39
 
36
40
  The results below were measured on my x86_64 Windows machine (Intel® Core™ i5-4460):
37
41
 
38
- Benchmark | Iterations | Total time | Overhead
39
- ------------- | ---------- | ----------- | ----------
40
- rand_napi | 20000000 | 2.10s | (baseline)
41
- rand_koffi | 20000000 | 3.87s | x1.84
42
- rand_node_ffi | 20000000 | 87.84s | x42
42
+ Benchmark | Iterations | Total time | Relative performance | Overhead
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%
43
47
 
44
48
  ## atoi results
45
49
 
@@ -51,21 +55,21 @@ Because rand is a pretty small function, the FFI overhead is clearly visible.
51
55
 
52
56
  The results below were measured on my x86_64 Linux machine (AMD® Ryzen™ 7 4700U):
53
57
 
54
- Benchmark | Iterations | Total time | Overhead
55
- ------------- | ---------- | ----------- | ----------
56
- atoi_napi | 20000000 | 2.97s | (baseline)
57
- atoi_koffi | 20000000 | 5.07s | x1.71
58
- atoi_node_ffi | 20000000 | 693.16s | x233
58
+ Benchmark | Iterations | Total time | Relative performance | Overhead
59
+ ------------- | ---------- | ----------- | -------------------- | ----------
60
+ atoi_napi | 20000000 | 2.97s | (baseline) | (baseline)
61
+ atoi_koffi | 20000000 | 5.07s | x0.58 | +71%
62
+ atoi_node_ffi | 20000000 | 693.16s | x0.005 | +23000%
59
63
 
60
64
  ### Windows x86_64
61
65
 
62
66
  The results below were measured on my x86_64 Windows machine (Intel® Core™ i5-4460):
63
67
 
64
- Benchmark | Iterations | Total time | Overhead
65
- ------------- | ---------- | ----------- | ----------
66
- atoi_napi | 20000000 | 2.97s | (baseline)
67
- atoi_koffi | 20000000 | 5.91s | x1.99
68
- atoi_node_ffi | 20000000 | 479.34s | x161
68
+ Benchmark | Iterations | Total time | Relative performance | Overhead
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%
69
73
 
70
74
  ## Raylib results
71
75
 
@@ -78,23 +82,23 @@ This benchmark uses the CPU-based image drawing functions in Raylib. The calls a
78
82
 
79
83
  The results below were measured on my x86_64 Linux machine (AMD® Ryzen™ 7 4700U):
80
84
 
81
- Benchmark | Iterations | Total time | Overhead
82
- --------------- | ---------- | ----------- | ----------
83
- raylib_cc | 100 | 9.31s | (baseline)
84
- raylib_node_raylib | 100 | 10.90s | x1.17
85
- raylib_koffi | 100 | 12.86s | x1.38
86
- raylib_node_ffi | 100 | 35.76s | x3.84
85
+ Benchmark | Iterations | Total time | Relative performance | Overhead
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%
87
91
 
88
92
  ### Windows x86_64
89
93
 
90
94
  The results below were measured on my x86_64 Windows machine (Intel® Core™ i5-4460):
91
95
 
92
- Benchmark | Iterations | Total time | Overhead
93
- --------------- | ---------- | ----------- | ----------
94
- raylib_cc | 100 | 10.67s | (baseline)
95
- raylib_node_raylib | 100 | 12.05s | x1.13
96
- raylib_koffi | 100 | 14.84s | x1.39
97
- raylib_node_ffi | 100 | 44.63s | x4.18
96
+ Benchmark | Iterations | Total time | Relative performance | Overhead
97
+ --------------- | ---------- | ----------- | -------------------- | ----------
98
+ raylib_cc | 100 | 10.67s | x1.17 | -12%
99
+ raylib_node_raylib | 100 | 12.05s | (baseline) | (baseline)
100
+ raylib_koffi | 100 | 14.84s | x0.81 | +23%
101
+ raylib_node_ffi | 100 | 44.63s | x0.27 | +270%
98
102
 
99
103
  ## Running benchmarks
100
104
 
Binary file
package/doc/changes.md ADDED
@@ -0,0 +1,2 @@
1
+ ```{include} ../ChangeLog.md
2
+ ```
package/doc/conf.py CHANGED
@@ -1,10 +1,17 @@
1
+ import json
2
+ import os
3
+
1
4
  # -- Project information -----------------------------------------------------
2
5
 
3
6
  project = 'Koffi'
4
7
  copyright = '2022, Niels Martignène'
5
8
  author = 'Niels Martignène'
6
- version = '1.3.0'
7
- revision = '1.3.0'
9
+
10
+ with open(os.path.dirname(__file__) + '/../package.json') as f:
11
+ config = json.load(f)
12
+
13
+ version = config['version']
14
+ revision = config['version']
8
15
 
9
16
  # -- General configuration ---------------------------------------------------
10
17
 
@@ -20,7 +27,7 @@ exclude_patterns = []
20
27
 
21
28
  # -- Options for HTML output -------------------------------------------------
22
29
 
23
- html_title = 'Koffi'
30
+ html_title = project
24
31
 
25
32
  html_theme = 'furo'
26
33
 
package/doc/contribute.md CHANGED
@@ -10,6 +10,15 @@ Go here: https://github.com/Koromix/luigi/issues
10
10
 
11
11
  We provide prebuilt binaries, packaged in the NPM archive, so in most cases it should be as simple as `npm install koffi`. If you want to hack Koffi or use a specific platform, follow the instructions below.
12
12
 
13
+ Start by cloning the repository with [Git](https://git-scm.com/):
14
+
15
+ ```sh
16
+ git clone https://github.com/Koromix/luigi
17
+ cd luigi/koffi
18
+ ```
19
+
20
+ As said before, this is a monorepository containg multiple projects, hence the name.
21
+
13
22
  ### Windows
14
23
 
15
24
  First, make sure the following dependencies are met:
@@ -113,3 +122,10 @@ The following features are also planned eventually, not necessarily in that orde
113
122
  - Add support for unions
114
123
  - Provide better ways to automatically deal with caller/heap-allocated memory (strings, etc.)
115
124
  - Port Koffi to PowerPC (POWER9+) ABI
125
+ - Fix assembly unwind and CFI directives for better debugging experience
126
+
127
+ ## Code style
128
+
129
+ Koffi is programmed in a mix of C++ and assembly code (architecture-specific code). It uses [node-addon-api](https://github.com/nodejs/node-addon-api) (C++ N-API wrapper) to interact with Node.js.
130
+
131
+ My personal preference goes to a rather C-like C++ style, with careful use of templates (mainly for containers) and little object-oriented programming. I strongly prefer tagged unions and code locality over inheritance and virtual methods. Exceptions are disabled.
Binary file
Binary file
Binary file
@@ -1,11 +1,15 @@
1
1
  # Benchmarks
2
2
 
3
- Here is a quick overview of the execution time of Koffi calls on three test cases (one based around rand, one based on atoi and one based on Raylib) compared to theoretical ideal implementations.
3
+ 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
+
5
+ - The first benchmark is based on `rand()` calls
6
+ - The second benchmark is based on `atoi()` calls
7
+ - The third benchmark is based on [Raylib](https://www.raylib.com/)
4
8
 
5
9
  <table style="margin: 0 auto;">
6
10
  <tr>
7
- <td><img src="_static/bench_linux.png" alt="Linux performance" style="width: 350px;"/></td>
8
- <td><img src="_static/bench_windows.png" alt="Windows performance" style="width: 350px;"/></td>
11
+ <td><a href="_static/perf_linux_20220623_2.png" target="_blank"><img src="_static/perf_linux_20220623_2.png" alt="Linux performance" style="width: 350px;"/></a></td>
12
+ <td><a href="_static/perf_windows_20220623_2.png" target="_blank"><img src="_static/perf_windows_20220623_2.png" alt="Windows performance" style="width: 350px;"/></a></td>
9
13
  </tr>
10
14
  </table>
11
15
 
@@ -15,7 +19,7 @@ These results are detailed and explained below, and compared to node-ffi/node-ff
15
19
 
16
20
  This test is based around repeated calls to a simple standard C function atoi, and has three implementations:
17
21
 
18
- - 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.
22
+ - 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)
19
23
  - the second one calls atoi through Koffi
20
24
  - the third one uses the official Node.js FFI implementation, node-ffi-napi
21
25
 
@@ -25,21 +29,21 @@ Because rand is a pretty small function, the FFI overhead is clearly visible.
25
29
 
26
30
  The results below were measured on my x86_64 Linux machine (AMD® Ryzen™ 7 4700U):
27
31
 
28
- Benchmark | Iterations | Total time | Overhead
29
- ------------- | ---------- | ----------- | ----------
30
- rand_napi | 20000000 | 1.44s | (baseline)
31
- rand_koffi | 20000000 | 2.60s | x1.81
32
- rand_node_ffi | 20000000 | 107.58s | x75
32
+ Benchmark | Iterations | Total time | Relative performance | Overhead
33
+ ------------- | ---------- | ----------- | -------------------- | ----------
34
+ rand_napi | 20000000 | 1.44s | (baseline) | (baseline)
35
+ rand_koffi | 20000000 | 2.60s | x0.55 | +81%
36
+ rand_node_ffi | 20000000 | 107.58s | x0.01 | +7400%
33
37
 
34
38
  ### Windows x86_64
35
39
 
36
40
  The results below were measured on my x86_64 Windows machine (Intel® Core™ i5-4460):
37
41
 
38
- Benchmark | Iterations | Total time | Overhead
39
- ------------- | ---------- | ----------- | ----------
40
- rand_napi | 20000000 | 2.10s | (baseline)
41
- rand_koffi | 20000000 | 3.87s | x1.84
42
- rand_node_ffi | 20000000 | 87.84s | x42
42
+ Benchmark | Iterations | Total time | Relative performance | Overhead
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%
43
47
 
44
48
  ## atoi results
45
49
 
@@ -51,21 +55,21 @@ Because rand is a pretty small function, the FFI overhead is clearly visible.
51
55
 
52
56
  The results below were measured on my x86_64 Linux machine (AMD® Ryzen™ 7 4700U):
53
57
 
54
- Benchmark | Iterations | Total time | Overhead
55
- ------------- | ---------- | ----------- | ----------
56
- atoi_napi | 20000000 | 2.97s | (baseline)
57
- atoi_koffi | 20000000 | 5.07s | x1.71
58
- atoi_node_ffi | 20000000 | 693.16s | x233
58
+ Benchmark | Iterations | Total time | Relative performance | Overhead
59
+ ------------- | ---------- | ----------- | -------------------- | ----------
60
+ atoi_napi | 20000000 | 2.97s | (baseline) | (baseline)
61
+ atoi_koffi | 20000000 | 5.07s | x0.58 | +71%
62
+ atoi_node_ffi | 20000000 | 693.16s | x0.005 | +23000%
59
63
 
60
64
  ### Windows x86_64
61
65
 
62
66
  The results below were measured on my x86_64 Windows machine (Intel® Core™ i5-4460):
63
67
 
64
- Benchmark | Iterations | Total time | Overhead
65
- ------------- | ---------- | ----------- | ----------
66
- atoi_napi | 20000000 | 2.97s | (baseline)
67
- atoi_koffi | 20000000 | 5.91s | x1.99
68
- atoi_node_ffi | 20000000 | 479.34s | x161
68
+ Benchmark | Iterations | Total time | Relative performance | Overhead
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%
69
73
 
70
74
  ## Raylib results
71
75
 
@@ -78,23 +82,23 @@ This benchmark uses the CPU-based image drawing functions in Raylib. The calls a
78
82
 
79
83
  The results below were measured on my x86_64 Linux machine (AMD® Ryzen™ 7 4700U):
80
84
 
81
- Benchmark | Iterations | Total time | Overhead
82
- --------------- | ---------- | ----------- | ----------
83
- raylib_cc | 100 | 9.31s | (baseline)
84
- raylib_node_raylib | 100 | 10.90s | x1.17
85
- raylib_koffi | 100 | 12.86s | x1.38
86
- raylib_node_ffi | 100 | 35.76s | x3.84
85
+ Benchmark | Iterations | Total time | Relative performance | Overhead
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%
87
91
 
88
92
  ### Windows x86_64
89
93
 
90
94
  The results below were measured on my x86_64 Windows machine (Intel® Core™ i5-4460):
91
95
 
92
- Benchmark | Iterations | Total time | Overhead
93
- --------------- | ---------- | ----------- | ----------
94
- raylib_cc | 100 | 10.67s | (baseline)
95
- raylib_node_raylib | 100 | 12.05s | x1.13
96
- raylib_koffi | 100 | 14.84s | x1.39
97
- raylib_node_ffi | 100 | 44.63s | x4.18
96
+ Benchmark | Iterations | Total time | Relative performance | Overhead
97
+ --------------- | ---------- | ----------- | -------------------- | ----------
98
+ raylib_cc | 100 | 10.67s | x1.17 | -12%
99
+ raylib_node_raylib | 100 | 12.05s | (baseline) | (baseline)
100
+ raylib_koffi | 100 | 14.84s | x0.81 | +23%
101
+ raylib_node_ffi | 100 | 44.63s | x0.27 | +270%
98
102
 
99
103
  ## Running benchmarks
100
104
 
@@ -0,0 +1,2 @@
1
+ ```{include} ../ChangeLog.md
2
+ ```
@@ -10,6 +10,15 @@ Go here: https://github.com/Koromix/luigi/issues
10
10
 
11
11
  We provide prebuilt binaries, packaged in the NPM archive, so in most cases it should be as simple as `npm install koffi`. If you want to hack Koffi or use a specific platform, follow the instructions below.
12
12
 
13
+ Start by cloning the repository with [Git](https://git-scm.com/):
14
+
15
+ ```sh
16
+ git clone https://github.com/Koromix/luigi
17
+ cd luigi/koffi
18
+ ```
19
+
20
+ As said before, this is a monorepository containg multiple projects, hence the name.
21
+
13
22
  ### Windows
14
23
 
15
24
  First, make sure the following dependencies are met:
@@ -113,3 +122,10 @@ The following features are also planned eventually, not necessarily in that orde
113
122
  - Add support for unions
114
123
  - Provide better ways to automatically deal with caller/heap-allocated memory (strings, etc.)
115
124
  - Port Koffi to PowerPC (POWER9+) ABI
125
+ - Fix assembly unwind and CFI directives for better debugging experience
126
+
127
+ ## Code style
128
+
129
+ Koffi is programmed in a mix of C++ and assembly code (architecture-specific code). It uses [node-addon-api](https://github.com/nodejs/node-addon-api) (C++ N-API wrapper) to interact with Node.js.
130
+
131
+ My personal preference goes to a rather C-like C++ style, with careful use of templates (mainly for containers) and little object-oriented programming. I strongly prefer tagged unions and code locality over inheritance and virtual methods. Exceptions are disabled.
@@ -78,6 +78,8 @@ console.log('Hello World!');
78
78
  // This program will print "Hello World!", and then "Result: 1257"
79
79
  ```
80
80
 
81
+ These calls are executed by worker threads. It is **your responsibility to deal with data sharing issues** in the native code that may be caused by multi-threading.
82
+
81
83
  You can easily convert this callback-style async function to a promise-based version with `util.promisify()` from the Node.js standard library.
82
84
 
83
85
  Variadic functions cannot be called asynchronously.
@@ -6,7 +6,7 @@ Overview
6
6
 
7
7
  Koffi is a **fast and easy-to-use C FFI module for Node.js**, featuring:
8
8
 
9
- * Low-overhead and fast performance (see :ref:`Benchmarks`)
9
+ * Low-overhead and fast performance (see :ref:`benchmarks<Benchmarks>`)
10
10
  * Support for primitive and aggregate data types (structs and fixed-size arrays), both by reference (pointer) and by value
11
11
  * Javascript functions can be used as C callbacks (since 1.2.0)
12
12
  * Well-tested code base for :ref:`popular OS/architecture combinations<Supported platforms>`
@@ -24,6 +24,7 @@ Table of contents
24
24
  memory
25
25
  benchmarks
26
26
  contribute
27
+ changes
27
28
 
28
29
  License
29
30
  -------
@@ -12,6 +12,8 @@ RISC-V 64 [^3] | ⬜️ *N/A* | ✅ Yes | ⬜️ *N/A* | 🟨 Probab
12
12
 
13
13
  For all fully supported platforms (green check marks), a prebuilt binary is included in the NPM package which means you can install Koffi without a C++ compiler.
14
14
 
15
+ Node 12 or later is required, earlier versions are not supported. Use [NVM](https://github.com/nvm-sh/nvm) to install recent Node versions on older Linux distributions.
16
+
15
17
  [^1]: The following call conventions are supported for forward calls: cdecl, stdcall, MS fastcall, thiscall. Only cdecl and stdcall can be used for C to JS callbacks.
16
18
  [^2]: The prebuilt binary uses the hard float ABI and expects a VFP coprocessor. Build from source to use Koffi with a different ABI (softfp, soft).
17
19
  [^3]: The prebuilt binary uses the LP64D (double-precision float) ABI. The LP64 ABI is supported in theory if you build Koffi from source (untested), the LP64F ABI is not supported.