Использовался набор бенчмарков из ruby-1.9.3-p125. Все тесты запускались на:
ОС: OSX Lion 10.7.3
Процессор: 2.3ГГц i5
Память: 8Гб 1333 MHz DDR3
SSD: OCZ Vertex 3 Max IOPS SATA III 2.5" 120Гб
Реализации:
— ruby 1.8.7p249 (системный ruby)
— ruby 1.9.3p125
— ruby 2.0.0dev (2012-02-25 trunk 34796)
— MacRuby 0.12 (ruby 1.9.2) (Nightly build)
— maglev 1.0.0 (ruby 1.8.7)
— rubinius 1.2.4 (1.8.7 release 2011-07-05 JI)
— rubinius 2.0.0dev (1.9.3 e22ed173 JI)
— jruby 1.7.0.dev (ruby-1.9.3-p28) (Java HotSpot(TM) 64-Bit Server VM 1.7.0_04-ea)
— jruby 1.6.7 (ruby-1.8.7-p357) (Java HotSpot(TM) 64-Bit Server VM 1.7.0_04-ea)
JRuby запускался с флагами --server -Xinvokedynamic.constants=true
Компилятор имеет значение
Время от времени я вижу посты об увеличении производительности ruby засчёт применения патчей, но что если пойти ещё дальше и попытаться увеличить производительность компилируя его новейшими компиляторами? Я решил проверить.
Вот список компиляторов:
— gcc version 4.2.1 (build 5658) (LLVM build 2336.9.00)
— Apple clang version 3.1 (tags/Apple/clang-318.0.45) (на базе LLVM 3.1svn)
— gcc version 4.2.1 (Apple Inc. build 5666)
— gcc version 4.7.0 20120218 (experimental) (GCC)
#!/bin/bash compilers=( gcc gcc-4.2 gcc-4.7 clang ) for i in "${compilers[@]}"; do CC=$i ./configure --disable-install-doc --prefix ~/Projects/benches/mri/1.9.3-p125-$i time make -j4 make install done $ ruby driver.rb -v -o ~/Projects/benches/compilers-bench.txt --executables='~/Projects/benches/mri/1.9.3-p125-gcc/bin/ruby; ~/Projects/benches/mri/1.9.3-p125-gcc-4.2/bin/ruby; ~/Projects/benches/mri/1.9.3-p125-gcc-4.7/bin/ruby; ~/Projects/benches/mri/1.9.3-p125-clang/bin/ruby'
Результаты:
~20% разницы (бенчмарк запускался несколько раз и я выбирал наилучший результат) между llvm-gcc, используемым по умолчанию, и gcc-4.7 в синтетических тестах. Неплохо, как мне кажется.
Убедимся, что с gcc-4.7 ничего не сломалось:
PASS all 943 tests KNOWNBUGS.rb . PASS all 1 tests
Хочу убедиться самостоятельно
Это легко можно сделать, если установлен homebrew:
$ brew install https://raw.github.com/etehtsea/formulary/009735e66ccabc5867331f64a406073d1623c683/Formula/gcc.rb --enable-cxx --enable-profiled-build --use-gcc
… часом позже:
$ CC=gcc-4.7 ruby-build 1.9.3-p125 ~/.rbenv/versions/1.9.3-p125
Прим. перев. О ruby-build здесь.
А что по поводу %ещё какая-то реализация ruby%?
Я не смог остановиться и пошёл на поводу своей любознательности и запустил бенчмарк на других популярных реализациях ruby и версиях MRI. Не привожу здесь полных логов, только освещу интересные моменты.
Не используйте ruby, установленный по умолчанию
Это подвох!
bm_vm_thread_mutex3.rb
# 1000 потоков, 1 мьютекс require 'thread' m = Mutex.new r = 0 max = 2000 (1..max).map{ Thread.new{ i=0 while i<max i+=1 m.synchronize{ r += 1 } end } }.each{|e| e.join } raise r.to_s if r != max * max
$ time ~/.rbenv/versions/1.8.7-p357/bin/ruby bm_vm_thread_mutex3.rb real 0m3.093s user 0m3.078s sys 0m0.013s $ /usr/bin/ruby -v ruby 1.8.7 (2011-12-28 patchlevel 357) [i686-darwin11.3.0] $ time /usr/bin/ruby bm_vm_thread_mutex3.rb ^Cbm_vm_thread_mutex3.rb:18:in `join': Interrupt from bm_vm_thread_mutex3.rb:18 from bm_vm_thread_mutex3.rb:7:in `each' from bm_vm_thread_mutex3.rb:7 real 3m54.930s user 3m54.122s sys 0m0.918s
Даже если вы не собираетесь пользоваться Thread, вот результаты без этого теста:
ruby 1.8.7 (2010-01-10) — 572.863 секунды
ruby 1.9.3p125 (2012-02-16) — 211.655 секунд
Не прошедшие тесты на 1.8:
— bm_app_factorial.rb
— bm_so_ackermann.rb
Rubinius 1.2.4 против 2.0.0-dev
Я читал о том, что в 2.0.0-dev больше нет GIL и т.п. и т.д., но эта готовящаяся к выходу версия заметно медленнее.
Самое заметное замедление всё в том же тесте bm_vm_thread_mutext3.rb:
— rubinius 1.2.4 (1.8.7 release 2011-07-05 JI) — 3.260 секунды
— rubinius 2.0.0dev (1.9.3 e22ed173 yyyy-mm-dd JI) — 207.711 секунд
Вот тесты, на которых разница наиболее заметна:
А вот результаты без этих тестов:
1.2.4 — 518.861 секунд
2.0.0dev — 606.811 секунд
Rubinius никогда и не был быстр, а стал ещё на 15% медленнее.
Не прошли тесты:
— факториал 4k вместо 5k
— bm_loop_generator.rb
— bm_so_ackermann.rb
— bm_vm_thread_pass_flood.rb (тест превысил время ожидания выполнения)
MacRuby 0.12 (Nightly)
MacRuby то что нужно, если вы пишете десктопное приложение для OS X, или просто пользуетесь API OS X, но с точки зрения производительности смысла её использовать нет.
Первым делом — eval в MacRuby (bm_vm2_eval.rb) довольно нерасторопен:
ruby 1.9.3p125 (2012-02-16) — 29.681 секунд
MacRuby 0.12 (ruby 1.9.2) — 232.257 секунды
bm_vm2_eval.rb
i=0 while i<6_000_000 i+=1 eval("1") end
So as erb parsing and creation Class instances:
bm_app_erb.rb
# # Create many HTML strings with ERB. # require 'erb' data = DATA.read max = 15_000 title = "hello world!" content = "hello world!n" * 10 max.times{ ERB.new(data).result(binding) } __END__ <html> <head> <%= title %> </head> <body> <h1> <%= title %> </h1> <p> <%= content %> </p> </body> </html>
1.9.3p125 — 1.817 секунды
MacRuby — 81.808 секунда
bm_vm3_clearmethodcache.rb
i=0 while i<200_000 i+=1 Class.new{ def m; end } end
1.9.3p125 — 0.748 секунды
MacRuby — 86.573 секунд
Не прошедшие тесты:
— bm_loop_generator.rb
— bm_so_count_words.rb
— bm_so_nsieve_bits.rb (превышено время ожидания)
— bm_vm_thread_create_join.rb (превышено время ожидания)
Maglev 1.0
Интересно, что у MagLev схожие проблемы:
bm_vm2_eval.rb — 754.028 секунды
bm_vm3_clearmethodcache.rb — 33.785 секунды
JRuby 1.6 против 1.7.0-dev
У JRuby 1.7.0-dev схожая c 1.6.6 производительность, с небольшим улучшением на тесте bm_vm_thread_mutex3.rb:
1.7.0-dev — 14.381 секунд
1.6.6 — 202.552 секунды
Общий результат таков:
1.7.0-dev — 257.584 секунд
1.6.6 — 229.502 секунд
Не прошедшие тесты:
— bm_io_select.rb
MRI 2.0.0-dev против 1.9.3-p125
Всё та же ситуация с dev веткой MRI. Улучшение только в тесте bm_vm_thread_create_join.rb:
ruby 2.0.0dev (2012-02-25 trunk 34796) — 2.806 секунды
ruby 1.9.3p125 (2012-02-16) — 9.239 секунд
Общий зачёт
Сводный график:
График без:
— bm_vm_thread_mutex3.rb
— bm_vm2_eval.rb
— bm_vm3_clearmethodcache.rb
Уже не так плохо, да?
PS. От переводчика: Довольно необычно было переводить статью русскоязычного автора.
Автор: philpirj