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):
| Workload | rubash | Git Bash | WSL (reference) |
|---|---|---|---|
Background subshell ( ) ×750 | 1643 | 2192 | 123 |
Background wait sleep & wait ×750 | 1696 | 1967 | 154 |
| Pure spawn ×750 | 1696 | 2119 | 158 |
| Builtin loop ×750 | 32 | 40 | 3 |
| Foreground external command ×750 | 37 | 41 | 857 |
中文原文 · 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
| Metric | niubash family | Contrast |
|---|---|---|
git startup (git --version) | ~14 ms (niu-git: MSVC + schannel, no MSYS) | Git Bash 45–103 ms |
One-shot execution niu -c true | 26.3 ms | Git Bash 71 ms |
| Shell startup (5 measured runs) | rubash 27–48 ms | Git Bash 60–93 ms · WSL 202–278 ms |
| Prompt git segment | reads .git/HEAD, ≤29 ms | Git spawned per prompt: 113–362 ms |
| WinuxCmd tool layer | 3.79 MB carrying 176 commands / 1,924 options, ~19 ms cold start | — |
| Install size | niu ≈16 MB · zero DLLs | Git 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/.