В информатике планирование инструкций - это оптимизация компилятора используется для улучшения параллелизма на уровне команд, что повышает производительность на машинах с конвейерами команд. Проще говоря, он пытается сделать следующее, не меняя значения кода:
Остановки конвейера могут быть вызваны структурными опасностями (ограничение ресурсов процессора), опасностями данных (вывод одной инструкции, необходимой другой инструкции) и опасностями управления (ветвление).
Планирование инструкций обычно выполняется для одного базового блока. Чтобы определить, сохраняет ли определенным образом перестановка инструкций блока поведение этого блока, нам нужна концепция зависимости данных. Есть три типа зависимостей, которые также являются тремя опасностями данных :
Технически существует четвертый тип, «Чтение после чтения» (RAR или «Ввод»): обе инструкции читают одно и то же место. Входная зависимость не ограничивает порядок выполнения двух операторов, но полезна при скалярной замене элементов массива.
Чтобы убедиться, что мы соблюдаем три типа зависимостей, мы строим граф зависимостей, который представляет собой ориентированный граф, где каждая вершина является инструкцией, а есть ребро из I От 1 до I 2, если I 1 должен стоять перед I 2 из-за зависимости. Если переносимые циклом зависимости не учитываются, граф зависимостей является направленным ациклическим графом. Тогда любая топологическая сортировка этого графа является допустимым расписанием команд. Ребра графа обычно помечены латентностью зависимости. Это количество тактов, которое должно пройти, прежде чем конвейер сможет продолжить выполнение целевой инструкции без остановки.
Часто используется простейший алгоритм поиска топологической сортировки, известный как планирование списка. По сути, он несколько раз выбирает источник графа зависимостей, добавляет его в текущее расписание инструкций и удаляет его из графа. Это может привести к тому, что другие вершины станут источниками, которые затем также будут учитываться при планировании. Алгоритм завершается, если граф пуст.
Чтобы добиться хорошего графика, следует избегать киосков. Это определяется выбором следующей инструкции для планирования. Часто используется ряд эвристик:
Планирование команд может выполняться либо до, либо после выделения регистров, либо до и после него. Преимущество выполнения этого перед распределением регистров состоит в том, что это приводит к максимальному параллелизму. Недостаток выполнения этого до распределения регистров состоит в том, что это может привести к тому, что распределителю регистров потребуется использовать количество регистров, превышающее доступное. Это приведет к появлению кода разлива / заполнения, что снизит производительность рассматриваемого участка кода.
Если в планируемой архитектуре есть последовательности команд, которые имеют потенциально недопустимые комбинации (из-за отсутствия блокировок команд), команды должны быть запланированы после выделения регистров. Этот второй проход планирования также улучшит размещение кода разлива / заполнения.
Если планирование выполняется только после распределения регистров, тогда будут возникать ложные зависимости, вносимые распределением регистров, которые ограничивают количество перемещений инструкций, возможное для планировщика.
Существует несколько типов планирования инструкций:
Коллекция компиляторов GNU - это компилятор, который, как известно, выполняет планирование инструкций с использованием -march
(набор инструкций и планирование) или -mtune
(только планирование) флаги. Он использует описания задержек выполнения инструкций и то, какие инструкции могут выполняться параллельно (или, что эквивалентно, какой «порт» каждый использует) для каждой микроархитектуры для выполнения задачи. Эта функция доступна почти для всех архитектур, поддерживаемых GCC.
До версии 12.0.0 планирование инструкций в LLVM / Clang могло принимать только -march
( называется target-cpu
на языке LLVM) как для набора команд, так и для планирования. Версия 12 добавляет поддержку -mtune
(tune-cpu
) только для x86.
Источники информации о задержке и использовании портов включают:
LLVM llvm -exegesis
должен использоваться на всех машинах, особенно для сбора информации на машинах, отличных от x86.