Rubinius — niby MRI, ale zupełnie inaczej

Rubinius — niby MRI, ale zupełnie inaczej

Slides from a presentation delivered on 15.01.2013 at the Warsaw Ruby Users Group meetup.

http://wrug.eu/2013/01/09/spotkanie-styczniowe/

Ae7a42fb716793697b1d222f3cc753b8?s=128

Jan Stępień

January 15, 2013
Tweet

Transcript

  1. Nazywam się Jan Stępień, a ta prezentacja nosi tytuł Rubinius

    czyli niby MRI, ale zupełnie inaczej
  2. $ rbx irb(main):001:0> RUBY_VERSION => ”1.8.7”

  3. $ rbx -X19 irb(main):001:0> RUBY_VERSION => ”1.9.3”

  4. Spis treści 1. Filozofia 2. Kompilacja JIT 3. Odśmiecanie pamięci

    4. Wielowątkowość 5. Co z tego wynika
  5. Filozofia

  6. MRI Język kluczowy to C

  7. Announcing RuDy: write Ruby native extensions in D programming language

    – Tomasz Stachewicz, EuRuKo 2009
  8. Profiling Ruby – Piotr Szotkowski, EuRuKo 2010

  9. Kod działa za wolno ⇒ Przepisz to w C, C++,

    D itp.
  10. Rubinius Język kluczowy to Ruby

  11. Array#insert w MRI i Rubinius static VALUE rb_ary_insert(int argc, VALUE

    *argv, VALUE ary) { long pos; if (argc < 1) { rb_raise(rb_eArgError, ”wrong number of arguments”); } rb_ary_modify_check(ary); if (argc == 1) return ary; pos = NUM2LONG(argv[0]); if (pos == -1) { pos = RARRAY_LEN(ary); } if (pos < 0) { pos++; } rb_ary_splice(ary, pos, 0, rb_ary_new4(argc - 1, argv + 1)); return ary; } class Array def insert(idx, *items) Rubinius.check_frozen return self if items.length == 0 idx = Rubinius::Type.coerce_to idx, Fixnum, :to_int idx += (@total + 1) if idx < 0 if idx < 0 raise IndexError, ”#{idx} out of bounds” end self[idx, 0] = items self end end (przeredegowano i usunięto to i owo w celu poprawy czytelności)
  12. Kod działa za wolno ⇒ Popraw maszynę wirtualną

  13. Kompilacja JIT

  14. Just-in-time compilation Kompilacja w ostatniej chwili

  15. Kompilacja wedle MRI require ’sinatra’ get ’/ping’ do content_type ’text/pong’

    ’pong’ end → call self :get '/ping' :args → putself putstring ”sinatra” send :require, 1, nil, 8 pop trace putself putstring ”/ping” send :get, 1, <c>, 8
  16. Kompilacja wedle Rubinius . . . → putself putstring ”sinatra”

    send :require, 1, nil, 8 pop trace putself putstring ”/ping” send :get, 1, <c>, 8 → xor eax, eax test rax, rax je 0xf01dab1e pop rbp mov edi, 0x600d80 jmp rax nop dword ptr [rax+0x0] mov eax, 0x600d80
  17. Kompilacja wedle Rubinius ...co można podsumować następująco:

  18. Kompilacja wedle Rubinius require ’sinatra’ get ’/ping’ do content_type ’text/pong’

    ’pong’ end → xor eax, eax test rax, rax je 0xf01dab1e pop rbp mov edi, 0x600d80 jmp rax nop dword ptr [rax+0x0] mov eax, 0x600d80 LLVM
  19. Making Ruby Fast: e Rubinius JIT – Evan Phoenix https://blog.engineyard.com/2010/making-ruby-fast-the-rubinius-jit/

  20. Odśmiecanie pamięci

  21. Zarządzanie pamięcią w MRI Alokacja ▶ Pula pamięci podzielona na

    bloki ▶ Lista nieużywanych kawałków Zwalnianie 1. Zatrzymaj działanie maszyny 2. Zaznacz używane obiekty 3. Usuń niezaznaczone
  22. MRI spędza 20% czasu na odśmiecaniu pamięci

  23. 20%

  24. 20%

  25. Garbage Collection and the Ruby Heap – Joe Damato, RailsConf

    2010
  26. Spostrzeżenie Większość obiektów żyje bardzo krótko

  27. Żłobek → Młodzież → Starszyzna Kontener na większe obiekty

  28. 5 ings You’ll Love About Rubinius – Brian Ford https://blog.engineyard.com/2009/5-things-youll-love-about-rubinius/

    Garbage Collector – Dirkjan Bussink https://github.com/rubinius/rubinius/blob/master/web/doc/en/memory- system/garbage-collector.markdown
  29. Wielowątkowość

  30. Współbieżność vs. Równoległośc

  31. Współbieżność (ang. concurrency) wątek β wątek α czas

  32. Równoległość (ang. parallelism) wątek β wątek α czas

  33. threads = [1, 2].map do |x| Thread.new do 100_000_000.times {

    x = -x } end end threads.map &:join
  34. $ time ruby wątki.rb 30.73user 0.03system 0:31.45elapsed 97%CPU (0avgtext+0avgdata 5032maxresident)k

    2032inputs+0outputs (1major+1354minor)pagefaults 0swaps $ time rbx wątki.rb 20.53user 0.04system 0:10.92elapsed 188%CPU (0avgtext+0avgdata 34280maxresident)k 0inputs+0outputs (0major+9166minor)pagefaults 0swaps
  35. mri 31,5 s 5 MB 97% rbx 10,9 s 34

    MB 188%
  36. Co z tego wynika

  37. Garść testów Życiowe ▶ rails — 1 000 zapytań do

    prostej aplikacji Rails 3.2 ▶ sinatra — 10 000 zapytań do jeszcze prostszej aplikacji w Sinatrze Nieżyciowe ▶ macierze — mnożenie macierzy (źródło: The Computer Language Benchmarks Game) ▶ wątki — to samo co kilka slajdów temu
  38. 0 10 20 30 40 50 rails sinatra wątki macierze

    rbx mri Czas wykonania [s] Rubinius: commit fd80bd skompilowany GCC 4.7.2. MRI: pakiet Arch Linux x86-64 w wersji 1.9.3_p362-1.
  39. Rubinius - Use Ruby – Karol Hosiawa, KRUG 11.2011 http://hosiawak.github.com/rubinius_presentation/

  40. jan@stepien.cc http://stepien.cc/~jan @janstepien Serdecznie dziękuję

  41. Uzupełnienia po prezentacji Niniejszy slajd ma na celu uzupełnienie prezentacji

    przedstawionej na spotkaniu Warsaw Ruby Users Group w dniu 15.01.2013. W przeprowadzonym przeze mnie eksperymencie, w którym MRI zużywał na odśmiecanie pamięci 20% czasu procesora, w wypadku Rubinius czas spędzony w GC stanowił 5% łącznego czasu wykonania. Przed każdym spośród wykonanych testów dokonano uruchomienia, którego wyniki były odrzucane, aby pozwolić systemowi operacyjnemu na umieszczenie niezbędnych plików w pamięci podręcznej. Testy Ruby on Rails i Sinatra były prowadzone przy pomocy serwera in 1.5.0. Ze względu na fakt, że in korzysta z rozszerzeń napisanych w C, warto dokonać powtórnych testów na innych serwerach, np. (sic!) WEBrick. Czas odpowiedzi na zapytania HTTP mierzono przy pomocy ApacheBench 2.3. W wypadku obu maszyn wirtualnych testy poprzedzone były zadaniem tysiąca niemierzonych zapytań HTTP. Miało to na celu umożliwienie Rubinius rozpoczęcia kompilacji JIT przed właściwymi testami. Kod testów można uzyskać pod adresem https://bitbucket.org/jstepien/wrug-2013-01-15
  42. Prezentację przygotowano przy pomocy pakietu L A TEX. © 2013

    Jan Stępień. Część praw zastrzeżono.