Профилирование кода Ruby

Помимо рубинового и основного классов Benchmark, что вы используете для профилирования вашего Ruby-кода? В частности, как вы находите узкие места в своем коде? Мне почти кажется, что мне нужно работать над своим собственным маленьким инструментом, чтобы выяснить, где все время тратится на мой код.

Я понимаю, что ruby-prof предоставляет это, но вывод откровенно очень запутанный и не позволяет легко узнать, какие фактические блоки вашего собственного кода являются источником проблемы (он рассказывает вам о том, какие вызовы метода самое время хотя). Таким образом, я не получаю так много от этого, как хотелось бы, и на самом деле не смог его использовать.

Возможно, я делаю это неправильно? Есть ли альтернативы? Поиск в Google не вызывает ничего для меня.

Ответ 1

Множество профайлеров вот так. Что вам нужно знать, это не то место, где программа тратит свое время, но почему. Любые ссылки на анализ динамического кода?

ADDED: Вот как я нахожу "узкие места" в моем коде. (Я ненавижу это слово.) Вот список причин почему.

Совершенно естественно предположить, что для поиска "узких мест" вам нужно как-то много измерить. Это настолько естественно, что почти все профилировщики основаны на нем.

Собственно, поиск и измерение - это не та же проблема. Необходимо измерить, чтобы увидеть, изменилось ли то, что вы нашли (и зафиксировано). Найти, что исправить, для меня больше похоже на отладку, чем на измерение.

Самый простой способ объяснить это - начать с бесконечного или почти бесконечного цикла. Как вы его нашли? Вы делаете паузу и смотрите на стек, верно? потому что вы знаете, что проблема находится где-то в стеке. Вам нужно только приостановить его один раз, а затем вам нужно изучить код в стеке. Несколько раз остановите его, если вы хотите убедиться, что нашли его.

Предположим, что код занимает в два раза больше необходимого. Это означает, что когда вы делаете паузу, есть 50% шанс, что вы увидите, что он делает ненужную вещь. Если вы приостановите его и посмотрите на него 10 раз, вы поймаете его в акте примерно 5 раз. Фактически, как только вы видите, что он делает что-то, вы можете оптимизировать всего лишь 2 образца, вы нашли "узкое место". Исправьте его, измерьте ускорение, покажите его и повторите.

Даже если ваша самая большая проблема не очень большая, этот метод в конечном итоге найдет ее. Кроме того, есть явление увеличения, где небольшие проблемы становятся легче найти после того, как вы удалите более крупные. Это позволяет вам продолжать работу, пока код не станет практически оптимальным.

P.S. После того, как вы это сделаете, все еще могут быть возможности для ускорения. Например, алгоритмы оптимизации могут зависеть от численной устойчивости. Архитектуры, основанные на сообщениях, могут затруднить отслеживание того, почему выполняется код. В программном обеспечении реального времени проблема с производительностью может возникать только изредка и быть менее простой в выборке. Это требует большего удобства. Падение назад только на измерение не делает этого.

Ответ 2

Чтобы действительно просверлить свой код, попробуйте stackprof.

Вот быстрое решение о том, как его использовать: Установите драгоценный камень: gem install stackprof. В своем коде добавьте: require 'stackprof' и объедините часть, которую вы хотите проверить:

StackProf.run(mode: :cpu, out: 'stackprof-output.dump') do {YOUR_CODE} end

После запуска ruby ​​ script go проверьте вывод в терминале с помощью stackprof stackprof.dump:

Mode: cpu(1000)
Samples: 9145 (1.25% miss rate)
GC: 448 (4.90%)

 TOTAL    (pct)     SAMPLES    (pct)     FRAME
   236   (2.6%)         231   (2.5%)     String#blank?
   546   (6.0%)         216   (2.4%)     ActiveRecord::ConnectionAdapters::Mysql2Adapter#select
   212   (2.3%)         199   (2.2%)     Mysql2::Client#query_with_timing
   190   (2.1%)         155   (1.7%)     ERB::Util#html_escape``

Здесь вы можете увидеть все свои методы, требующие много времени. Теперь удивительная часть: сверлить только сделать stackprof stackprof.dump --method String#blank?, и вы получите результат для конкретного метода:

String#blank? (lib/active_support/core_ext/object/blank.rb:80)
  samples:   231 self (2.5%)  /    236 total (2.6%)
  callers:
    112  (   47.5%)  Object#present?
  code:
                                  |    80  |   def blank?
  187    (2.0%) /   187   (2.0%)  |    81  |     self !~ /[^[:space:]]/
                                  |    82  |   end

И вы можете легко понять, какая часть вашего кода занимает много времени для запуска.

Если вы хотите получить визуальный вывод stackprof stackprof.dump --graphviz >> stackprof.dot и с помощью graphviz (brew install graphviz) dot- T pdf -o stackprof.pdf stackprof.dot получить красивый PDF-вывод, в котором выделяются методы, которые занимают много времени.

Ответ 3

Это мой собственный вопрос, но я нашел инструмент, который настолько поразителен для профилирования, что я должен добавить его здесь:

http://samsaffron.com/archive/2013/03/19/flame-graphs-in-ruby-miniprofiler

Flamegraphs делают источник проблем с производительностью удивительно очевидным, по сравнению с поиском backtraces.