Performance profile: where it is fast, where it is even

The performance meaning of the zero-fork three-tier model (see the execution model) fits in one sentence: wherever bash must create a process and niubash does not, niubash is faster; wherever both must create a process, the two are even. Every number on this page is a same-machine measurement (method at the end), benchmark artifacts ship with the package, and each can be checked on the benchmarks page.

Where zero fork pays off

Command substitution, subshells, background jobs — the constructs bash forks for on every use — are ShellState::clone plus an fd-table copy in niubash, never process creation. Same-session measurements of 2026-10-18 (750 iterations per workload, interleaved rotation, warm-up discarded, min-of-3, in ms):

WorkloadrubashGit BashWSL (reference)
Background subshell ( ) ×75016432192123
Background wait sleep & wait ×75016961967154
Pure spawn ×75016962119158
Builtin loop ×75032403
Foreground external command ×7503741857
中文原文 · Chinese original

对 Git Bash 是 8 个工作负载全部占优;WSL 列仅作参考——Linux 内核 fork 让它的 后台作业天然占优,但它的前台外部命令要跨 OS 文件边界(857 ms)、冷启动 202–278 ms,且带走一整套虚拟机。迁移评估时,按你的脚本里「fork 密集」还是 「外部命令密集」对号入座。

External processes: parity is a design fact

niubash does not claim faster external processes — they should not be faster. Single-spawn cost: rubash 1.183 ms vs GNU 1.121 ms — even, because both land on the same Win32 CreateProcess floor. The entire zero-fork payoff comes from the "no process" paths, not from making "necessary processes" faster. That is also the essential difference from the MSYS layer: in Git Bash every process additionally pays the fork-emulation tax.

Hot paths inside the engine: gaps are engineered away

中文原文 · Chinese original

语言层的重负载也被逐个啃掉,而不是留着当「已知慢」:nvm.sh 这类重词法脚本的 解析差距从 720 倍压到 8 倍(重词法字节量 −40%);数组元素写入从 O(n²) 改为 O(1) 追加——K=5000 时关联数组单次写快 45 倍、索引数组覆盖写快 177 倍; 多行粘贴的自动误执行从 186 次降到 0(257 行载荷从 300 秒超时降到 4.6 秒)。 这些不是理论优化:每项都有 PR 号与基准脚本可复现,夜间性能门盯住它们不回潮。

Summary in English: the heavy lexer workloads were closed one by one rather than left as "known slow" — the nvm.sh-class parsing gap shrank from 720× to 8× (heavy-lexer bytes −40%); array element writes went from O(n²) to O(1) append (at K=5000, associative-array single writes 45× faster, indexed-array overwrite writes 177×); multiline-paste auto-execution misfires dropped from 186 to 0 (a 257-line payload from a 300 s timeout to 4.6 s). None of these are theoretical: each has a PR number and a reproducible benchmark script, and a nightly performance gate keeps them from regressing.

Startup numbers

Metricniubash familyContrast
git startup (git --version)~14 ms (niu-git: MSVC + schannel, no MSYS)Git Bash 45–103 ms
One-shot execution niu -c true26.3 msGit Bash 71 ms
Shell startup (5 measured runs)rubash 27–48 msGit Bash 60–93 ms · WSL 202–278 ms
Prompt git segmentreads .git/HEAD, ≤29 msGit spawned per prompt: 113–362 ms
WinuxCmd tool layer3.79 MB carrying 176 commands / 1,924 options, ~19 ms cold start—
Install sizeniu ≈16 MB · zero DLLsGit Bash 440 MB + 20 MB msys-2.0.dll
中文原文 · Chinese original

提示符一项值得展开:Git Bash 兼容主题不 spawn git 子进程,而是直接读 .git/HEAD 文件(微秒级),把「每敲一条命令付一次 git 启动」变成 「不付」。一次性执行数字对 agent 与 CI 尤其重要——niu -c 的 冷启动地板从 105.6 ms 一路压到 26.3 ms(一次性快路径六连 PR)。

How to read these numbers

Environment: Intel Xeon w5-3435 · Windows 10 19045 · same-machine WSL2 Ubuntu (GNU Bash 5.3.0 contrast) · Git Bash 5.3.0. Method: interleaved rotation (rubash → Git Bash → WSL), one warm-up round discarded, min-of-3, identical timing for all three. Numbers move with versions; the methodology does not: nothing unmeasured gets written, wins and losses both shown. The repo also runs a nightly performance gate (per-asset timing trends; hard-fails over budget) against regressions.

Full tables, raw TSVs and the runner scripts: /en/benchmarks/.