作者:方家菱芝合 | 来源:互联网 | 2022-12-06 17:49
我有一个在支持AVX-512的Intel机器上运行的进程,但是这个进程不直接使用任何AVX-512指令(asm或内在函数)并且编译时-mno-avx512f
使编译器不插入任何AVX-512指令.
然而,它在减少的AVX turbo频率下无限运行.毫无疑问,有一个AVX-512指令在某个地方偷偷摸摸,通过一个库,(非常不可能)系统调用或类似的东西.
而不是尝试"二进制搜索"AVX-512指令来自哪里,有没有什么方法可以立即找到它,例如,捕获这样的指令?
操作系统是Ubuntu 16.04.
1> Jérôme Pouil..:
正如评论中所建议的那样,您可以搜索系统的所有ELF文件并进行反汇编,以检查它们是否使用AVX-512指令:
$ objdump -d /lib64/ld-linux-x86-64.so.2 | grep %zmm0
14922: 62 f1 fd 48 7f 44 24 vmovdqa64 %zmm0,0xc0(%rsp)
14a2d: 62 f1 fd 48 6f 44 24 vmovdqa64 0xc0(%rsp),%zmm0
14c2c: 62 f1 fd 48 7f 81 50 vmovdqa64 %zmm0,0x50(%rcx)
14ca0: 62 f1 fd 48 6f 84 24 vmovdqa64 0x50(%rsp),%zmm0
(BTW,libc和ld.so确实包括AVX-512指令,它们不是你要找的那些?)
但是,你可能会发现你甚至没有执行的二进制文件和动态未压缩的代码等等...
如果你对进程有疑问(因为perf
报告CORE_POWER.LVL*_TURBO_LICENSE
事件),我建议生成一个核心转储,如果这个进程并反汇编它(注意第一行也允许转储代码):
$ echo 0xFF > /proc//coredump_filter
$ gdb --pid=
[...]
(gdb) gcore
Saved corefile core.19602
(gdb) quit
Detaching from program: ..., process ...
$ objdump -d core.19602 | grep %zmm0
7f73db8187cb: 62 f1 7c 48 10 06 vmovups (%rsi),%zmm0
7f73db818802: 62 f1 7c 48 11 07 vmovups %zmm0,(%rdi)
7f73db81883f: 62 f1 7c 48 10 06 vmovups (%rsi),%zmm0
[...]
接下来,您可以轻松编写一个小的python脚本,在每个AVX-512指令上添加断点(或跟踪点).就像是
(gdb) python
>import os
>with os.popen('objdump -d core.19602 | grep %zmm0 | cut -f1 -d:') as pipe:
> for line in pipe:
> gdb.Breakpoint("*" + line)
当然它会创建数百(或数千)个断点.但是,断点的开销足够小,gdb可以支持它(我认为每个断点的<1kB).
另一种方法是在虚拟机中运行代码.特别是,我建议使用libvex.libvex用于动态检测代码(内存泄漏,内存分析等).libvex解释机器代码,将其转换为中间表示并重新编码机器代码以执行CPU.使用libvex的最着名的项目是valgrind(公平地说,libvex是valgrind的后端).
因此,您可以使用libvex运行应用程序,而无需任何检测:
$ valgrind --tool=none YOUR_APP
现在你必须围绕libvex编写一个工具来检测AVX-512的使用情况.但是,libVEX还没有(还)支持AVX-512.因此,只要它必须执行AVX-512指令,它就会因非法指令而失败.
$ valgrind --tool=none YOUR_APP
[...]
vex amd64->IR: unhandled instruction bytes: 0x62 0xF1 0xFD 0x48 0x28 0x84 0x24 0x8 0x1 0x0
vex amd64->IR: REX=0 REX.W=0 REX.R=0 REX.X=0 REX.B=0
vex amd64->IR: VEX=0 VEX.L=0 VEX.nVVVV=0x0 ESC=NONE
vex amd64->IR: PFX.66=0 PFX.F2=0 PFX.F3=0
==20061== valgrind: Unrecognised instruction at address 0x10913e.
==20061== at 0x10913E: main (in ...)
==20061== Your program just tried to execute an instruction that Valgrind
==20061== did not recognise. There are two possible reasons for this.
==20061== 1. Your program has a bug and erroneously jumped to a non-code
==20061== location. If you are running Memcheck and you just saw a
==20061== warning about a bad jump, it's probably your program's fault.
==20061== 2. The instruction is legitimate but Valgrind doesn't handle it,
==20061== i.e. it's Valgrind's fault. If you think this is the case or
==20061== you are not sure, please let us know and we'll try to fix it.
==20061== Either way, Valgrind will now raise a SIGILL signal which will
==20061== probably kill your program.
==20061==
==20061== Process terminating with default action of signal 4 (SIGILL)
==20061== Illegal opcode at address 0x10913E
==20061== at 0x10913E: main (in ...)
==20061==
注意:此答案已经过测试:
#include
int main(int argc, char *argv[]) {
__m512d a, b, c;
_mm512_fnmadd_pd(a, b, c);
}