udem-dlteam / pnut

🥜 A Self-Compiling C Transpiler Targeting Human-Readable POSIX Shell
https://pnut.sh
BSD 2-Clause "Simplified" License
425 stars 14 forks source link

Optimize line splitting for longer lines #51

Closed laurenthuberdeau closed 5 months ago

laurenthuberdeau commented 5 months ago

Context

Reading long lines either via stdin or file input is painfully slow. This is because the algorithm we use to extract individual characters from a shell string is quadratic in length of the line. This problem wasn't apparent when bootstrapping pnut, but it becomes an obstacle when writing utilities such as cat.

While we can't workaround the limitations of the shell and escape the quadratic complexity of our algorithm, we can extract more characters at once to reduce the constant C in O(C*n^2). We use smaller buffers of length 32, 64 and 128 to reduce the number of operations taking linear time over long strings.

Benchmarks

Results from ./shell-benchmarks/bench-cat.sh which reads a file and output it to stdout, like cat:

Length 1000
      default - fast
ksh   0m0.35s   0m0.04s
dash  0m0.04s   0m0.03s
bash  0m0.25s   0m0.07s
zsh   0m0.09s   0m0.06s

Length 5000
      default - fast
ksh   0m36.28s  0m0.68s
dash  0m0.56s   0m0.11s
bash  0m21.23s  0m0.56s
zsh   0m1.18s   0m0.42s

Length 10000
      default - fast
ksh   >1m       0m4.36s
dash  0m3.24s   0m0.27s
bash  2m44.53s  0m2.76s
zsh   0m4.12s   0m1.12s