IACA是什么以及如何使用它?

58

我发现了一个有趣而强大的工具,叫做IACA(英特尔体系结构代码分析器),但是我很难理解它。我可以用它做什么?它有什么限制?我该如何:

  • 使用它分析C或C++代码?
  • 使用它分析x86汇编代码?
1个回答

72

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位代码分析。

如何使用:

IACA的输入是您的代码的已编译二进制文件,其中注入了两个“标记”:一个“起始标记”和一个“结束标记”。这些标记使得代码无法运行,但允许工具快速找到相关的代码片段并分析它们。
您不需要在系统上运行二进制文件;实际上,由于代码中注入的标记存在,提供给IACA的二进制文件无论如何都不能运行。IACA仅需要能够读取要分析的二进制文件。因此,使用IACA可以在Pentium III机器上分析使用FMA指令的Haswell二进制文件。
C和C++中,通过包含“iacaMarks.h”头文件(该头文件随工具一起在“include/”子目录中提供),可以访问注入标记的宏。然后,按照以下方式将标记插入到感兴趣的最内层循环或直线段周围:
/* C or C++ usage of IACA */

while(cond){
    IACA_START
    /* Loop body */
    /* ... */
}
IACA_END

该应用程序随后会以启用优化的方式进行重建(对于使用Visual Studio等IDE的用户来说,是在发布模式下)。输出是一个二进制文件,除了存在标记使得应用程序无法运行外,在所有方面都与发布版本相同。

IACA依赖于编译器不会过度重新排序这些标记;因此,在进行此类分析构建时,如果这些优化会重新排序标记以包括不在最内层循环中的多余代码或排除其中的代码,则需要禁用某些强大的优化。

汇编语言(x86)

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

因此,在Haswell处理器上运行64位二进制文件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

这个工具有助于指出目前瓶颈在于Haswell前端和Port 2以及3的AGU。这个例子让我们发现问题是Port 7没有处理存储,需要采取补救措施。
限制:
IACA不支持某些指令,并在分析中忽略它们。它不支持早于Nehalem的处理器,并且不支持吞吐量模式中的非最内层循环(无法猜测哪个分支被采取多少次以及以什么模式采取)。

4
IACA是否需要硬件支持?比如说,我能否在只有SSE2的Core2系统上编译fma3并使用IACA进行测试?反之亦然。如果我想测试仅支持SSE2的代码,我能在Haswell系统上执行吗?由于IACA读取计数器,所以我认为这是不可能的。但既然IACA不需要root/admin权限,我认为这意味着它不需要硬件支持。 - Z boson
4
@Zboson 这个工具不需要硬件支持;它是一个静态分析工具,因此从未真正运行过代码。唯一真正的要求是有一个可分析的二进制文件;你甚至不需要能够运行该二进制文件就可以进行分析。事实上,要分析的二进制文件无论如何都无法运行,因为其中注入了标记。 - Iwillnotexist Idonotexist
2
有趣的工具 :-} 我有一个带有一些内部分支的内部汇编块,它有两个出口。我将起始标记放在顶部,并在两个出口处放置结束标记。当我运行它(它有效!很好!)时,它会选择其中一个出口并显示所选路径的结果。a) 它似乎捕获了块内条件性但很少执行的代码;如何让它忽略那些代码?b) 如何分析两条路径?(我即将尝试删除一个分支上的标记,但担心该工具会跟随该分支进入无限的代码供应...) - Ira Baxter
3
现代英特尔CPU不仅具有流水线技术(即同时执行多个处于不同完成阶段的指令),还具有超标量技术(即在相同完成阶段同时执行多个指令)。英特尔处理器获取的多个指令被解码成0个或多个微操作,然后被分派到能够处理它们的端口。经过优化的代码确保使用的指令均匀地占用端口,以使所有端口都能发挥作用。 - Iwillnotexist Idonotexist
2
另一个选择:OSACA - como
显示剩余45条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接