【问题标题】:what does "iterations" mean in "perf report -b --branch-history" (of perf record -b -g)“迭代”在“性能报告 -b --branch-history”(性能记录 -b -g)中是什么意思
【发布时间】:2019-01-09 11:26:42
【问题描述】:

我正在使用 perf 分析一个玩具程序(选择排序),我想知道 perf 报告输出中的 iterations 对应于什么。它显示的地址对应于内部循环和 if 语句。我希望有人能帮忙。此外,当我将“-b --branch-history”与 perf 一起使用时,基本块周期列会消失。我不知道为什么。

这是我的代码被采样的部分(MAX_LENGTH 为 500):

   35 // FROM: https://www.geeksforgeeks.org/selection-sort
   37 void swap(int *xp, int *yp)
   38 {
   39     int temp = *xp;
   40     *xp = *yp;
   41     *yp = temp;
   42 }
   43       
   44 void selection_sort(int arr[])
   45 {
   46     int i, j, min_idx;
   47
   48     // One by one move boundary of unsorted subarray
   49     for (i = 0; i < MAX_LENGTH-1; i++)
   50     {
   51         // Find the minimum element in unsorted array
   52         min_idx = i;
   53         for (j = i+1; j < MAX_LENGTH; j++)
   54           if (arr[j] < arr[min_idx])
   55             min_idx = j;
   56
   57         // Swap the found minimum element with the first element
   58         swap(&arr[min_idx], &arr[i]);
   59     }
   60 }

使用(clang 版本 5.0.0)编译:

clang -O0 -g selection_sort.c -o selection_sort_g_O0

这是我调用性能记录的方式:

sudo perf record -e cpu/event=0xc4,umask=0x20,name=br_inst_retired_near_taken,period=1009/pp -b -g ./selection_sort_g_O0

性能报告及其输出:

sudo perf report -b --branch-history --no-children

Samples: 376  of event 'br_inst_retired_near_taken', Event count (approx.): 37603384
  Overhead  Source:Line               Symbol                  Shared Object                                                                                                                                         ▒
+   51.86%  selection_sort_g_O0[862]  [.] 0x0000000000000862  selection_sort_g_O0                                                                                                                                   ▒
-   24.47%  selection_sort_g_O0[86e]  [.] 0x000000000000086e  selection_sort_g_O0                                                                                                                                   ▒
     0x873 (cycles:1)                                                                                                                                                                                               ▒
   - 0x86e (cycles:1)                                                                                                                                                                                               ▒
      - 23.94% 0x86e (cycles:3 iterations:25)                                                                                                                                                                       ▒
           0x862 (cycles:3)                                                                                                                                                                                         ▒
           0x83f (cycles:1)                                                                                                                                                                                         ▒
           0x87c (cycles:1)                                                                                                                                                                                         ▒
           0x873 (cycles:1)                                                                                                                                                                                         ▒
           0x86e (cycles:1)                                                                                                                                                                                         ▒
           0x86e (cycles:3)                                                                                                                                                                                         ▒
           0x862 (cycles:3)                                                                                                                                                                                         ▒
           0x83f (cycles:1)                                                                                                                                                                                         ▒
           0x87c (cycles:1)                                                                                                                                                                                         ▒
           0x873 (cycles:1)                                                                                                                                                                                         ▒
           0x86e (cycles:1)                                                                                                                                                                                         ▒
           0x86e (cycles:3)                                                                                                                                                                                         ▒
           0x862 (cycles:3)                                                                                                                                                                                         ▒
+   22.61%  selection_sort_g_O0[87c]  [.] 0x000000000000087c  selection_sort_g_O0                                                                                                                                   ▒
+    1.06%  selection_sort_g_O0[8a5]  [.] 0x00000000000008a5  selection_sort_g_O0

我使用 objdump 在地址和源文件行之间进行映射:

objdump -Dleg selection_sort_g_O0 > selection_sort_g_O0.s

../selection_sort.c:53
 836:   8b 45 f4                mov    -0xc(%rbp),%eax
 839:   83 c0 01                add    $0x1,%eax
 83c:   89 45 f0                mov    %eax,-0x10(%rbp)
 83f:   81 7d f0 f4 01 00 00    cmpl   $0x1f4,-0x10(%rbp)
 846:   0f 8d 35 00 00 00       jge    881 <selection_sort+0x71>
../selection_sort.c:54
 84c:   48 8b 45 f8             mov    -0x8(%rbp),%rax
 850:   48 63 4d f0             movslq -0x10(%rbp),%rcx
 854:   8b 14 88                mov    (%rax,%rcx,4),%edx
 857:   48 8b 45 f8             mov    -0x8(%rbp),%rax
 85b:   48 63 4d ec             movslq -0x14(%rbp),%rcx
 85f:   3b 14 88                cmp    (%rax,%rcx,4),%edx
 862:   0f 8d 06 00 00 00       jge    86e <selection_sort+0x5e>
../selection_sort.c:55
 868:   8b 45 f0                mov    -0x10(%rbp),%eax
 86b:   89 45 ec                mov    %eax,-0x14(%rbp)
../selection_sort.c:54
 86e:   e9 00 00 00 00          jmpq   873 <selection_sort+0x63>
