diff --git a/README.md b/README.md index 37a2743..194c9e8 100644 --- a/README.md +++ b/README.md @@ -6,22 +6,25 @@ Write a library to interface between Lua, and wasm, for enabling communication b ## Performance: -There is a poor mans performance test implementation, that imitates [Bram's implementation](https://github.com/vim/vim/blob/master/README_VIM9.md) of just summing a number inside a for loop, more will be done later, but as it appears now, wasm is faster than luajit atleast on my Windows 10 machine as you can see from the results: -![1690628636000](./imgs/1690628636000.png) +- The first test is a poor mans performance test implementation, that imitates [Bram's implementation](https://github.com/vim/vim/blob/master/README_VIM9.md) of just summing a number inside a for loop, wasm is faster by **99%**, due to compiler optimizations of the language om this case it is zig, this mostly shows the compilation optmization benefits that compiling to wasm could bring to the table vs JIT with LuaJIT. -Wasm version is atleast 30% faster than luajit/neovim version, if you compile for full optimisation for example in rust, you can get even 90% boost as seen in the image. -To run this test simply run the bellow: +- The second one is a test where we try get the prime numbers between 0-10000, and count the number of times it could be achieved within 5 seconds, there is no constants, so even the wasm compiled shouldn't optimize the away almost all the operations like it did in the first test. Here wasm was **99%** faster than Luajit. I didn't want to optmize the algorithm for each specific language, instead used basic structures, and avoid bitwise manipulation or stack pre allocation even on the zig/wasm side. -```sh -cargo make perf -``` +- This image shows the tests:![1690628636000](./imgs/perf.png) +- To run this test simply run the bellow: + + ```sh + cargo make perf + ``` + + Requires: -Requires: + - `cargo-make` which can be installed by `cargo install cargo-make` . + - `zig` to be in system path, can be installed from [Download ⚡ Zig Programming Language (ziglang.org)](https://ziglang.org/download/) -- `cargo-make` which can be installed by `cargo install cargo-make` . -- `zig` to be in system path, can be installed from [Download ⚡ Zig Programming Language (ziglang.org)](https://ziglang.org/download/) +- Overall Wasm should be faster than luajit on average, without trying any fancy optimization techniques, for a wider range of luajit vs wasm comparisons one can check [here](https://programming-language-benchmarks.vercel.app/wasm-vs-lua) -**NOTE: Current test only runs on Windows 10. That's the machine I have.** +**NOTE: Current perf test results shown are from a Windows 10 PC. That's the machine I have.** ## READING: diff --git a/default_cfg/perf.lua b/default_cfg/perf.lua index 2543638..0e25795 100644 --- a/default_cfg/perf.lua +++ b/default_cfg/perf.lua @@ -25,3 +25,51 @@ end print("Lua For Loop takes: "..lua_for_loop().."s\n"); print("Wasm Time From Nvim For Loop takes: "..wasm_for_loop().."s\n"); + + +function lua_primes(size) + local factos = {} + local primes = {2,} + + local i = 3; + while i<= size do + local is_prime = true + -- check if is a factor + for _, val in pairs(factos) do + if val == i then + is_prime = false + break + end + end + + if is_prime == true then + table.insert(primes,i) + --fill factos + local j =3 + while j*i < size do + table.insert(factos,j*i) + j = j+2 + end + end + i=i+2 + end + + -- print("LUA PRIMES: "..#primes) +end + +function test_prime() + print(" \n") + print("Starting to get number of primes between 0-1000") + print("Over a period of 5 seconds in both wasm and lua...") + local times_lua = 0 + local start = vim.fn.reltime(); + while(vim.fn.reltimefloat(vim.fn.reltime(start)) < 5) do + lua_primes(10000) + times_lua = times_lua + 1 + end + print("-LUA has done it "..times_lua.." times") + local times_wasm = wasm.perf.wasm_primes(10000) + print("-WASM has done it "..times_wasm.." times\n") +end + +test_prime() diff --git a/imgs/1690628636000.png b/imgs/1690628636000.png deleted file mode 100644 index 46968a9..0000000 Binary files a/imgs/1690628636000.png and /dev/null differ diff --git a/imgs/perf.png b/imgs/perf.png new file mode 100644 index 0000000..56befb0 Binary files /dev/null and b/imgs/perf.png differ diff --git a/wasm/perf.zig b/wasm/perf.zig index b763679..8956cee 100644 --- a/wasm/perf.zig +++ b/wasm/perf.zig @@ -5,7 +5,8 @@ const json = std.json; extern "host" fn get_id() u32; extern "host" fn set_value(id: u32, loc: u32, size: u32) void; extern "host" fn get_addr(ptr: *u8) u32; -extern "host" fn nvim_create_augroup(id: u32) i64; +extern "host" fn get_value_size(id: u32) u32; +extern "host" fn get_value_addr(id: u32) [*]u8; var aloc: std.mem.Allocator = std.heap.page_allocator; @@ -32,6 +33,7 @@ export fn functionality() u32 { var funcs = ArrayList(Functionality).init(aloc); defer funcs.deinit(); funcs.append(CreateFunctionality("for_loop", "void", "void")) catch unreachable; + funcs.append(CreateFunctionality("wasm_primes", "u32", "u32")) catch unreachable; var jsoned = ArrayList(u8).init(aloc); std.json.stringify(funcs.items, .{}, jsoned.writer()) catch undefined; @@ -55,3 +57,58 @@ export fn for_loop() void { var writer = std.io.getStdOut().writer(); writer.print("Wasm Time from inside function For Loop takes: {d}\n", .{diff}) catch undefined; } + +fn get_primes(size: u32) void { + var factos = ArrayList(u32).init(aloc); + defer factos.deinit(); + var primes = ArrayList(u32).init(aloc); + primes.append(2) catch unreachable; + defer primes.deinit(); + + var i: u32 = 3; + while (i < size) { + var is_prime = true; + // check if i is a factor + for (factos.items) |f| { + if (f == i) { + is_prime = false; + break; + } + } + + if (is_prime == true) { + primes.append(i) catch unreachable; + var j: u32 = 3; + while (j * i < size) { + factos.append(j * i) catch unreachable; + j += 2; + } + } + i += 2; + } + + // std.io.getStdOut().writer().print("WASM PRIMES: {d}\n", .{primes.items.len}) catch unreachable; +} + +export fn wasm_primes(id: u32) u32 { + const in_size = get_value_size(id); + var inArray = ArrayList(u8).init(aloc); + defer inArray.deinit(); + inArray.capacity = in_size; + inArray.items = get_value_addr(id)[0..in_size]; + + const size = json.parseFromSlice(u32, aloc, inArray.items, .{}) catch unreachable; + + var times: u32 = 0; + const start = std.time.milliTimestamp(); + while (std.time.milliTimestamp() - start < 5000) { + get_primes(size.value); + times += 1; + } + + const return_id = get_id(); + var results = ArrayList(u8).init(aloc); + json.stringify(times, .{}, results.writer()) catch unreachable; + set_value(return_id, get_addr(&results.items[0]), results.items.len); + return return_id; +}