作者mshockwave (夏克维夫)
看板CompilerDev
标题Re: [问题] 为何这两份程式码的效能差异如此奇特
时间Mon May 16 11:08:56 2022
※ 引述《shane87123 (阳光大肥宅)》之铭言:
: 由於我是在 LLVM IR 最佳化阶段发现这个问题,
: 跟编译器最佳化有关,所以我发在这个版上。
: 这个问题困扰我很久了,想和版上的大大讨论一番。
: 由於 LLVM IR 比较难读,所以我把程式逆推成 C code 来增加可读性。
: 先附上两份程式码的线上 diff:
: https://www.diffchecker.com/Thbx9sDk
: 然後进行这样编译:
: opt -S -passes=mem2reg more.ll -o more.ll
: opt -S -passes=mem2reg less.ll -o less.ll
: llc more.ll
: llc less.ll
: ( llc 预设 O2)
: 得到两份组合语言。线上 diff 如下:
: https://www.diffchecker.com/NV4uuopa
: (可以直接拉到左方组语 85 行 if.end 那里)
: 其实可以发现,左边那份程式码(姑且称之 less.c)先将 foo(rem % 5) 存起来,
: 只计算了 rem % 5 一次、call foo 一次;
: 右边的程式码(more.c) foo(rem % 5) 计算两次,也就是说 rem % 5 两次、call foo 两次,
: 比左边的程式码多一次。
: 理论上,应该要比较慢才对,但我用 Linux Perf 跑过一万次发现,
: 多计算 rem % 5 和 call foo 的反而比较快。
我其实比较好奇这个「比较快」是快几趴?
因为其实通常差距低於2%我会直接认为是噪音
: perf 中,我可以得知 instruction 数量、cycles 数量等等
: instruction 数量中,less.c 比 more.c 还要少,不过这是可以预料的,
: 毕竟人家就是比他少做运算跟呼叫函数;
: 然而在 "insn per cycle" 则直接输给了 more.c,导致实际 cycles 数量 less.c 比 more.c
: 还要多,
: 也当然执行时间比较长,但我实在是不明白原因为何。
: 目前的实验做到以下:
: 1. llc 用 O0 最佳化 -> less.c 比 more.c 更快
: -> 表示 llc 的 O2 对 more.c 那份程式码有更好的最佳化?
: 但很没道理,明明多 call 了 function 也多计算了取余数运算,怎麽会比较快?
: 2. 观察 foo(rem % 5) 的参数 "rem % 5" 值为多少,发现都是 0
: -> 也就是说,多 call 的 function 都只是进入 function 直接回传 1
: -> 把该参数改成非 0 则 less.c 比 more.c 更快。
: 但不管如何,还是多呼叫 function 了呀,没道理参数影响这麽多,
: program counter 跳来跳去,一定会比较慢吧?
: 这问题虽然很实务,但真的很玄,而且困扰我很久。
: 我的老板(现为硕士生)要我把原因找出来,但我找了一整天,实在是想不到原因。
: 希望有高手能够帮帮我,拜托了...
我刚刚用 MCA 跑了一下 但没有分析整个main而是只有while loop body
(如果是less的话是 line 63 ~ 97, more 的话是 line 74 ~ 105)
然後用这个command: llvm-mca -mcpu=skylake -iterations=10000 ...
(我猜你也是在 Skylake 上)
这是 less 的summary:
Iterations: 10000
Instructions: 240000
Total Cycles: 1110005
Total uOps: 920000
Dispatch Width: 6
uOps Per Cycle: 0.83
IPC: 0.22
Block RThroughput: 15.3
而这是 more 的summary:
Iterations: 10000
Instructions: 270000
Total Cycles: 1150003
Total uOps: 990000
Dispatch Width: 6
uOps Per Cycle: 0.86
IPC: 0.23
Block RThroughput: 16.5
IPC 的确比较低,但是老实讲差距很小。另外cycle数上less也没有比较高
虽然这是MCA而不是perf就对了
但我认同你说的关於data dependency所造成的 register pressure的理论
既便实务上我实在不觉得它会变成很严重的问题
证据之一就是 MCA 的 bottleneck analysis 也説 data dependency hazard
的比例还蛮低的:
less:
Data Dependencies: [ 0.90% ]
- Register Dependencies [ 0.90% ]
- Memory Dependencies [ 0.00% ]
more:
Data Dependencies: [ 0.87% ]
- Register Dependencies [ 0.87% ]
- Memory Dependencies [ 0.00% ]
两者相距甚至不到 0.1%
就像前面提过的,遇到这种事情我通常会先问自己:这个问题的scale到底多大?
如果不到2%或甚至不到1%通常我会再三思考该不该把时间花在这上面
别说学术界了,在产业界如果你的performance regression不到5%甚至10%
有些老板甚至不会同意你的效能优化计画
话说既然这边讨论到LLVM MCA,在刚刚结束的 EuroLLVM 2022 本鲁其实是第一天的
keynote speaker
(
https://llvm.swoogo.com/2022eurollvm/agenda)
然後主题就是介绍一个新的、基於LLVM MCA 的工具: MCA Daemon (MCAD)
演讲的录影大概要再几个月才会上传 但如果有兴趣的话这边是投影片:
https://tinyurl.com/bdhtsuvk
--
※ 发信站: 批踢踢实业坊(ptt.cc), 来自: 169.234.228.237 (美国)
※ 文章网址: https://webptt.com/cn.aspx?n=bbs/CompilerDev/M.1652670539.A.991.html
1F:推 sorcerer1973: 编译不死 05/27 17:19
2F:推 hpo14: 给推 12/06 19:33
3F:推 KevinR: 推 01/14 06:15