Upload
svitla-systems-inc
View
1.946
Download
2
Embed Size (px)
Citation preview
How to make your Ruby/Rails app
10x faster
Александр ДымоRubyC
www.acunote.com
2 / 70
Что не так с Ruby?
Ruby – это медленно!
3 / 70
Что не так с Ruby?
Ruby – это очень медленно!
4 / 70
Что не так с Ruby?
Причины?
5 / 70
Что не так с Ruby?
1. GC (cборка мусора)
6 / 70
Что не так с Ruby?
2. Мелкие неприятности
7 / 70
Что не так с Ruby?
1. GC (cборка мусора)
8 / 70
Garbage Collection
Сборка мусора происходит:
каждые 8 Мб выделенной памяти
выделенная однажды память повторно используется
но никогда не возвращается!
9 / 70
Garbage Collection
в среднем приложении 1 сборка мусора == 100ms
выделяете 1Gb?
- ожидайте 1024/8 = 128 вызовов GC
- потеряете 128 * 0,1 = 12,8 sec!!!
- навсегда оставите себе этот гиг
10 / 70
Garbage Collection
class TestControllerdef index
gc_statistics {#дайте-ка мне гиг памяти!1024.times {
"x"*1024*1024}
}end
end
app.get '/test'> : allocated: 1049602K total in 2052 allocations, GC calls:
146, GC time: 17281 msec
11 / 70
Garbage Collection
Патч, включающий сбор статистики про GC
http://blog.pluron.com/2008/02/memory-profilin.html
12 / 70
Garbage Collection
RUBY_HEAP_MIN_SLOTS=8000000
RUBY_GC_MALLOC_LIMIT=10000
13 / 70
Garbage Collection
Эффект сборки мусора:
GC GC
Tasks 100 (C) 0,54 0,24 2.2х
Sprint 20 x (1+5) (C) 0,46 0,3 1.5х
Copy 120 3,43 2,41 1.4х
Import 71 5,02 3,81 1.3х
Ruby приложение будет в 1.5 - 2 раза медленнее!
"Спасибо" сборщику мусора!
14 / 70
Garbage Collection
Mark & Sweep GC?
Настроить параметры GC?
Почему невовремя?
Почему не то?
15 / 70
Что не так с Ruby?
2. Мелкие неприятности
16 / 70
Что не так с Ruby?
Медленная интерпретация
17 / 70
Медленная интерпретация
Что не так с Date?
> puts Benchmark.realtime { 1000.times { Time.mktime(2009, 5, 6, 0, 0, 0) } }
0.005
> puts Benchmark.realtime { 1000.times { Date.civil(2009, 5, 6) } }
0.080
16x медленнее чем Time! Почему?
%self total self wait child calls name
7.23 0.66 0.18 0.00 0.48 18601 <Class::Rational>#reduce
6.83 0.27 0.17 0.00 0.10 5782 <Class::Date>#jd_to_civil
6.43 0.21 0.16 0.00 0.05 31528 Rational#initialize
5.62 0.23 0.14 0.00 0.09 18601 Integer#gcd
18 / 70
Медленная интерпретация
Исправляем Date: Вася, используй C!
Date::Performance gem с переписанным на С Date
(с) Ryan Tomayko (с моими патчами)
> puts Benchmark.realtime { 1000.times { Time.mktime(2009, 5, 6, 0, 0, 0) } }
0.005
> puts Benchmark.realtime { 1000.times { Date.civil(2009, 5, 6) } }
0.080
> require 'date/performance'
puts Benchmark.realtime { 1000.times { Date.civil(2009, 5, 6) } }
0.006
gem install date-performance
19 / 70
Медленная интерпретация
Влияние Date::Performance:
До: 0.95 sec
После: 0.65 sec
1.5x!
20 / 70
Медленная интерпретация
Используем String::<< вместо String::+=
> long_string = "foo" * 100000
> Benchmark.realtime { long_string += "foo" }
0.0003
> Benchmark.realtime { long_string << "foo" }
0.000004
Избегаем конверсий BigDecimal в строки и числа
> n = BigDecimal("4.5")
> Benchmark.realtime { 10000.times { n <=> 4.5 } }
0.063
> Benchmark.realtime { 10000.times { n <=> BigDecimal("4.5") } }
0.014
in theory: 4.5xin practice: 1.15x
in theory: 75xin practice: up to 70x
21 / 70
Медленная интерпретация
Переписывать на C не такая уж плохая идея:
date-performance
github.com/rtomayko/date-performance
ускоряет операции с датами в 13 раз!
ускоряет приложения в 1.5 раза
monkeysupport
http://github.com/burke/monkeysupport
ActiveSupport переписанный на C
22 / 70
Медленная интерпретация
Переписывать Rails приложение на SQL
тоже неплохая идея:
– иногда ускорение в 5х
– иногда делает возможным то, что невозможно в Ruby
операции над большим кол-вом (1млн) объектов
– детали в моей презентации "Быстрее, Выше, SQL'нее"http://www.slideshare.net/adymo/alexander-dymo-barcamp-2009-faster-higher-sql-2644467
23 / 70
Альтернативные Ruby?
24 / 70
Альтернативные Ruby?
Интерпретация GC
1.8.7EE tmalloc настройки
1.9 VM Lazy GC
jruby JavaVM Java VM GC
rubinius LLVM LLVM GC
25 / 70
Чистая производительность, без GC
26 / 70
Производительность с GC
27 / 70
Влияние настроек
37 Signals:RUBY_HEAP_MIN_SLOTS=600000RUBY_GC_MALLOC_LIMIT=59000000
28 / 70
GC против "без GC"
29 / 70
История
2 года назад сейчас
30 / 70
Инструменты: Производительность
Медленный Ruby
Что делать?
Профилировать с Ruby-Prof
Переписывать на C
Переписывать на SQL
31 / 70
Инструменты: Производительность
Ruby-Prof (http://ruby-prof.rubyforge.org/)
Всегда скажет что не так:
%self total self child calls name 8.39 0.54 0.23 0.31 602 Array#each_index 7.30 0.41 0.20 0.21 1227 Integer#gcd 6.20 0.49 0.17 0.32 5760 Timecell#date 5.11 0.15 0.14 0.01 1 Magick::Image#to_blob
gem install ruby-prof
KCachegrind для визуализации результатов
http://kcachegrind.sourceforge.net
32 / 70
Инструменты: Производительность
33 / 70
Инструменты: Производительность
До какой степени оптимизировать?
Пока не будет так:
%self total self child calls name 1.42 0.39 0.25 0.14 1033 Range#each-1 0.85 0.43 0.15 0.28 2221 Array#each-1 0.74 0.13 0.13 0.00 113447 Array#[] 0.40 0.07 0.07 0.00 5008 Hash#initialize_copy 0.40 0.07 0.07 0.00 45467 Hash#[]= 0.40 0.13 0.07 0.06 37784 Hash#[] 0.17 0.15 0.03 0.12 176 Array#collect 0.17 0.08 0.03 0.05 22371 String#gsub 0.17 0.03 0.03 0.00 44881 Array#<< 0.17 0.03 0.03 0.00 15936 String#== 0.17 0.75 0.03 0.72 1218 Array#each 0.17 0.03 0.03 0.00 37274 PGresult#getvalue 0.11 0.18 0.02 0.16 137 Array#collect! 0.11 0.02 0.02 0.00 3227 User#id
34 / 70
Инструменты: Производительность
Что нужно помнить при профилировке Ruby приложений?
не забывать профилировать память
в среднем приложении 1 сборка мусора == 100ms
выделяете 1Gb?
- ожидайте 1024/8 = 128 вызовов GC
- потеряете 128 * 0,1 = 12,8 sec!!!
35 / 70
Инструменты: Производительность
Что нужно помнить при профилировке Ruby приложений?
выключать GC (GC.disable), иначе можно увидеть:
class Foodef do_smth
return "x" * 1024 # займем 1Kb памятиend
endsmth = "x" * 7999999 # займем почти 8Mb памятиFoo.new.do_smth # здесь произойдет GC
--------------------------%self calls name0.10 1 Foo#do_smth # do_smth такой медленный???0.01 2 String#*