我发现了一个有趣而强大的工具,叫做IACA(英特尔体系结构代码分析器),但是我很难理解它。我可以用它做什么?它有什么限制?我该如何:
- 使用它分析C或C++代码?
- 使用它分析x86汇编代码?
我发现了一个有趣而强大的工具,叫做IACA(英特尔体系结构代码分析器),但是我很难理解它。我可以用它做什么?它有什么限制?我该如何:
2019年4月: 已到达EOL(生命周期结束)。 建议使用替代方案: LLVM-MCA
2017年11月: 发布3.0版(截至2019年5月18日最新版本)
2017年03月: 发布2.3版
IACA(英特尔体系结构代码分析器)是一款免费的闭源静态分析工具,由英特尔制作,用于静态分析现代英特尔处理器执行指令的调度。这使得它能够计算给定代码片段的性能瓶颈。
假设执行条件最佳(所有内存访问都命中L1缓存,并且没有页面故障)。
IACA支持Nehalem、Westmere、Sandy Bridge、Ivy Bridge、Haswell、Broadwell和Skylake处理器的计算调度,版本2.3支持Haswell、Broadwell和Skylake,版本3.0支持。
IACA是一个命令行工具,可生成ASCII文本报告和Graphviz图表。版本2.1及以下支持32位和64位Linux、Mac OS X和Windows以及32位和64位代码分析;版本2.2及更高版本仅支持64位操作系统和64位代码分析。
/* C or C++ usage of IACA */
while(cond){
IACA_START
/* Loop body */
/* ... */
}
IACA_END
该应用程序随后会以启用优化的方式进行重建(对于使用Visual Studio等IDE的用户来说,是在发布模式下)。输出是一个二进制文件,除了存在标记使得应用程序无法运行外,在所有方面都与发布版本相同。
IACA依赖于编译器不会过度重新排序这些标记;因此,在进行此类分析构建时,如果这些优化会重新排序标记以包括不在最内层循环中的多余代码或排除其中的代码,则需要禁用某些强大的优化。
IACA的标记是魔术字节模式,注入到代码的正确位置。在C或C ++中使用iacaMarks.h时,编译器会处理在正确位置插入头文件指定的魔术字节。然而,在汇编语言中,您必须手动插入这些标记。因此,必须执行以下操作:
; NASM usage of IACA
mov ebx, 111 ; Start marker bytes
db 0x64, 0x67, 0x90 ; Start marker bytes
.innermostlooplabel:
; Loop body
; ...
jne .innermostlooplabel ; Conditional branch backwards to top of loop
mov ebx, 222 ; End marker bytes
db 0x64, 0x67, 0x90 ; End marker bytes
对于C/C++程序员来说,编译器实现相同的模式非常关键。
作为示例,让我们分析在Haswell架构上的以下汇编示例:
.L2:
vmovaps ymm1, [rdi+rax] ;L2
vfmadd231ps ymm1, ymm2, [rsi+rax] ;L2
vmovaps [rdx+rax], ymm1 ; S1
add rax, 32 ; ADD
jne .L2 ; JMP
.L2
标签之前立即添加起始标记,在 jne
之后立即添加结束标记。然后重新构建软件,并像这样调用 IACA(在 Linux 上,假设 bin/
目录在路径中,并且 foo
是包含 IACA 标记的 ELF64 对象):iaca.sh -64 -arch HSW -graph insndeps.dot foo
foo
的分析报告以及可在Graphviz中查看的指令依赖关系图形将被生成。-o
开关将其重定向到文件)。上面片段给出的报告如下:Intel(R) Architecture Code Analyzer Version - 2.1
Analyzed File - ../../../tests_fma
Binary Format - 64Bit
Architecture - HSW
Analysis Type - Throughput
Throughput Analysis Report
--------------------------
Block Throughput: 1.55 Cycles Throughput Bottleneck: FrontEnd, PORT2_AGU, PORT3_AGU
Port Binding In Cycles Per Iteration:
---------------------------------------------------------------------------------------
| Port | 0 - DV | 1 | 2 - D | 3 - D | 4 | 5 | 6 | 7 |
---------------------------------------------------------------------------------------
| Cycles | 0.5 0.0 | 0.5 | 1.5 1.0 | 1.5 1.0 | 1.0 | 0.0 | 1.0 | 0.0 |
---------------------------------------------------------------------------------------
N - port number or number of cycles resource conflict caused delay, DV - Divider pipe (on port 0)
D - Data fetch pipe (on ports 2 and 3), CP - on a critical path
F - Macro Fusion with the previous instruction occurred
* - instruction micro-ops not bound to a port
^ - Micro Fusion happened
# - ESP Tracking sync uop was issued
@ - SSE instruction followed an AVX256 instruction, dozens of cycles penalty is expected
! - instruction not supported, was not accounted in Analysis
| Num Of | Ports pressure in cycles | |
| Uops | 0 - DV | 1 | 2 - D | 3 - D | 4 | 5 | 6 | 7 | |
---------------------------------------------------------------------------------
| 1 | | | 1.0 1.0 | | | | | | CP | vmovaps ymm1, ymmword ptr [rdi+rax*1]
| 2 | 0.5 | 0.5 | | 1.0 1.0 | | | | | CP | vfmadd231ps ymm1, ymm2, ymmword ptr [rsi+rax*1]
| 2 | | | 0.5 | 0.5 | 1.0 | | | | CP | vmovaps ymmword ptr [rdx+rax*1], ymm1
| 1 | | | | | | | 1.0 | | | add rax, 0x20
| 0F | | | | | | | | | | jnz 0xffffffffffffffec
Total Num Of Uops: 6