ash ${str/find/repl} performance

Alin Mr almr.oss at outlook.com
Mon Jul 19 19:21:06 UTC 2021


It seems that bash-like pattern substitution is surprisingly slow. Tested with busybox 1_33_stable, 1_32_stable, master, Debian/buster busybox-static (all having the applet-bias features configured, i.e. FEATURE_SH_STANDALONE, FEATURE_PREFER_APPLETS, STATIC)

== ${} vs built-in sed

x=$(cat /etc/passwd /etc/passwd /etc/passwd | head -30) \
  hyperfine -s basic -w 2 -r 10 -S /tmp/bbox-1.33/sh \
  'for i in $(seq 1 20); do echo "${x//:/|}"; done' \
  'for i in $(seq 1 50); do sed -e "s/:/|/g"; done'

Benchmark #1: for i in $(seq 1 20); do echo "${x//:/|}"; done

  Time (mean ± σ):     829.9 ms ±  12.8 ms    [User: 829.6 ms, System: 0.4 ms]
  Range (min … max):   820.9 ms … 863.6 ms    10 runs
 
Benchmark #2: for i in $(seq 1 50); do sed -e "s/:/|/g"; done
  Time (mean ± σ):      40.6 ms ±   0.3 ms    [User: 29.8 ms, System: 12.0 ms]
  Range (min … max):    39.9 ms …  40.9 ms    10 runs
 
Summary
  'for i in $(seq 1 50); do sed -e "s/:/|/g"; done' ran
   20.46 ± 0.35 times faster than 'for i in $(seq 1 20); do echo "${x//:/|}"; done'

== O(n^?)

hyperfine -L n 10,15,20,30 -S /tmp/bbox-1.33/sh -w 2 -r 10 -s basic 'x=$(cat /etc/passwd /etc/passwd /etc/passwd | head -{n}); for i in $(seq 1 20); do echo "${x//:/|}"; done'
Benchmark #1: x=$(cat /etc/passwd /etc/passwd /etc/passwd | head -10); for i in $(seq 1 20); do echo "${x//:/|}"; done
  Time (mean ± σ):      47.8 ms ±   2.8 ms    [User: 47.6 ms, System: 0.9 ms]
  Range (min … max):    44.6 ms …  50.4 ms    10 runs
 
Benchmark #2: x=$(cat /etc/passwd /etc/passwd /etc/passwd | head -15); for i in $(seq 1 20); do echo "${x//:/|}"; done
  Time (mean ± σ):     125.0 ms ±   4.1 ms    [User: 125.4 ms, System: 0.2 ms]
  Range (min … max):   121.4 ms … 133.1 ms    10 runs
 
Benchmark #3: x=$(cat /etc/passwd /etc/passwd /etc/passwd | head -20); for i in $(seq 1 20); do echo "${x//:/|}"; done
  Time (mean ± σ):     302.5 ms ±   5.3 ms    [User: 302.2 ms, System: 0.9 ms]
  Range (min … max):   296.0 ms … 313.3 ms    10 runs
 
Benchmark #4: x=$(cat /etc/passwd /etc/passwd /etc/passwd | head -30); for i in $(seq 1 20); do echo "${x//:/|}"; done
  Time (mean ± σ):     833.6 ms ±   7.9 ms    [User: 833.3 ms, System: 0.9 ms]
  Range (min … max):   821.0 ms … 843.7 ms    10 runs
 
Summary
  'x=$(cat /etc/passwd /etc/passwd /etc/passwd | head -10); for i in $(seq 1 20); do echo "${x//:/|}"; done' ran
    2.61 ± 0.17 times faster than 'x=$(cat /etc/passwd /etc/passwd /etc/passwd | head -15); for i in $(seq 1 20); do echo "${x//:/|}"; done'
    6.32 ± 0.38 times faster than 'x=$(cat /etc/passwd /etc/passwd /etc/passwd | head -20); for i in $(seq 1 20); do echo "${x//:/|}"; done'
   17.43 ± 1.02 times faster than 'x=$(cat /etc/passwd /etc/passwd /etc/passwd | head -30); for i in $(seq 1 20); do echo "${x//:/|}"; done'



More information about the busybox mailing list