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

Iwi*_*ist 54 c c++ performance assembly iaca

我发现了这个有趣且功能强大的工具IACA(英特尔架构代码分析器),但我无法理解它.我能用它做什么,它的局限性是什么?我该怎么做:

  • 用它来分析C或C++中的代码?
  • 用它来分析x86汇编程序中的代码?

Iwi*_*ist 68

2017-11:3.0版本发布(2017-11-03最新)

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++

在C和C++中,可以访问标记注入宏#include "iacaMarks.h",其中iacaMarks.h包含include/子目录中工具附带的标头.

然后,将标记插入感兴趣的最内圈或感兴趣的直线块周围,如下所示:

/* C or C++ usage of IACA */

while(cond){
    IACA_START
    /* Loop body */
    /* ... */
}
IACA_END
Run Code Online (Sandbox Code Playgroud)

然后重建应用程序,否则将启用优化(在Visual Studio等IDE用户的发布模式下).输出是二进制文件,除了存在标记之外,在所有方面都与Release版本相同,这使得应用程序不可运行.

IACA依赖于编译器不会过度重新排序标记; 因此,对于此类分析,如果对标记重新排序以包括不在最内层循环内的无关代码或排除其中的代码,则可能需要禁用某些强大的优化.

装配(x86)

IACA的标记是在代码中的正确位置注入的魔术字节模式.当使用iacaMarks.h在C或C++中,编译器手柄插入在正确的位置由标头中指定的魔术字节.但是,在装配中,您必须手动插入这些标记.因此,必须做到以下几点:

    ; 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
Run Code Online (Sandbox Code Playgroud)

对于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
Run Code Online (Sandbox Code Playgroud)

我们在.L2标签开始标记之前立即添加,jne在结束标记之后立即添加.然后我们重建软件,然后调用IACA(在Linux上,假定bin/目录在路径中,并且foo是包含IACA标记的ELF64对象):

iaca.sh -64 -arch HSW -graph insndeps.dot foo
Run Code Online (Sandbox Code Playgroud)

从而foo在Haswell处理器上运行时生成64位二进制文​​件的分析报告,以及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
Run Code Online (Sandbox Code Playgroud)

该工具有助于指出,目前,瓶颈是Haswell前端和Port 2和3的AGU.此示例允许我们将问题诊断为端口7未处理存储,并采取补救措施.

限制:

IACA不支持某些指令,这些指令在分析中被忽略.它不支持比Nehalem更早的处理器,并且不支持吞吐量模式中的非最内层循环(无法猜测采用哪种分支的频率和模式).

  • IACA是否要求您拥有硬件?我的意思是你可以编译为例如fma3并在仅具有SSE2的core2系统上使用IACA进行测试吗?与此相反.如果我想测试SSE2,我可以使用Haswell系统执行此操作吗?如果IACA读取计数器我不认为这是可能的.但由于IACA不需要root/admin,我认为这意味着它不需要硬件. (4认同)
  • @Zboson它不需要硬件; 它是一个静态分析工具,因此从未实际运行代码.唯一真正的要求是分析二进制; 您甚至无需运行所述二进制文件来分析它.实际上,由于注入的标记,待分析的二进制文件无法正常运行. (4认同)
  • @halivingston现代英特尔CPU不仅仅是_pipelined_(在完成的不同阶段同时执行多个指令的概念),而且_superscalar_(在完成的同一阶段执行多个指令的概念).然后,英特尔处理器获取的(多个)指令被解码为0+微操作,并且这些指令被分派到能够处理它们的端口.经过良好调整的代码可确保所使用的指令均匀地使端口饱和,因此所有这些都是高效的. (3认同)
  • 你不是在听我在说什么.我在看`iacaMarks.h`!您正在引用适用于C/C++的定义.这对NASM无效.看看标题的结尾.有一个注释块启动"/****************asm*****************"块中的汇编代码是你用于NASM的. (2认同)
  • 有趣的工具: - }我有一个内部汇编程序块,其中一些内部分支有*两个*退出.我将开始标记放在顶部,并在*两个*出口上结束标记.当我运行它(它工作!很好!)它选择两个出口中的一个*并向我显示所选路径的结果.a)它似乎在块内拾取有条件但很少执行的代码; 如何让它忽略它,以及b)如何分析这两条路径?(我即将尝试删除一个分支上的标记,但担心该工具将跟随该分支进入它导致的无限代码供应...... (2认同)
  • 仅供参考,英特尔再次对此进行了更新.v2.3(2017年3月发布)增加了对Skylake和AVX-512的支持.他们还增加了对"跟踪处理器内部不同操作阶段的深入信息"的支持.他们确切地解释了新文档中的含义. (2认同)
  • @IwillnotexistIdonotexist 有一个新版本:v3.0。它仅支持第 4 至第 6 代处理器(Haswell、Broadwell、Skylake)。跟踪功能更强大。 (2认同)
  • 另一种选择:[OSACA](https://github.com/RRZE-HPC/OSACA) (2认同)