perf报告解读

Interpreting of perf report

我展示了使用 perf -g -p 收集的样本的 perf report 的输出。我不知道如何实现第一列。有很多 Java_* 个调用花费了 > 90% 的时间。

如何解读?


在显示的结果中有很多条目,我的意思是:

+ 98,78%     0,00%             java       libpthread-2.26.so
+ 95,77%     0,00%             java       libjvm.so 
...

我的问题是:

为什么这样的条目多于 1 个?每个条目都是一种堆栈跟踪。单线程进程只有一个堆栈跟踪。

您在这里引用的列表:

+ 98,78%     0,00%             java       libpthread-2.26.so
+ 95,77%     0,00%             java       libjvm.so 

...

And my question is:

Why is there more such entries than 1? Every entry is a kind of stacktrace. The one-threaded process has exactly one stacktrace.

不是堆栈跟踪。它是在 运行 期间出现在任何样本的任何堆栈跟踪中的函数列表。只有当您展开该列表的一个元素时,您才能看到包含该函数的组合 tree-view 堆栈跟踪。

我不确定您所说的 one-threaded 进程只有一个堆栈跟踪 是什么意思。任何进程在其生命周期中都会有各种堆栈跟踪,即使它只有一个线程。例如,在它开始的那一刻,堆栈跟踪将只是 main(),一旦 main() 调用一个函数,堆栈跟踪就会更改为包含该函数,依此类推。

现在在函数列表中,第一列显示总开销,包括所有 children(即包括此函数调用的函数)。由于几乎所有有趣的工作都发生在共享相同最外层函数的调用链中,因此顶层是一种无用的列表,其中显示的许多函数占 >90% 的开销。

第二列是"own"开销,表示在该方法中实际花费的时间1不是 任何 children。对于所有顶级方法,这接近于零,因此真正的工作发生在这些方法调用的某些方法中,而不是这些方法本身。

您在顶部展开的树视图确实告诉了您需要了解的内容:您花费了 ~94% 的时间 inside/below radek.queue.wlQueue.writeBytes(),而那个人花费了大部分时间它的时间在 String.intern()。所以这里的瓶颈是所有的 String.intern() 调用,可能是因为字符串 table 太小,或者只是因为 String.intern() 只是 generally sucks for de-duplication。我这里的一般规则是只使用 Guava 的 Interner<String> 除非你特别需要 属性 文字字符串与 interned 字符串共享相同的字符串池(即 "foo" == new String("foo").intern())。


1 我在这里松散地说 "amount of time" - 它实际上是您指定给 perf record 的任何事件的总样本的一部分 - 但默认情况下那应该是大约 CPU 时间。