Open Manual

Performance

Performance work answers two different questions:

1. how expensive the compiler/toolchain path is;

2. how fast the produced program runs.

Do not mix those numbers unless compile time is part of the workload.

Command Matrix

CommandMeasuresUse
ny file.nyCompile plus JIT/runtime path.Edit loop and behavior checks.
ny -run file.nyTemporary native executable plus run.Quick AOT smoke test.
ny -o app file.nyNative compilation only.Stable runtime artifact.
ny -O3 --profile=peak -o app file.nyPeak native compilation only.Upper-bound runtime check.
./appRuntime only.Program comparisons without compile noise.
ny -time file.nyCompiler phases plus run time.Find parse/import/codegen/cache regressions.
ny -prof file.nyTiming and compiler/runtime stats.Broader toolchain profile.
ny perfMaintained perf checks.Regression pass.

Native -o defaults to -O2. JIT and REPL default to -O0 for edit latency.

Use --profile=peak only when compile time can be traded for native speed.

Compile Once, Run Many

ny -O3 --profile=peak -g -o build/cache/bench/app bench.ny
build/cache/bench/app
build/cache/bench/app
build/cache/bench/app

-g keeps profiler symbols. Drop -g and add -strip only for distribution

size checks.

Read -time

AreaMeaning
read/import/stdlibSource size, import graph, stdlib cache.
parse/type/codegenCompiler work from syntax, types, generated IR.
native/JIT compileLLVM/backend cost and cache behavior.
runProgram runtime after execution starts.
totalWhole edit-loop command cost.

If only total moved, the regression is not isolated. If run moves in a

reused binary, the program behavior changed.

Native Profiling

Linux perf flow:

ny -O3 --profile=peak -g -o build/cache/bench/app bench.ny
perf record -F 997 -g -o build/cache/bench/perf.data -- build/cache/bench/app
perf report -i build/cache/bench/perf.data

Compiler artifacts:

ny -O3 -time -dump-stats bench.ny
ny -O3 --emit-ir=build/cache/bench/app.ll -emit-only bench.ny
ny -O3 --emit-asm=build/cache/bench/app.s -emit-only bench.ny

Use IR and assembly to confirm a hypothesis, not to start one.

Cache Discipline

ny --clean-cache
ny -time bench.ny
ny -time bench.ny

Record cold/warm cache state. Public notes should prefer CLI flags; mention

environment variables only when they are part of the experiment.

Common knobs:

SettingUse
NYTRIX_JIT_CACHE_FORMAT=irbcSelect JIT cache artifact format.
NYTRIX_LAZY_STDLIB_CODEGEN=1Demand-emit imported stdlib bodies.
NYTRIX_RUNTIME_OPT=3 or speedSpeed settings for runtime support.
NYTRIX_RUNTIME_NATIVE=1Native CPU tuning for speed-profile runtime objects.

Benchmark Shape

use std.core

def data = [1, 2, 3, 4]

fn work(list<int> xs) int {
   mut int total = 0
   for x in xs { total += int(x) }
   total
}

assert(work(data) == 10, "bench result")

Benchmarks separate setup from timed work and assert the result.

Optimization Order

1. Pin the command and input.

2. Compile a native binary and confirm the slow path still exists.

3. Profile or use -time to separate compiler cost from runtime cost.

4. Change the narrow measured hot path.

5. Run focused tests and rerun the same benchmark.

6. Keep dynamic fallback behavior when the public API accepts dynamic values.

Common useful changes: typed internal helpers, direct indexed access after a

type contract, fewer repeated get calls in loops, and precomputed

comptime tables.

Report

command: ny -O3 --profile=peak -g -o build/cache/bench/app bench.ny
run: build/cache/bench/app
input: rows=1024 cols=2048
cache: warm std cache, native binary reused
before: 185ms pipeline, 111ms solver
after: 25ms pipeline, 25ms solver
validation: ny test --pattern factorization

Related