Linux c 程序性能分析问题,有大佬能解释一下为何这段代码在 3700x 上很慢,而在 5600x 上很快吗? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Distributions
Ubuntu
Fedora
CentOS
中文资源站
网易开源镜像站
kgdb00
V2EX    Linux

Linux c 程序性能分析问题,有大佬能解释一下为何这段代码在 700x 上很慢,而在 5600x 上很快吗?

  •  
  •   kgdb00 2022-04-06 15:39:46 +08:00 6100 次点击
    这是一个创建于 1287 天前的主题,其中的信息可能已经有所发展或是发生改变。
    // 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 。

    33 条回复    2022-04-07 09:34:28 +08:00
    kgdb00
        1
    kgdb00  
    OP
       2022-04-06 15:51:24 +08:00
    使用"sysbench cpu run"得到的是同样的结果,5600x 上的性能要远高于 3700x 。
    booboo
        2
    booboo  
       2022-04-06 15:55:39 +08:00   1
    是否确保编译出来的程序是一样(汇编代码比较),再就是你用了 sqrt 是动态链接的话库是否一致,操作系统版本和编译项是否一样。
    一般性能差这么大,大概率是缓存引起的。
    Huelse
        3
    Huelse  
       2022-04-06 16:00:26 +08:00
    据我所知,锐龙 5000 系列是新架构,三缓利用效率对比前几代提升很大,也就是单核性能很强

    你都是 long long 类型的,占用比较大,此时三缓越快越明显
    askonly
        4
    askonly  
       2022-04-06 16:02:44 +08:00
    @booboo 感谢回复,编译出的程序是一样的,都是在 fedora 35 系统上,而且用 fedora 35 的 sysbench 也是这样的差距。
    kgdb00
        5
    kgdb00  
    OP
       2022-04-06 16:03:59 +08:00
    @booboo 感谢回复,编译出的程序是一样的,都是在 fedora 35 系统上,而且用 fedora 35 的 sysbench 也是这样的差距。刚才不小心用小号回复了。
    icyalala
        6
    icyalala  
       2022-04-06 16:15:30 +08:00
    先把 branches, branch-misses, L1-dcache-loads, L1-dcache-load-misse 都打出来看看。
    这段代码没什么访存压力,无非是 sqrt 里面可能有些查表操作,warmup 后应该都在 L1 内。
    排除编译差别,我感觉更可能是分支预测器表现不同,但还是要看 perf 输出结果。
    jdjingdian
        7
    jdjingdian  
       2022-04-06 16:25:29 +08:00
    不懂性能分析,但是 3700x 是 zen2 ,5600x 是 zen3 ,5600x 单核性能高出 3700x 一大截
    kgdb00
        8
    kgdb00  
    OP
       2022-04-06 16:25:41 +08:00
    @icyalala
    在 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
    ```
    kgdb00
        9
    kgdb00  
    OP
       2022-04-06 16:27:28 +08:00
    @kgdb00 #8 v 站的回复不能用 markdown 格式化
    choury
        10
    choury  
       2022-04-06 16:38:26 +08:00
    从 stalled-cycles-backend 上看,是浮点数性能差异比较大
    icyalala
        11
    icyalala  
       2022-04-06 17:13:32 +08:00
    分支预测没什么太大差距。
    如果同楼上浮点数性能差异的话,那就把其他都去掉,只测一下 sqrt() 看看,还有 fp 转 int 也可以单独测一下。
    看了下 agner.org 的描述,Zen3 对 FP 单元提升挺大。
    kgdb00
        12
    kgdb00  
    OP
       2022-04-06 17:44:52 +08:00
    @choury @icyalala 我觉得应该跟浮点数性能没关系,我把 if (c % l == 0) 这一行去掉,3700x 的 ipc 还反超了 5600x 。

    而且我用 perf annotate 分析 ,if (c % l == 0) 这一行的汇编指令有一条 mov %rdx,%rax 在 3700X 上占了 81%的时间,在 5600x 上也占了 54%的时间。

    有没有什么办法让 perf record 的输出能在另一台机上分析?我发现拷贝 perf.data 到另一台机就不能 annotate 了,所以也没法共享给各位分析。
    BrettD
        13
    BrettD  
       2022-04-06 17:49:41 +08:00 via iPad
    把完整的 annotated assembly 贴出来?
    kgdb00
        14
    kgdb00  
    OP
       2022-04-06 17:58:12 +08:00
    kgdb00
        15
    kgdb00  
    OP
       2022-04-06 18:00:20 +08:00
    3700X:
    [Imgur]( )

    5600X:

    [Imgur]( )
    secondwtq
        16
    secondwtq  
       2022-04-06 18:37:44 +08:00
    这问题在这扯过了 https://v2ex.com/t/828141
    BrettD
        17
    BrettD  
       2022-04-06 18:38:57 +08:00
    > 而且我用 perf annotate 分析 ,if (c % l == 0) 这一行的汇编指令有一条 mov %rdx,%rax 在 3700X 上占了 81%的时间,在 5600x 上也占了 54%的时间。

    我觉得热点显示的 mov %rdx,%rax 这一行是在等上一条 divq 指令的 rdx 余数结果出来,然后 3700X 的整数除法运算可能比 5600X 慢,所以

    > 把 if (c % l == 0) 这一行去掉,3700x 的 ipc 还反超了 5600x 。
    secondwtq
        18
    secondwtq  
       2022-04-06 18:54:23 +08:00
    @BrettD
    > 我觉得热点显示的 mov %rdx,%rax 这一行是在等上一条 divq 指令的 rdx 余数结果出来

    这是数据采集机制导致的误差,关键词 "skid"
    choury
        19
    choury  
       2022-04-06 22:17:41 +08:00 via Android
    为什么不是编绎好的同一份二进制在两台机器上测呢,你这逻辑都不一样,测鬼呢
    kgdb00
        20
    kgdb00  
    OP
       2022-04-06 22:38:38 +08:00
    @choury 你为什么会认为我在两台机器上测的不是同一个二进制文件?
    mayli
        21
    mayli  
       2022-04-06 23:19:20 +08:00 via Android
    3700x 的 cycle 明显比 5600x 多,大概 3x 的样子
    我感觉是某个指令上 3700x 需要的 cycle 多,可以把这里面的指令拆开分别做 microbenchmark 看看具体是哪个指令慢多少。
    kgdb00
        22
    kgdb00  
    OP
       2022-04-06 23:45:25 +08:00
    @mayli 我觉得不是某个指令慢导致的,你可以看一下我在 12 楼的回复。
    c0xt30a
        23
    c0xt30a  
       2022-04-06 23:54:49 +08:00
    OP 的系统环境硬件配置是什么样子的?还有编译选项能否分享一下?
    BrettD
        24
    BrettD  
       2022-04-07 01:02:49 +08:00   1
    @kgdb00 上面说了呀,建议排查 divq 指令在 Zen2 和 Zen3 之间的延迟区别
    mayli
        25
    mayli  
       2022-04-07 01:12:43 +08:00 via Android
    @kgdb00 如果是 if 这个引发的话 那就是两个 cpu 分支预测成功率不一样 不过这种情况比较罕见,现代 cpu 预测一般都差不多,而且从 perf 看 也是的确差不多
    owwlo
        26
    owwlo  
       2022-04-07 02:07:49 +08:00 via iPhone
    有可能是 vulnerability mitigation 导致的么(但是差别不应该这么大)…楼主查过 lscpu 有没有 mitigation 吗?
    nlzy
        27
    nlzy  
       2022-04-07 02:14:22 +08:00   17
    看了眼源码,是用试除法计算素数。那汇编都不用细看了,只要编译器不作妖,程序的瓶颈肯定是 l <= t 和 if (c % l == 0) 这两句。和缓存、访存关系都不大了。

    虽然有一个 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 ,寄存器重命名阶段就已经处理掉了,不会是瓶颈。

    (唉,我为什么要大半夜不睡觉去分析这种编译器优化都没开,代码也没有仔细写的程序呢)
    mayli
        28
    mayli  
       2022-04-07 02:19:45 +08:00 via Android
    @nlzy 破案了?
    kgdb00
        29
    kgdb00  
    OP
       2022-04-07 03:03:32 +08:00
    @nlzy 感谢回复,我也是大半夜不睡觉,编译器优化是故意关掉的,开了 O3 优化差距一样大。你这一大堆解释我得等有空了再验证吸收一下,另外这代码是取自 sysbench ,我也不管它有啥意义,只是想搞明白性能为啥有差别。
    LeeReamond
        30
    LeeReamond  
       2022-04-07 03:04:14 +08:00
    @nlzy 大佬怎么判断瓶颈的,为什么文 for 中的<不是瓶颈,而下文 for 中的<=是瓶颈呢
    weyou
        31
    weyou  
       2022-04-07 09:04:25 +08:00 via Android
    @LeeReamond 前面的 for 是整型比较,后面的 for 需要是转浮点数比较,涉及浮点运算
    secondwtq
        32
    secondwtq  
       2022-04-07 09:13:51 +08:00
    @weyou 是因为大多数数都不是素数,所以外层循环的几乎每个 iteration ,内层循环都要跑大约 sqrt(c) 次,外层循环占得可能不到 1%。
    nlzy
        33
    nlzy  
       2022-04-07 09:34:28 +08:00 via Android
    @LeeReamond 外层循环的运行次数肯定少于内层循环。这也是没考虑 sqrt() 对性能的影响的原因,它们的运行次数都远远少于那两个表达式。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5606 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 34ms UTC 08:10 PVG 16:10 LAX 01:10 JFK 04:10
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86