../selection_sort.c:53
 873:   8b 45 f0                mov    -0x10(%rbp),%eax
 876:   83 c0 01                add    $0x1,%eax
 879:   89 45 f0                mov    %eax,-0x10(%rbp)
 87c:   e9 be ff ff ff          jmpq   83f <selection_sort+0x2f>

【问题讨论】:

  • 你真的需要sudo吗?我忘记了 sysctl kernel.perf_even_paranoid = 0 实际做了什么,但我通常不必使用 sudo 来分析内容。
  • 您向selection_sort 提供什么输入?你的 CPU 微架构、性能版本、内核版本是什么?我无法重现相同的输出。
  • 我确实需要 sudo。我没有注意“为什么”,但我的系统是archlinux 4.13,12。 perf 版本是 4.13(看起来我需要更新)。机器是zenbook pro:i7-6700HQ CPU @ 2.60GHz,8核
  • 作为输入,我生成了随机 500 个数字并将其放入数组中。该代码不使用 rand(),我只是通过 bash $RANDOM 生成了这些数字并将它们放入代码中:一个带有初始化列表的数组。我试图保持一切确定性,以便分析信息可能更有意义

标签: assembly x86 perf branch-prediction


【解决方案1】:

我将尝试在祖兰的回答之上重申并添加更多信息。

最后一个分支记录 (LBR) 允许在可执行文件中查找热执行路径,以直接检查它们以获得优化机会。在 perf 中,这是通过扩展调用堆栈显示机制并将最后的基本块添加到调用堆栈中来实现的,调用堆栈通常用于显示最常见的函数调用层次结构。

这可以通过使用 perf 记录中的 调用图 (-g) 和 LBR (-b) 选项 以及 perf 中的 --branch-history 选项来完成报告,它将最后一个分支信息添加到调用图中。本质上,它为 8-32 个分支提供了为什么发生某事的额外上下文。

最近perf 版本中的timed LBR 功能报告每个基本块的平均周期数。

什么是迭代?

据我了解,分支历史代码有循环检测功能。这使我们可以通过计算removed loops 的数量来获得迭代次数。 重复循环的删除仅在perf report 输出中引入(以直方图格式显示),通过 Linux 内核中的先前commit

struct iterations 是一个有用的 C 结构,用于显示 perf report 中的迭代次数。

This 是保存迭代次数以显示在perf report 输出中的位置。正在从 remove_loops 函数内部调用 save_iterations 函数。

在解决 callchain 时正在删除循环。

您还可以阅读此commit,它描述了perf report 如何显示在较新的 Linux 内核版本中引入的迭代和更改的数量。

【讨论】:

  • 谢谢!因此,假设我设法获得了我要求的时间段,我如何估计我的循环的行程次数?我在 1009 期间看到 25,这个循环实际上执行 (499*500)/2 = 124750。我知道我只是在采样。我将尝试使用在整个执行过程中具有恒定行程计数的循环。
  • 我不太确定“循环行程计数”是什么意思。但我可以说的是,您只是在 1009 期间内进行采样。您每 1009 个事件生成一个样本 - 所以实际上您并没有计算在内。但是,使用分支历史记录确实可以让您以低得多的粒度查看周期数。
  • 好的,所以我的目标是使用 perf 报告的采样周期和迭代来估计循环所花费的迭代总数(也称为循环行程计数)。
【解决方案2】:

当我快速浏览perf 源代码和提交时,我将信息拼凑在一起,对此答案持保留态度。

perf report --branch-history 尝试根据跟踪中的分支记录构建程序的控制流。这样做时,它还会检测循环。但是,perf record 的信息可能不完整,因此循环检测也会出错。

如果您的系统与我的系统相似(Haswell 桌面,Linux 4.17.6),perf 可能会记录每个采样的LBR。如果此 LBR 包含 16 个最近的分支,则您必须将事件周期减少到 16 个退休分支。即使使用convincing the kernel not to throttle recording,我也无法获得任何有意义的结果。

很遗憾,我不知道用perf 记录完整分支跟踪的方法。

【讨论】:

  • 感谢您的信息。但是,我不太明白“如果此 LBR 包含 16 个最近的分支,则您必须将事件周期减少到 16 个退休分支”。关于收集的数据是错误的,我同意。首先,我们正在采样,其次,已知 LBR 是错误的:ieeexplore.ieee.org/document/8366953。老实说,我想不出更多来了解我正在查看的性能报告数据
  • 我的观点是,如果你能收集每个样本最近的16个分支,你必须每16个分支抽取一个样本。查看perf script -D 以查看原始数据,这可能会提供一些关于幕后内容的见解。
  • 好的,我玩过的时期是:499、277、97 和 31。我仍然看到迭代为 25、24 围绕相同的地址。我期待它会改变。也许我应该得出结论,这些“迭代”与循环迭代无关。
  • 检查您的dmesg 以获得perf: interrupt took too long。如果你找到了,你可能没有得到你要求的时间。
  • 谢谢你的建议,我看了我的 dmesg,你是对的。对于我发布的示例,我没有观察到这一点,但对于我强调循环行程计数的其他玩具示例。所以,我无法确认我的实验是否合理
猜你喜欢
  • 1970-01-01
  • 2022-11-10
  • 1970-01-01
  • 1970-01-01
  • 2014-01-16
  • 2017-02-02
  • 2013-12-16
  • 2017-11-28
  • 1970-01-01
相关资源
最近更新 更多