Что такое IACA и как его использовать?

Я нашел этот интересный и мощный инструмент под названием IACA (анализатор кода архитектуры Intel), но мне трудно понять его. Что я могу с ней сделать, каковы его ограничения и как я могу:

  • Использовать его для анализа кода на C или С++?
  • Использовать его для анализа кода в ассемблере x86?

Ответ 1

2019-04: достиг EOL. Предлагаемая альтернатива: LLVM-MCA

2017-11: выпущена версия 3.0 (последняя на 2019-05-18)

2017-03: выпущена версия 2.3

Что это:

IACA (анализатор архитектуры Intel) - это бесплатное (2019: конец -o f-life) бесплатное средство статического анализа с закрытым исходным кодом, разработанное корпорацией Intel для статического анализа планирования команд при выполнении современными процессорами Intel. Это позволяет ему вычислять для данного фрагмента,

  • В режиме пропускной способности максимальная пропускная способность (предполагается, что фрагмент является телом самого внутреннего цикла)
  • В режиме задержки минимальная задержка от первой инструкции до последней.
  • В режиме трассировки печатает ход выполнения инструкций через этапы конвейера.

при допущении оптимальных условий выполнения (все обращения к памяти попадают в кэш 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 можно анализировать двоичный файл Haswell с использованием инструкций FMA на компьютере с процессором Pentium III.

С /C++

В C и C++ можно получить доступ к макросам для инъекции маркера с помощью #include "iacaMarks.h", где iacaMarks.h - заголовок, который поставляется вместе с инструментом в подкаталоге include/.

Затем вставляют маркеры вокруг самой внутренней интересующей циклы или прямой линии интереса следующим образом:

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

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

Затем приложение перестраивается, как в противном случае с включенной оптимизацией (в режиме выпуска для пользователей сред IDE, таких как Visual Studio). Вывод является двоичным файлом, который идентичен во всех отношениях сборке 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

Для программистов 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 - объект ELF64, содержащий метки IACA):

iaca.sh -64 -arch HSW -graph insndeps.dot foo

Таким образом, создается отчет об анализе 64-битного двоичного foo при запуске на процессоре Haswell и график зависимостей команд, которые можно просмотреть с помощью 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 и порт 2 и 3 AGU. Этот пример позволяет нам диагностировать проблему как хранилище, которое не обрабатывается портом 7, и принять меры по исправлению.

Ограничения:

IACA не поддерживает несколько инструкций, которые игнорируются при анализе. Он не поддерживает процессоры, более старые, чем Nehalem, и не поддерживает не внутренние циклы в режиме пропускной способности (не имея возможности угадать, какая ветвь берется, как часто и по какой схеме).