Linux c 程序性能分析问题,有大佬能解释一下为何这段代码在 3700x 上很慢,而在 5600...
source link: https://www.v2ex.com/t/845257
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Linux c 程序性能分析问题,有大佬能解释一下为何这段代码在 3700x 上很慢,而在 5600x 上很快吗?
kgdb00 · 11 小时 35 分钟前 · 1513 次点击// cpu-test.c
#include <math.h>
int main(int argc, char *argv[])
{
unsigned long long c;
unsigned long long l;
double t;
for (c = 3; c < 1000000; c++) {
t = sqrt((double) c);
for (l = 2; l <= t; l++)
if (c % l == 0)
break;
}
return 0;
}
这段代码取自 sysbench ,略有删减,原函数是:
https://github.com/akopytov/sysbench/blob/master/src/tests/cpu/sb_cpu.c 的 cpu_execute_event 函数。
使用"perf stat ./cpu-test"在 3700x 上得到的 IPC 是 0.83 ,而在 5600X 上得到的是 2.23 。
kgdb00 11 小时 23 分钟前
booboo 11 小时 19 分钟前 1
一般性能差这么大,大概率是缓存引起的。
Huelse 11 小时 14 分钟前
你都是 long long 类型的,占用比较大,此时三缓越快越明显
kgdb00 11 小时 10 分钟前
icyalala 10 小时 59 分钟前
这段代码没什么访存压力,无非是 sqrt 里面可能有些查表操作,warmup 后应该都在 L1 内。
排除编译差别,我感觉更可能是分支预测器表现不同,但还是要看 perf 输出结果。
jdjingdian 10 小时 49 分钟前
kgdb00 10 小时 49 分钟前
在 3700x 上运行"perf stat ./cpu-test"结果如下:
```
root@develop:~/test# perf stat ./cpu-test
Performance counter stats for './cpu-test':
313.31 msec task-clock # 0.999 CPUs utilized
0 context-switches # 0.000 /sec
0 cpu-migrations # 0.000 /sec
62 page-faults # 197.886 /sec
1,334,724,216 cycles # 4.260 GHz
4,152,400 stalled-cycles-frontend # 0.31% frontend cycles idle
1,084,407,060 stalled-cycles-backend # 81.25% backend cycles idle
1,112,064,247 instructions # 0.83 insn per cycle
# 0.98 stalled cycles per insn
280,732,961 branches # 896.020 M/sec
479,493 branch-misses # 0.17% of all branches
0.313649907 seconds time elapsed
0.313436000 seconds user
0.000000000 seconds sys
```
5600x 上结果如下:
```
d@desktop:~/test$ perf stat ./cpu-test
Performance counter stats for './cpu-test':
109.50 msec task-clock:u # 0.997 CPUs utilized
0 context-switches:u # 0.000 /sec
0 cpu-migrations:u # 0.000 /sec
57 page-faults:u # 520.552 /sec
497,192,700 cycles:u # 4.541 GHz
1,236,868 stalled-cycles-frontend:u # 0.25% frontend cycles idle
3,047 stalled-cycles-backend:u # 0.00% backend cycles idle
1,109,781,743 instructions:u # 2.23 insn per cycle
# 0.00 stalled cycles per insn
280,305,908 branches:u # 2.560 G/sec
420,708 branch-misses:u # 0.15% of all branches
0.109816486 seconds time elapsed
0.108714000 seconds user
0.000997000 seconds sys
```
choury 10 小时 36 分钟前
icyalala 10 小时 1 分钟前
如果同楼上浮点数性能差异的话,那就把其他都去掉,只测一下 sqrt() 看看,还有 fp 转 int 也可以单独测一下。
看了下 agner.org 的描述,Zen3 对 FP 单元提升挺大。
kgdb00 9 小时 29 分钟前
BrettD 9 小时 25 分钟前 via iPad
kgdb00 9 小时 14 分钟前
[Imgur]( )
5600X:
[Imgur]( )
BrettD 8 小时 35 分钟前
我觉得热点显示的 mov %rdx,%rax 这一行是在等上一条 divq 指令的 rdx 余数结果出来,然后 3700X 的整数除法运算可能比 5600X 慢,所以
> 把 if (c % l == 0) 这一行去掉,3700x 的 ipc 还反超了 5600x 。
secondwtq 8 小时 20 分钟前
choury 4 小时 57 分钟前 via Android
mayli 3 小时 55 分钟前 via Android
我感觉是某个指令上 3700x 需要的 cycle 多,可以把这里面的指令拆开分别做 microbenchmark 看看具体是哪个指令慢多少。
c0xt30a 3 小时 19 分钟前
mayli 2 小时 2 分钟前 via Android
owwlo 1 小时 6 分钟前 via iPhone
nlzy 1 小时 0 分钟前 5
虽然有一个 if ,但是这个分支比较好预测:即使是静态预测,每个不同的 c 也只会预测失败一次,所以和分支也没什么关系。循环条件同理。
同一个 c 的每一轮试除,l 是循环变量,而 c 和 t 是不变的,所以上述良好的分支预测再加上投机执行,是可以掩盖掉他们的延迟的,所以程序的瓶颈大概就是 l <= t 和 c % l 这两句的吞吐了。前者是整型转浮点然后比较,后者是一个除法。
上网查资料,zen2 的 div 吞吐率倒数是 13-44 ,zen3 是 7-12 。而 cvtsi2sd 和 comisd 在 zen2 和 zen3 上都是 1 。瓶颈在前者,后者可以忽略掉,而前者在 zen2 和 zen3 的性能差距正好大约是三倍。(浮点和整数除法的执行单元应该不冲突吧)
这大概就是楼主想要的答案了。
至于 mov %rdx, %rax ,寄存器重命名阶段就已经处理掉了,不会是瓶颈。
(唉,我为什么要大半夜不睡觉去分析这种编译器优化都没开,代码也没有仔细写的程序呢)
kgdb00 11 分钟前
LeeReamond 10 分钟前
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK