Pull to refresh

Забег реализаций ruby '2012

Reading time 4 min
Views 2.1K
Original author: Konstantin Shabanov
Использовался набор бенчмарков из 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. От переводчика: Довольно необычно было переводить статью русскоязычного автора.
Tags:
Hubs:
+29
Comments 19
Comments Comments 19

Articles