Все мопы в вашем цикле являются ветвями (2 на итерацию). Я думаю, что причина того, что `lsd_cycles_4_uops равен нулю, заключается в ограничении переименователя. Согласно Руководству по оптимизации Intel, раздел 2.4.3.1:
Переименователь может выделять две ветви в каждом цикле по сравнению с одной
ветвь каждого цикла в предыдущей микроархитектуре. Это может
устранить некоторые пузыри в исполнении.
Это подраздел раздела микроархитектуры Песчаного моста. Но, насколько мне известно, это относится ко всем более поздним микроархитектурам. Максимальная пропускная способность переименования составляет 4 мопа за цикл. Но не более двух мопов могут быть ветвями. Таким образом, в этом примере, где все мопы являются ветвями, LSD никогда не сможет доставить более 2 мопов в любой заданный цикл даже на первой итерации цикла.
Таким образом, 2 RSU будут распределены в RS за цикл, и оба (один предикат принят и один не взят) могут быть отправлены за цикл. Так что заполняемость РС не растет.
Это ограничение не влияет на производительность вашей программы. Выполнение 2 переходов мопов за цикл, при котором IPC равен 3 за цикл, уже является оптимальным.
Я попытался найти событие производительности, которое может захватить задержки распределителя из-за этого ограничения. События RESOURCE_STALLS.ANY
и UOPS_ISSUED.ANY
(с cmask
= 1 и inv
= 1) в данном случае не актуальны. @IwillnotexistIdonotexist предложил использовать
IDQ_UOPS_NOT_DELIVERED.CORE
. Я представляю результаты ниже для события производительности и всех его поддерживаемых вариантов. Я также даю правильное значение этих событий, потому что руководство неверно. T
обозначает количество итераций.
IDQ_UOPS_NOT_DELIVERED.CORE
: подсчитывает количество слотов, которые не были использованы распределителем. Если программа выполнялась для циклов ядра C, то общее количество слотов равно 4 * C. Измеренное значение практически равно 2 * Т. Поскольку количество циклов равно T, количество временных интервалов равно 4 * T, что означает, что около половины временных интервалов выдачи не было использовано.
IDQ_UOPS_NOT_DELIVERED.CYCLES_0_UOPS_DELIV.CORE
: Подсчитывает количество циклов, в течение которых с IDQ было доставлено ноль мопов. Измеренное значение пренебрежимо мало.
IDQ_UOPS_NOT_DELIVERED.CYCLES_LE_1_UOP_DELIV.CORE
: подсчитывает количество циклов, в течение которых максимум 1 моп было доставлено из IDQ. Измеренное значение пренебрежимо мало.
IDQ_UOPS_NOT_DELIVERED.CYCLES_LE_2_UOP_DELIV.CORE
: подсчитывает количество циклов, в течение которых с IDQ было доставлено не более 2 моп: измеренное значение почти равно T.
IDQ_UOPS_NOT_DELIVERED.CYCLES_LE_3_UOP_DELIV.CORE
: подсчитывает количество циклов, в течение которых с IDQ было доставлено не более 3 моп: измеренное значение почти равно T.
Следовательно, поскольку время выполнения почти равно T базовых циклов, мы можем сделать вывод, что распределитель выделяет только 2 мопа за цикл в большинстве циклов, что равно скорости диспетчеризации.
Обратите внимание, что RS в Haswell и Skylake содержит неиспользованные мопы. Таким образом, каждая запись может содержать один неиспользованный моп. См. Сноска 2 . Но это не имеет значения, потому что здесь нет микрофузии.