Timing the compiler tests with SKC_TIME_PHASES
Now that SKC_TIME_PHASES (#1291/#1292) is in main, I profiled the compiler test suite by compiling every test file with it set. The headline: SKC_TIME_PHASES accounts for only ~10% of a test compile — the other ~90% is a fixed, uninstrumented per-invocation cost (loading the stdlib sklib).
Method
Each valid test compiled exactly as the harness does — skc -O0 --no-inline --export-function-as <Module>.main=skip_main -o <bin> <file>.sk — with SKC_TIME_PHASES=1, capturing the ##TIME## lines. All 896/896 valid tests compiled successfully (parallel run, coverage check). Per-compile figures below are from a single-threaded run (no contention) over a stratified 12-file sample; every file landed within 4831–4941 ms regardless of its content, so the numbers are highly stable. Measured on this dev box (20 cores) with the stage1 release skc; absolute ms will differ on CI hardware, but the proportions won't.
Result: ~90% of a compile is untimed
|
per compile |
Total skc wall |
~4870 ms |
Sum of all SKC_TIME_PHASES phases |
~493 ms (~10%) |
| Untimed |
~4377 ms (~90%) |
The instrumented phases (the ~10% we can currently see), single-threaded means:
| phase |
ms |
% of instrumented |
native/link (clang++) |
184 |
37% |
frontend+ir (createIR) |
112 |
23% |
native/compile |
97 |
20% |
native/write_asm_files |
50 |
10% |
native/create_asm_graph |
48 |
10% |
native/merge_asm_graph |
0.7 |
— |
native/create_asm_symbols |
0.5 |
— |
outer/makeOuter |
0.01 |
— |
What the untimed ~4.4s is
It's a fixed cost paid on every skc invocation, independent of the input — an empty fun main(): void { void } compiles in the same ~4.87s. strace pins it down:
- skc opens
libstd.sklib (2×) and zero prelude .sk sources — so it loads the precompiled stdlib, it does not recompile the prelude.
strace -c shows only ~0.18s in syscalls (mostly wait4 on the clang++ link). The ~4.4s is CPU-bound userspace work — deserializing/materializing the stdlib into the compiler's SKStore context, plus parse/name/type of the input.
Note this also means the frontend+ir label (from #1292) overstates what it captures: it wraps IR generation (~112 ms); the real frontend/stdlib cost happens before it and is untimed.
Scale across the suite
At ~4.87s/compile, single-threaded subprocess mode:
- 896 valid tests ≈ 73 min; with the 823 invalid tests, 1719 compiles ≈ 140 min.
- Of that, the fixed stdlib-load overhead (~4.4s × 1719) is ≈ 126 min of redundant work — the same stdlib materialized from scratch 1719 times.
This is exactly the cost the unified @exptest harness (#1289) removes by compiling all tests into one binary (the stdlib is loaded once). It's also why the old per-test subprocess path was slow.
Takeaways
SKC_TIME_PHASES is currently blind to ~90% of compile time. The stdlib-load/materialization and the parse/name/type frontend aren't wrapped in runCompilerPhase. Extending the instrumentation to cover them (and splitting frontend+ir into real frontend vs IR-gen) would make the profiler actually point at where time goes.
- sklib load/materialization (~4.4s) is the single highest-leverage compiler-perf target. It dominates every compile and every non-unified test run. Worth a dedicated look at why deserializing a 1.6 MB sklib costs seconds of CPU.
- Within the codegen/link phases that are timed,
native/link (clang++) and native/compile are the largest — but they're a rounding error next to the stdlib load.
Raw per-file ##TIME## data available if useful.
🤖 Generated with Claude Code
Timing the compiler tests with
SKC_TIME_PHASESNow that
SKC_TIME_PHASES(#1291/#1292) is inmain, I profiled the compiler test suite by compiling every test file with it set. The headline:SKC_TIME_PHASESaccounts for only ~10% of a test compile — the other ~90% is a fixed, uninstrumented per-invocation cost (loading the stdlib sklib).Method
Each valid test compiled exactly as the harness does —
skc -O0 --no-inline --export-function-as <Module>.main=skip_main -o <bin> <file>.sk— withSKC_TIME_PHASES=1, capturing the##TIME##lines. All 896/896 valid tests compiled successfully (parallel run, coverage check). Per-compile figures below are from a single-threaded run (no contention) over a stratified 12-file sample; every file landed within 4831–4941 ms regardless of its content, so the numbers are highly stable. Measured on this dev box (20 cores) with the stage1 releaseskc; absolute ms will differ on CI hardware, but the proportions won't.Result: ~90% of a compile is untimed
skcwallSKC_TIME_PHASESphasesThe instrumented phases (the ~10% we can currently see), single-threaded means:
native/link(clang++)frontend+ir(createIR)native/compilenative/write_asm_filesnative/create_asm_graphnative/merge_asm_graphnative/create_asm_symbolsouter/makeOuterWhat the untimed ~4.4s is
It's a fixed cost paid on every
skcinvocation, independent of the input — an emptyfun main(): void { void }compiles in the same ~4.87s.stracepins it down:libstd.sklib(2×) and zero prelude.sksources — so it loads the precompiled stdlib, it does not recompile the prelude.strace -cshows only ~0.18s in syscalls (mostlywait4on theclang++link). The ~4.4s is CPU-bound userspace work — deserializing/materializing the stdlib into the compiler'sSKStorecontext, plus parse/name/type of the input.Note this also means the
frontend+irlabel (from #1292) overstates what it captures: it wraps IR generation (~112 ms); the real frontend/stdlib cost happens before it and is untimed.Scale across the suite
At ~4.87s/compile, single-threaded subprocess mode:
This is exactly the cost the unified
@exptestharness (#1289) removes by compiling all tests into one binary (the stdlib is loaded once). It's also why the old per-test subprocess path was slow.Takeaways
SKC_TIME_PHASESis currently blind to ~90% of compile time. The stdlib-load/materialization and the parse/name/type frontend aren't wrapped inrunCompilerPhase. Extending the instrumentation to cover them (and splittingfrontend+irinto real frontend vs IR-gen) would make the profiler actually point at where time goes.native/link(clang++) andnative/compileare the largest — but they're a rounding error next to the stdlib load.Raw per-file
##TIME##data available if useful.🤖 Generated with Claude Code