# Some rough benchmarks

To compare different approaches to a problem with regards to performance, here's some rough benchmarks which may be system-dependent. Feel free to run each test yourself to see how your system fares.

Results are always sorted with the winners on top. All tests were repeated multiple times to make sure deviations did not exceed acceptable levels or cross result boundaries.

The different approaches don't all produce identical results. Side effects are noted on the side for your information.

## Math

 0m1.153s j=0; time for i in {1..100000}; do ((j++)); done An empty value is considered 0. 0m1.381s j=0; time for i in {1..100000}; do j=\$((j+1)); done An empty value is considered 0. 0m1.498s j=0; time for i in {1..100000}; do let j++; done An empty value is considered 0. 0m1.726s j=0; time for i in {1..100000}; do j=\$((\$j+1)); done An empty value may cause bugs. In this case, leads to the valid ((+1)). 5m8.448s j=0; time for i in {1..100000}; do j=\$(expr "\$j" + 1); done An empty value will cause errors.

## Quoting

 0m1.510s printf -v i '%s ' {1..1000000}; time { : "\$i"; } 0m2.828s printf -v i '%s ' {1..1000000}; time { : \$i; } Words in i undergo word splitting and pathname expansion.

## Expanding Multiple Arguments

 0m2.828s printf -v i '%s ' {1..1000000}; time { : \$i; } Arguments can only be words, they also undergo (likely unwanted) pathname expansion. 0m6.885s i=( {1..1000000} ); time { : "\${i[@]}"; }

## Testing

 0m1.099s time for i in {1..100000}; do [[ -d . ]]; done A keyword. Special (convenient) parsing rules apply. 0m2.110s time for i in {1..100000}; do [ -d . ]; done A built-in. 3m47.509s time for i in {1..100000}; do /bin/test -d .; done An external process.

## String Operations

 0m0.149s path=/foo/bar; time for i in {1..10000}; do : "\${path##*/}"; done 0m19.284s path=/foo/bar; time for i in {1..10000}; do basename "\$path" >/dev/null; done An external process. 0m21.289s path=/foo/bar; time for i in {1..10000}; do expr "\$path" : '.*/\(.*\)' >/dev/null; done An external process. 0m24.789s path=/foo/bar; time for i in {1..10000}; do sed 's,.*/,,' <<< "\$path" >/dev/null; done An external process.

## Iterate Parameters

 0m0.239s set -- {1..100000}; time for x; do <(); done An empty process substitution is closer to a noop than :, which undergoes simple-command evaluation. 0m0.298s set -- {1..100000}; time for x; do :; done 0m12.759s set -- {1..100000}; n=1; time while ((\${!n+n++})); do :; done 0m15.700s set -- {1..100000}; n=1; time while [[ \${!n+_} ]]; do ((++n)); done 0m18.560s set -- {1..100000}; time while shift; do :; done Varies greatly between trials - repeated shifting of big argument lists causes cache misses. 0m38.831s set -- {1..100000}; n=1; time while ((n++<\$#)); do :; done Calculating \$# has some overhead.

## Invocation

 0m0.021s time dash -c ':' -- {1..10000} 0m0.024s time ksh -c ':' -- {1..10000} 0m0.027s time zsh -c ':' -- {1..10000} 0m0.217s time bash -c ':' -- {1..10000} Bash takes longer to boot with a long argument list but set -- is just as fast as the others.

BashBenchmark (last edited 2012-05-22 06:01:31 by ormaaj)