我正在使用性能分析工具对玩具程序(选择排序)进行性能分析,我想知道性能报告输出中对应的迭代次数是什么。它显示的地址对应于内部循环和if语句。希望有人能帮忙。另外,当我在perf中使用“ -b --branch-history”时,基本的块循环列会消失。我不知道为什么。
这是我的代码中被采样的部分(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>
答案 0 :(得分:2)
在Zulan的回答之外,我将尝试重申并添加更多信息。
最后分支记录(LBR)允许在可执行文件中查找热执行路径,以直接检查它们的优化机会。在性能方面,这是通过扩展调用堆栈显示机制并将最后的基本块添加到调用堆栈中来实现的,该堆栈通常用于显示函数调用的最常见层次结构。
这可以通过在perf记录中使用调用图(-g)和LBR(-b)选项以及在perf中使用-branch-history 选项来完成报告,它将最后的分支信息添加到调用图。本质上,它为8-32分支提供了某些发生原因的额外上下文。
最近perf
版中的定时LBR 功能报告了每个基本块的平均周期数。
什么是迭代?
据我了解,分支历史代码具有循环检测功能。这使我们可以通过计算removed loops的数量来获得迭代次数。
仅在perf report
输出中(通过直方图格式显示)通过Linux内核中的前一个commit引入了重复循环的消除。
struct iterations是有用的C结构,用于显示perf report
中的迭代次数。
This是保存迭代次数的位置,以显示在perf report
输出中。从save_iterations
函数内部调用remove_loops
函数。
在解决callchain时将删除循环。
您还可以阅读此commit,它描述了perf report
如何显示在较新的Linux内核版本中引入的迭代和更改的数量。
答案 1 :(得分:1)
我从快速浏览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
记录完整分支跟踪的方法。