分析Ruby代码

Profiling Ruby Code

除了RubyProf和核心基准类之外,您使用什么来分析您的Ruby代码?尤其是,如何在代码中找到瓶颈?我几乎觉得我需要使用自己的小工具来弄清楚代码中所有的时间都花在了哪里。

我认识到Ruby Prof提供了这一点,但是坦率地说,输出非常混乱,而且不容易找出您自己代码的实际块是问题的根源(它告诉您哪些方法调用花费的时间最多)。所以我并没有得到我想要的那么多,也没有真正的利用它。

也许我做错了?有其他选择吗?谷歌搜索没有给我带来任何东西。


要真正深入到代码中,请尝试stackprof。

下面是一个关于如何使用它的快速解决方案:安装gem:gem install stackprof。在您的代码中,添加:require 'stackprof'并围绕您要检查的部分:

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

运行ruby脚本后,使用stackprof stackprof.dump检查终端中的输出:

1
2
3
4
5
6
7
8
9
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?,就可以获得特定方法的输出:

1
2
3
4
5
6
7
8
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 graphvizdot -T pdf -o stackprof.pdf stackprof.dot得到一个漂亮的pdf输出,这突出了运行时间长的方法。


很多资料员都是这样的。你需要知道的不是程序在哪里花费时间,而是为什么。有关于动态代码分析的参考吗?

补充:下面是我如何在代码中找到"瓶颈"的方法。(我讨厌这个词。)以下是原因列表。

假设要找到"瓶颈",你必须以某种方式进行大量的测量,这是非常自然的。这是很自然的,几乎所有的轮廓都是基于它的。

事实上,发现和测量不是同一个问题。需要进行测量,以查看您发现(和修复)的内容是否产生了影响。对我来说,找到解决问题的方法更像是调试而不是测量。

最简单的解释方法是从一个无限的,或接近无限的循环开始。你怎么找到的?你停下来看看那堆,对吗?因为你知道问题出在堆栈的某个地方。您只需要暂停一次,然后需要研究堆栈上的代码。如果你想确定你找到它,可以暂停几次。

假设代码只需要两倍的时间。这意味着当你暂停的时候,你有50%的机会看到它做了不必要的事情。如果你停下来看10次,你会在表演中抓住它大约5次。事实上,一旦你看到它做了一些你可以在2个样本上优化的事情,你就会发现一个"瓶颈"。修好它,测量加速,展示它,然后重复。

即使你最大的问题不是很大,这个方法最终也会找到它。此外,还有一种放大现象,当你移除较大的问题后,很容易发现小问题。这使您可以继续工作,直到代码接近最佳状态。

另外,在你这样做之后,可能还有加速的机会。例如,优化算法可以依赖于数值稳定性。消息驱动的体系结构会使跟踪代码执行的原因变得更加困难。在实时软件中,性能问题只会偶尔发生,不太容易取样。这需要更多的聪明。仅仅靠测量是不行的。


这是我自己的问题,但我发现了一个非常适合分析的工具,我必须在这里添加它:

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

与查看回溯相比,火焰图使性能问题的根源非常明显。


也有ruby -rprofile或者Ruby源代码require 'profile'中的等效代码。

文档:

https://ruby-doc.org/stdlib-2.1.0/libdoc/profiler/rdoc/profiler_uuu.html