Skip to content

a zig lane, the C++ lane as a C++ program per test, a startup table, and fresh macOS and Linux records - #14

Merged
borisbat merged 10 commits into
mainfrom
bbatkin/zig-lane
Sep 8, 2026
Merged

a zig lane, the C++ lane as a C++ program per test, a startup table, and fresh macOS and Linux records#14
borisbat merged 10 commits into
mainfrom
bbatkin/zig-lane

Conversation

@borisbat

@borisbat borisbat commented Sep 7, 2026

Copy link
Copy Markdown
Owner

Behavior change: every test is pure das now, the C++ lane is a C++ program per test under tests/cpp/, test_profile.cpp is the interop module only (AddOne, ParseFloat), a capture writes a third section, Startup, and the records are a fresh macOS capture (M1 Max) and a new Linux one (zen4); the old Windows record is removed.

Why. The suite's native floor was C++ alone, measured through a das loop and a binding call per iteration; a startup report compared us against zig; and nothing measured what a program in each lane pays before its first line.

What changes.

  • tests/zig/<test>.zig for all sixteen tests plus profile.zig, the shared budget loop; built on demand with zig build-exe -O ReleaseFast into tests/zig/.zig-out; ZIG after C++ on the AOT or JIT board.
  • tests/cpp/<test>.cpp for all sixteen tests plus profile.h, the same budget loop; built at the configuration's default optimization (Release -O3, MSVC /O2, what the kernels had as a module) and staged into the runtime root beside the other lanes' hosts; run_files spawns the staged program like every other lane. native links addOne.c as its own object. The tests no longer require testProfile (interop host calls keeps it - its das kernel calls AddOne), and the module shrinks from 1258 lines to the two interop callees, each bound NTTP-inline and member.
  • --startup, and every --json capture: hello world in every language on the boards, launched the way that lane's kernels are launched - the das interpreter, the JIT with a warm DLL cache, a das exe built into a temp directory, the C++ hello, the zig hello, Luau with and without --codegen, Lua, LuaJIT with and without the JIT, Quirrel, QuickJS, Mono under both engines from an mcs build, .NET from a dotnet build - ten launches after a warm one, the median and the samples, and the size of the artifact where the lane runs one it built.
  • The .NET builds run with UseSharedCompilation=false: a build left the Roslyn compiler server resident across the lanes measured after it.
  • profile_root reads the cwd tree the way config.das does: get_this_module_dir() for a relative main.das is the binary's directory, and the runner had been reading the SDK's staged copy of the tests.
  • The README generator renders the Startup table one runtime per row and says what a row is; Zig joins the AOT or JIT columns and the runtime line.
  • Records: profile_results_darwin.json recaptured on the M1 Max; profile_results_linux.json is new, from zen4 (Ryzen 7 PRO 8700GE, Debian 12, clang-19 SDK from master); profile_results_windows.json, the Threadripper 3990X capture that predates all of this, is removed. The README carries macOS and Linux.

