Ruby / [Перевод] Забег реализаций ruby ‘2012

в 19:43, , рубрики: jruby, maglev, rubinius, ruby, yarv

Использовался набор бенчмарков из 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' 

Результаты:
Ruby / [Перевод] Забег реализаций ruby 2012

~20% разницы (бенчмарк запускался несколько раз и я выбирал наилучший результат) между llvm-gcc, используемым по умолчанию, и gcc-4.7 в синтетических тестах. Неплохо, как мне кажется.

Ruby / [Перевод] Забег реализаций ruby 2012

Убедимся, что с 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 секунд

Вот тесты, на которых разница наиболее заметна:
Ruby / [Перевод] Забег реализаций ruby 2012

А вот результаты без этих тестов:

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 секунды

Ruby / [Перевод] Забег реализаций ruby 2012

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 секунд

Общий зачёт

Ruby / [Перевод] Забег реализаций ruby 2012

Сводный график:
Ruby / [Перевод] Забег реализаций ruby 2012

График без:

— bm_vm_thread_mutex3.rb
— bm_vm2_eval.rb
— bm_vm3_clearmethodcache.rb

Ruby / [Перевод] Забег реализаций ruby 2012

Уже не так плохо, да?

PS. От переводчика: Довольно необычно было переводить статью русскоязычного автора.

Автор: philpirj

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js