性能报告。两次或更多次花费太多时间的条目

perf report. Twice or more entries that takes too much time

我展示了我使用 perf -g -p 收集的样本的 perf 输出。

我不知道如何解释有很多条目需要 > 90% 的时间这一事实。毕竟,如果一个进程在 start_thread(及其子进程)中花费了 90% 的时间,那么该进程不可能在 java_start(例如)中花费 > 90% 的时间。

请说明

让我们从您用来执行 perf record 的命令开始。

-g 开关的使用表明您正在尝试收集有关调用链的信息以及有关开销的信息。

当 perf 收集调用链时,开销可以在两列中显示为 ChildrenSelf

  Children      Self  Command          Shared Object                Symbol                                                                                                                                 ◆
-   14.19%     0.00%  qemu-system-x86  [unknown]                    [.] 0xbbbe258d4c544155                                                                                                                 ▒
     0xbbbe258d4c544155                                                                                                                                                                                    ▒
     __libc_start_main                                                                                                                                                                                     ▒
   + main                                                                                                                                                                                                  ▒

'self' 开销值表示在单个函数中花费的计时器滴答计数(周期值)。因此,如果仅 'self' 开销值显示在 perf report 中,开销值的总和将始终如您所期望的那样 100%

然而,当 'children' 和 'self' 列都显示在 perf report 中时,事情变得更加混乱。 'children' 开销列汇总了从父项调用的所有子函数的开销值。

在您的案例中,start_thread 的 'children' 开销百分比为 98.78%,但其 'self' 开销为 0.00%。这意味着 start_thread(即 子函数 )调用的所有函数执行所花费的时间总和为 98.78%,但 start_thread 单独根本不会导致任何开销,因为它的 'self' 开销是 0.00%。

现在 Java_start。看起来 start_thread 调用了 Java_start。同样,Java_start 的 'children' 开销将包括它调用的所有函数的开销总和。这就是为什么您再次看到这两个函数的开销值几乎相同。

考虑一个例子--

void main(){
  do_main();
}

void do_main() {
  foo();
}

void foo(){
  bar();
}

void bar(){
  /* do something here */
}

让我们假设 foo()bar() 的 'self' 开销分别为 60% 和 40%。并且还让 main()do_main() 每个 'self' 开销分别为 0% 和 0%。

那么每个函数的 'children' 开销就像 -

main()       children: 100%    self: 0%

do_main()    children: 100%    self: 0%

foo()        children: 100%    self: 60%

bar()        children:  40%    self: 40%