Observable behavior.

  • Both boards carry a Zig column, the C++ column is the standalone programs, and a Startup table follows the two boards; the Windows section is gone until a Windows capture lands.
  • M1 Max: das JIT geomean 0.75 of C++ and 0.93 of zig over the sixteen rows, das AOT 0.93 of C++, zig 0.81 of C++; das AOT or JIT fastest on nine rows of sixteen. Hello world: das interpreter 46 ms, das JIT 332 ms, das exe 12 ms (50 KB), C++ 5.7 ms, zig 6.1 ms, the Lua family, Quirrel and QuickJS 6 to 7.6 ms, Mono 21 to 25 ms, .NET 28 ms.
  • zen4: das JIT geomean 0.72 of C++ and 1.02 of zig, das AOT 0.76 of C++, zig 0.71 of C++ (clang-19 at -O3 against zig's LLVM 22); das AOT or JIT fastest on eight rows. Hello world: das interpreter 61 ms, das JIT 423 ms, das exe 15 ms, C++ 6.1 ms, zig 6.0 ms, the Lua family and QuickJS 6 to 7 ms, Mono 16 to 18 ms, .NET 24 ms.
  • The queen row reads two speeds on the M1 in every native lane, process by process (das JIT 28 to 56 us, C++ 38 to 62, zig 56 to 60), so its JIT, C++ and zig cells carry a 20 to 27 percent spread where the rest of the board sits at 0 to 2; the same programs on an M5 Max and on zen4 read one speed. A 64-byte aligned board does not change it, nor does the QoS class.

Where to look. collect_startup in main.das; run_files in config.das for the C++ and zig spawns; tests/cpp/profile.h and tests/zig/profile.zig - every kernel takes its size through a volatile read and drops its result into a volatile sink, or the optimizer deletes every call but the last and the budget loop spins on nothing (five of the C++ programs and four of the zig ones did exactly that before the sink).

Validation, claims, ledger

Validation

  • Every zig and C++ program standalone and through the runner on an M5 Max, the M1 and zen4; each box's record is the second of two full captures there - the first M1 capture ran with Parsec's daemon up and carried one 6x sample on LuaJIT's tree row; the first zen4 capture carried one 1.7x sample in five in cells spread over every lane, the Roslyn build server resident across the run; the second captures are clean on every row but the M1's queen (above).
  • On zen4 the das AOT lane's fifth in-process sample reads 1.7x on three rows (queen, interop host calls, fibonacci recursive) in both captures, the same three rows and the same factor; the medians are the fast four. Not chased.
  • The C++ program column against the das-hosted module on the same M1: within a few percent on every row (sha256 156 vs 156 us, tree 2.51 vs 2.52 ms, fibonacci loop 2.02 vs 2.02 ms) except mandelbrot, 0.36 vs 0.57 ms - a scalar sqrtf against the module's vector length call.
  • The first startup capture read 107 ms on every lane: a timed popen_argv polls the child on a 100 ms grain. The wait is unbounded now.
  • Launches are timed from a daslang parent through popen_argv; the spawn adds about 2 ms to every lane alike.
  • The SDK install was missing include/daScript/builtin/ast_gen.inc, which the shipped aot_builtin_ast.h includes; zen4's AOT companion did not build until the file was copied in by hand. Fixed in the SDK installs the generated binding tables the shipped aot_builtin_ast.h includes GaijinEntertainment/daScript#3963.

Claims - stated, not tested

  • Windows: zig build-exe with the addOne.c object and -lc, the C++ programs and their staging, the startup capture's -jit-no-cache JIT lane, the PATH prefix for the das exe, and the mcs / dotnet build steps were not run on a Windows host.

Not done

  • A Windows capture, when a Windows box frees up.

…leaseFast on demand into tests/zig/.zig-out and rebuilt when the test or the shared harness is newer than the artifact; profile.zig is the same budget loop as bench() and profile.lua, printing the same "category", seconds, runs line on stdout, and every kernel takes its size through a volatile read so the optimizer makes a real call per repetition (with a constant argument LLVM hoisted the pure kernel out of the loop, and the budget loop ran a billion empty repetitions); interop host calls compiles addOne.c beside the zig test as its own object with LTO off, one C-ABI call per iteration like the other lanes' hosts; ZIG joins the AOT or JIT board after C++ in the JSON, the README generator's column and runtime line, and `zig version` joins the environment summary; the README opening names Zig
…st is now pure das (the one that calls the C++ module, interop host calls, keeps its require), and the C++ kernels run from tests/cpp/<name>.das, the one program per test that requires testProfile, spawned by run_files as the C++ lane like every other runtime's host; nothing is no_jit any more, which a standalone exe refuses in strict mode (the JIT lane's loop is jitted now, queen moved 5%, tree 1%); main.das --startup (and every --json capture) launches hello world (tests/startup/hello.das, tests/zig/hello.zig) and every test under DASPROFILE_STARTUP=1 - bench() and profile.zig run the kernel once and print nothing, run_files spawns nothing - as a script, under the JIT, as a standalone exe built into a temp directory, and as its zig twin, ten launches after one warm one, the median and the samples per lane and the artifact's size where the lane is an executable, into a Startup section keyed like the boards; the wait is unbounded because a timed popen_argv polls on a 100 ms grain, which is what the first capture measured; profile_root reads the cwd tree like config.das does - get_this_module_dir() for a relative main.das is the binary's directory, and the runner had been reading the SDK's staged copy of the tests; the README generator renders the Startup table with sizes and says what a row is
@borisbat borisbat changed the title a zig lane: every test's zig twin under tests/zig, built on demand, on the AOT or JIT board after C++ a zig lane, the C++ lane as its own program, and the startup table Sep 7, 2026
…age on the boards, launched the way that lane's kernels are launched (the das interpreter, the JIT with a warm DLL cache, a das exe built into a temp directory, the C++ hello the CMake builds and stages, the zig hello, luau with and without codegen, lua, luajit with and without the JIT, quirrel, quickjs, mono under both engines from an mcs build, .NET from a dotnet build), ten launches after a warm one, the median and the samples, and the size of the artifact where the lane runs one it built; the per-test startup rows, the startup mode in bench() and profile.zig and the exe build per test are gone, and the tests' no_jit annotations are back as they were; the README generator renders the table one runtime per row and the preamble says what a row is
@borisbat borisbat changed the title a zig lane, the C++ lane as its own program, and the startup table a zig lane, the C++ lane as its own program, and a startup table - hello world in every language on the boards Sep 7, 2026
…ofile.h, the same budget loop as bench() and profile.lua printing the same line, built at -O2 by the CMake and staged into the runtime root beside the other lanes' hosts, and run_files spawns the staged program like every other runtime's host, so the C++ column no longer carries a das loop and a binding call per iteration; hello.cpp is the startup row's program; native links addOne.c as its own object, one C-ABI call per iteration; every kernel takes its size through a volatile read and drops its result into a volatile sink, or the optimizer deletes every call but the last and the budget loop spins on nothing (fib_loop, fib_recursive, primes, mandelbrot and exp did exactly that at -O2); the das-hosted tests/cpp/*.das go, and test_profile.cpp shrinks from 1258 lines to the interop module - AddOne and ParseFloat, each bound NTTP-inline and member for tests/native.das and tests/_abtest.das - the ES pass tables, managed vectors, particles, try/catch and every kernel copy nothing referenced any more are gone; a one-sample capture reads the program column within a few percent of the das-hosted one on every row but mandelbrot, where the scalar sqrt is 40% faster than the module's vector length call
@borisbat borisbat changed the title a zig lane, the C++ lane as its own program, and a startup table - hello world in every language on the boards a zig lane, the C++ lane as a C++ program per test, and a startup table - hello world in every language on the boards Sep 7, 2026
borisbat and others added 5 commits September 7, 2026 14:38
…elease -O3 on clang and gcc, /O2 on MSVC, which is what the kernels had as a module; queen's helpers keep external linkage as the module's did - on an M1 the -O2 static build read 80 us where the module read 40 and this shape reads 35
… SDK - every lane including the C++ programs, the zig lane and the startup table, five samples per cell, ten launches per startup lane, Parsec off; queen reads two speeds on this box in every native lane (28 to 38 us and 55 to 62 us, process by process), so its JIT, C++ and zig cells carry a 20 to 27 percent spread where the rest of the board sits at 0 to 2
…e Roslyn compiler server resident across the lanes measured after it, and a zen4 capture read one sample in five 1.7x slow in cells spread over every lane
… 12, clang-19 SDK from master) - every lane including the C++ programs, the zig lane and the startup table, five samples per cell, ten launches per startup lane, the box idle and the .NET builds non-shared; the README gains a Linux section between macOS and Windows
…dates the C++ programs, the zig lane and the startup table, and the box that would recapture it is busy; the README carries macOS and Linux until a Windows capture lands
@borisbat borisbat changed the title a zig lane, the C++ lane as a C++ program per test, and a startup table - hello world in every language on the boards a zig lane, the C++ lane as a C++ program per test, a startup table, and fresh macOS and Linux records Sep 8, 2026
@borisbat
borisbat merged commit dd3222c into main Sep 8, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant