关于嵌套函数的性能最高结果
perf top result about nested functions
我们使用 perf top
来展示 CPU 的用法。结果显示两个函数
samples pcnt function
------ ---- ---------
... ... ....
12617.00 6.8% func_outside
8691.00 4.7% func_inside
.....
其实这两个函数是这样嵌套的,而且总是1对1嵌套。
func_outside() {
....
func_inside()
...
}
我是否应该得出结论,在 perf top
结果中,4.7% 实际上已经包含在 6.8% 中。如果排除 func_inside 的成本,func_outside 的成本是 2.1% (6.8-4.7)?
简答
没有报告的每个百分比仅针对该特定功能。所以 func_inside
个样本不计入 func_outside
详情
perf
的工作方式是定期收集性能样本。默认情况下 perf top
只是检查当前哪个函数 运行 然后将其添加到该函数的样本计数中。
我很确定是这种情况,但想验证 perf top
显示结果的方式,所以我编写了一个快速测试程序来测试其行为。这个程序有两个有趣的函数 outer
和 inner
。 outer
函数在循环中调用 inner
,inner
所做的工作量由参数控制。编译时一定要使用 O0 以避免内联。命令行参数控制两个函数之间的工作比例。
运行参数./a.out 1 1 1000000000
给出结果:
49.20% a.out [.] outer
23.69% a.out [.] main
21.32% a.out [.] inner
运行参数./a.out 1 10 1000000000
给出结果:
66.06% a.out [.] inner
17.77% a.out [.] outer
9.50% a.out [.] main
运行参数./a.out 1 100 1000000000
给出结果:
88.53% a.out [.] inner
2.85% a.out [.] outer
1.09% a.out [.] main
如果 inner
的计数包含在 outer
中,则 outer
的运行时间百分比将始终高于 inner
。但正如这些结果所表明的那样,情况并非如此。
下面是我用的测试程序,是用gcc -O0 -g --std=c11 test.c
.
编译的
#include <stdlib.h>
#include <stdio.h>
long inner(int count) {
long sum = 0;
for(int i = 0; i < count; i++) {
sum += i;
}
return sum;
}
long outer(int count_out, int count_in) {
long sum = 0;
for(int i = 0; i < count_out; i++) {
sum += inner(count_in);
}
return sum;
}
int main(int argc, char **argv) {
if(argc < 4) {
printf("Usage: %s <outer_cnt> <inner_cnt> <loop>\n",argv[0]);
exit(-1);
}
int outer_cnt = atoi(argv[1]);
int inner_cnt = atoi(argv[2]);
int loops = atoi(argv[3]);
long res = 0;
for(int i = 0; i < loops; i++) {
res += outer(outer_cnt, inner_cnt);
}
printf("res is %ld\n", res);
return 0;
}
我们使用 perf top
来展示 CPU 的用法。结果显示两个函数
samples pcnt function
------ ---- ---------
... ... ....
12617.00 6.8% func_outside
8691.00 4.7% func_inside
.....
其实这两个函数是这样嵌套的,而且总是1对1嵌套。
func_outside() {
....
func_inside()
...
}
我是否应该得出结论,在 perf top
结果中,4.7% 实际上已经包含在 6.8% 中。如果排除 func_inside 的成本,func_outside 的成本是 2.1% (6.8-4.7)?
简答
没有报告的每个百分比仅针对该特定功能。所以 func_inside
个样本不计入 func_outside
详情
perf
的工作方式是定期收集性能样本。默认情况下 perf top
只是检查当前哪个函数 运行 然后将其添加到该函数的样本计数中。
我很确定是这种情况,但想验证 perf top
显示结果的方式,所以我编写了一个快速测试程序来测试其行为。这个程序有两个有趣的函数 outer
和 inner
。 outer
函数在循环中调用 inner
,inner
所做的工作量由参数控制。编译时一定要使用 O0 以避免内联。命令行参数控制两个函数之间的工作比例。
运行参数./a.out 1 1 1000000000
给出结果:
49.20% a.out [.] outer
23.69% a.out [.] main
21.32% a.out [.] inner
运行参数./a.out 1 10 1000000000
给出结果:
66.06% a.out [.] inner
17.77% a.out [.] outer
9.50% a.out [.] main
运行参数./a.out 1 100 1000000000
给出结果:
88.53% a.out [.] inner
2.85% a.out [.] outer
1.09% a.out [.] main
如果 inner
的计数包含在 outer
中,则 outer
的运行时间百分比将始终高于 inner
。但正如这些结果所表明的那样,情况并非如此。
下面是我用的测试程序,是用gcc -O0 -g --std=c11 test.c
.
#include <stdlib.h>
#include <stdio.h>
long inner(int count) {
long sum = 0;
for(int i = 0; i < count; i++) {
sum += i;
}
return sum;
}
long outer(int count_out, int count_in) {
long sum = 0;
for(int i = 0; i < count_out; i++) {
sum += inner(count_in);
}
return sum;
}
int main(int argc, char **argv) {
if(argc < 4) {
printf("Usage: %s <outer_cnt> <inner_cnt> <loop>\n",argv[0]);
exit(-1);
}
int outer_cnt = atoi(argv[1]);
int inner_cnt = atoi(argv[2]);
int loops = atoi(argv[3]);
long res = 0;
for(int i = 0; i < loops; i++) {
res += outer(outer_cnt, inner_cnt);
}
printf("res is %ld\n", res);
return 0;
}