Driven by the curiosity to find out why Rails boot time is so long, I had a look at various interpreter bootup times a few months ago. The findings were interesting, so I repeated the experiment and documented it here.
Without much further ado, here are the results on my 2.6GHz (max 3.2GHz) dual-core i5, 3MB shared L3 cache MacBook Pro. The processor utilization was around ~20% during the tests. I have the feeling that the taskgated
process was actually throttling the process spawns because it showed a ~3% CPU utilization.
Results (measured from Rebol 2)
Language | Time (s) | Command |
---|---|---|
awk | 3.338692 | awk 1 /dev/null |
bash | 3.319932 | bash /dev/null |
Red | 3.355276 | red <<< q |
Perl | 3.367032 | perl -e 1 |
Rebol3 | 4.386402 | r3 -q --do 1 |
Rebol2 | 5.730028 | rebol -qw --do 1 |
Python | 5.774575 | python -c 1 |
Ruby | 6.542229 | ruby -e 1 |
NodeJS | 6.548273 | node -e 1 |
PHP | 7.388102 | php -r "1;" |
I have no idea why is it so slow, but looks like there is a 1 time ~3second overhead...
Results (measured from Rebol 3)
Language | Time (s) | Command | Version |
---|---|---|---|
awk | 0.418281 | awk 1 /dev/null | 20070501 |
bash | 0.598093 | bash /dev/null | 3.2.48(1) |
Perl | 0.793951 | perl -e 1 | 5.12.4 |
Red | 0.804189 | red <<< q | 2013-May-13 |
Rebol3 | 1.291347 | r3 -q --do 1 | 2.101.0.2.5-g7aba167 |
Rebol2 | 2.693652 | rebol -qw --do 1 | 2.7.8.2.5 |
Python | 2.87769 | python -c 1 | 2.7.2 |
Ruby | 3.17956 | ruby -e 1 | 2.0.0p247 |
NodeJS | 3.362719 | node -e 1 | 0.10.5 |
PHP | 4.388712 | php -r 1\; | 5.3.15 |
It's a lot closer to the results measure from the shell, but still can't explain the significantly higher runtimes.
Results (measured from Bash)
Language | Time (s) | Command |
---|---|---|
awk | real 0.20 user 0.09 sys 0.09 | awk 1 /dev/null |
bash | real 0.24 user 0.11 sys 0.10 | bash /dev/null |
Red | real 0.40 user 0.20 sys 0.17 | echo q | red > /dev/null |
Perl | real 0.59 user 0.25 sys 0.24 | perl -e 1 |
Rebol3 | real 1.03 user 0.74 sys 0.17 | r3 -q --do 1 |
Rebol2 | real 2.41 user 1.90 sys 0.34 | rebol -qw --do 1 |
Python | real 2.61 user 1.80 sys 0.69 | python -c 1 |
Ruby | real 3.03 user 2.40 sys 0.48 | ruby -e 1 |
NodeJS | real 3.16 user 2.42 sys 0.58 | node -e 1 |
PHP | real 4.23 user 3.26 sys 0.75 | php -r 1; |
Since the results are below the second often, the next table shows results of a 10 times longer loop.
Language | Time (s) | Command |
---|---|---|
awk | real 2.28 user 1.03 sys 1.09 | awk 1 /dev/null |
bash | real 2.50 user 1.22 sys 1.12 | bash /dev/null |
Red | real 4.11 user 2.08 sys 1.79 | echo q | red > /dev/null |
Perl | real 5.89 user 2.55 sys 2.36 | perl -e 1 |
Rebol3 | real 10.35 user 7.47 sys 1.73 | r3 -q --do 1 |
Rebol2 | real 24.72 user 19.46 sys 3.58 | rebol -qw --do 1 |
Python | real 26.94 user 18.49 sys 7.22 | python -c 1 |
Ruby | real 31.32 user 24.74 sys 5.04 | ruby -e 1 |
NodeJS | real 31.81 user 24.44 sys 5.85 | node -e 1 |
PHP | real 41.80 user 32.44 sys 7.45 | php -r 1; |
Earl's results
Running on a 2.9GHz i7 Lenovo T430s 64bit Linux machine:
Language | Time (s) | Command | Version |
---|---|---|---|
Perl | 0.350214 | perl -e 1 | 5.18.0 |
awk | 0.452196 | awk 1 /dev/null | 4.1.0 |
bash | 0.459334 | bash /dev/null | 4.2.45 |
Rebol3 | 0.811616 | rebol3 -q --do 1 | 2.101.0-g264bb4e (current mainline) |
Python2 | 1.08194 | python2 -c 1 | 2.7.5 |
Rebol2 | 1.084499 | rebol2 -qw --do 1 | 2.7.8.4.2 |
NodeJS | 1.619252 | node -e 1 | 0.10.15 |
Ruby | 2.237109 | ruby -e 1 | 2.0.0p247 |
Python3 | 2.775345 | python3 -c 1 | 3.3.2 |
Akomba's result
Just for the record here is a latest 1.7GHz i7 MacBook Air
Language | Time (s) | Command | Version |
---|---|---|---|
Perl | real 0.64 user 0.25 sys 0.24 | perl -e 1 | |
Ruby | real 2.93 user 2.30 sys 0.46 | ruby -e 1 | 2.0.0p195 |
Python | real 6.22 user 5.14 sys 0.83 | python -c 1 |
Bash benchmark script
Just copy it from here and run pbpaste | bash
.
x=`seq 1 100`
bm() { echo "| $1 | "`(time -p for i in $x; do $2 >/dev/null; done) 2>&1`" | $2 |"; }
bm awk "awk 1 /dev/null"
bm bash "bash /dev/null"
t_red=`(time -p for i in $x; do echo q | red > /dev/null; done) 2>&1`
echo "| Red | "$t_red" | echo q | red > /dev/null |"
bm Perl "perl -e 1"
bm Rebol3 "r3 -q --do 1"
bm Rebol2 "rebol -qw --do 1"
bm Python "python -c 1"
bm NodeJS "node -e 1"
bm Ruby "ruby -e 1"
bm PHP "php -r 1;"
Rebol benchmark script
This was left as the last section so this article can be fed in to the Rebol interpreter directly, like:
$ rebol2 -qws _posts/2013-08-18-startup-time-of-interpreters.md
$ rebol3 -q _posts/2013-08-18-startup-time-of-interpreters.md
Rebol []
; rebol2 -qw --do 'source build-tag' | pbcopy
build-tag: func [
"Generates a tag from a composed block."
values [block!] "Block of parens to evaluate and other data."
/local tag value-rule xml? name attribute value
][
tag: make string! 7 * length? values
value-rule: [
set value issue! (value: mold value)
| set value file! (value: replace/all copy value #" " "%20")
| set value any-type!
]
xml?: false
parse compose values [
[
set name ['?xml (xml?: true) | word!] (append tag name)
any [
set attribute [word! | url!] value-rule (
repend tag [#" " attribute {="} value {"}]
)
| value-rule (repend tag [#" " value])
]
end (if xml? [append tag #"?"])
]
|
[set name refinement! to end (tag: mold name)]
]
to tag! tag
]
foreach [lang cmd] [
awk "awk 1 /dev/null"
bash "bash /dev/null"
Red "red <<< q > /dev/null"
Perl "perl -e 1"
Rebol3 "r3 -q --do 1"
Rebol2 "rebol -qw --do 1"
Python "python -c 1"
NodeJS "node -e 1"
Ruby "ruby -e 1"
PHP "php -r 1\;"
][
t: delta-time [ loop 100 [call/wait cmd] ] secs: round/to t 0.01
|: "|" bar-div: build-tag [div style (rejoin ["width:" secs "em"])]
print [ | lang bar-div </div> | secs | cmd | ]
] q