Я написал программу , которую можно использовать для изучения недокументированных ограничений RS в процессорах Intel в надежде, что в конечном итоге я смогу ответить на этот вопрос.Основная идея состоит в том, чтобы удостовериться, что RS полностью пуст, прежде чем выделять и выполнять определенную последовательность мопов в цикле.RESOURCE_STALLS.RS
может использоваться для определения, достигла ли эта последовательность ограничения в самом RS.Например, если RESOURCE_STALLS.RS
равно 1 на итерацию, то распределителю пришлось остановиться на один цикл, чтобы выделить записи RS для всех мопов в последовательности.Если RESOURCE_STALLS.RS
намного меньше, чем 1 на одну итерацию, то в принципе не нужно было останавливаться, и поэтому мы знаем, что не затронули ни одно из ограничений RS.
Я экспериментировал с последовательностьюзависимые ADD
инструкции, последовательность зависимых инструкций BSWAP, последовательность зависимых инструкций загрузки в одно и то же местоположение, последовательность обратных или прямых инструкций безусловного перехода и последовательность инструкций сохранения в одном и том же месте.На следующих двух графиках показаны результаты для последовательности add
инструкций для различных целевых заполнений RS (максимальное количество записей RS, которые будут одновременно требоваться и заняты последовательностью мопов).Все значения показаны для каждой итерации.
На следующем графике показано, что RESOURCE_STALLS.RS
для каждой итерации становится по меньшей мере (или где-то рядом) 1 циклом на итерацию, когда занятость RS равна 50. Хотя это не ясно видно,1013 * становится больше нуля, когда занятость RS превышает 43, но только превышает 1, когда занятость RS превышает 49. Другими словами, я могу одновременно использовать только 49 записей RS из 60 (в Haswell) безRS киосков.После этого RESOURCE_STALLS.RS
увеличивается в среднем на 1 на дополнительный моп в последовательности, что согласуется с импульсным поведением распределителя и тем фактом, что каждый макс ADD
может выполняться каждый цикл (каждый моп занимает запись RS дляТолько 1 цикл)cycles
увеличивается в среднем на 2,3 за дополнительную моп.Это больше, чем 1 на дополнительный моп, потому что в ROB есть также дополнительные киоски по причинам, не связанным с add
мопами, но это нормально, потому что они не влияют на RESOURCE_STALLS.RS
.
На следующем графике показано изменение cycles
и RESOURCE_STALLS.RS
за итерацию.Это иллюстрирует сильную корреляцию между временем выполнения и остановками RS.
Когда целевая занятость RS находится между 44-49, RESOURCE_STALLS.RS
очень малано все же не совсем ноль.Я также заметил, что точный порядок, в котором различные мопы представляются распределителю, немного влияет на занятость RS, которая может быть достигнута.Я думаю, что это является следствием схемы распределения портов записи массива RS, упомянутой в руководстве Intel.
Так что же с остальными 11 записями RS (предполагается, что RS Haswell имеет 60 записей)?Событие производительности RESOURCE_STALLS.ANY
- ключ к ответу на вопрос.Я обновил код, который я использую для выполнения этих экспериментов, чтобы протестировать различные виды нагрузок:
- Нагрузки, которые могут быть отправлены с умозрительными адресами, чтобы достичь 4-тактовой задержки L1D.Этот случай называется
loadspec
. - Грузы, которые нельзя отправить с умозрительными адресами.У них задержка попадания L1D в 5 циклов на Haswell.Этот случай называется
loadnonspec
. - Грузы, которые можно отправлять с умозрительными, но неправильными адресами.У них L1D задержка попадания в 9 циклов на Haswell.Этот случай упоминается как
loadspecreplay
.
Я следовал тому же подходу с инструкциями ADD
, но на этот раз нам нужно смотреть RESOURCE_STALLS.ANY
вместо RESOURCE_STALLS.RS
(который фактически не захватывает ларьки RS из-за нагрузок).На следующем графике показано изменение cycles
и RESOURCE_STALLS.ANY
за итерацию.Первый всплеск указывает, что целевая занятость RS превысила доступные записи RS для этого вида мопов.Мы можем ясно видеть, что для случая loadspec
есть ровно 11 записей RS для load uops!Когда целевая занятость RS превышает 11, требуется в среднем 3,75 цикла для входа RS, чтобы стать свободным до следующей загрузки.Это означает, что мопы освобождаются от RS, когда они завершаются, а не когда они отправляются.Это также объясняет, как работает воспроизведение UOP.Пик для loadspecreplay
происходит при занятости RS 6. Пик для loadnonspec
происходит при занятости RS 9. Как вы увидите позже, эти 11 записей не предназначены для нагрузок.Некоторые из 11 записей, используемых нагрузками, могут быть среди 49 записей, используемых ADD
мопами.
Я также разработал двеконтрольные примеры для хранилищ: один достигает предела буфера хранилища, а другой - ограничения RS.График выше показывает первый случай.Обратите внимание, что хранилищу нужны две записи в RS, поэтому случаи, когда целевое занятие RS нечетно, совпадают с предыдущими четными занятиями RS (изменение равно нулю).График показывает, что в RS может быть до 44/2 = 22 хранилища одновременно.(В коде, который я использовал для создания графа хранилищ, была ошибка, из-за которой достигнутая занятость RS была больше, чем она есть. После исправления, результаты показывают, что в RS может быть до 20 хранилищ одновременно.)запись, занимаемая адресом магазина или хранением данных, может быть освобождена за один цикл.Intel говорит, что в буфере хранилища Haswell есть 42 записи, но я не смог использовать все эти записи одновременно.Вероятно, мне придется спроектировать другой эксперимент, чтобы добиться этого.
Последовательность прыжков не вызвала никаких срывов.Я думаю, что это может быть объяснено следующим образом: прыжковая операция освобождает запись RS, которую она занимает за один цикл, и распределитель не ведет себя непрерывно, когда он выделяет прыжковые операции.То есть каждый цикл, в котором одна запись RS становится свободной, и распределитель будет просто выделять один скачок без остановки.Таким образом, мы никогда не останавливаемся, сколько бы прыжков ни было.Это в отличие от добавления мопов, когда поведение пакетного распределителя заставляет его останавливаться до тех пор, пока требуемое количество записей RS не станет свободным (4 записи), даже если задержка добавления мопа также равна одному циклу.Имеет смысл, чтобы переходы распределялись как можно скорее, чтобы любые неправильные прогнозы могли быть обнаружены как можно раньше.Таким образом, если распределитель увидел скачок, и в RS достаточно места для него, но не позднее, в его группе 4 мопа, он все равно выделил бы его.Иначе, возможно, придется ждать потенциально много циклов, которые могут значительно задержать обнаружение неправильных прогнозов.Это может быть очень дорогостоящим
Есть ли инструкция, мопс которой может занимать все 60 записей RS одновременно?Да, один пример - BSWAP
.Для его двух мопов требуются две записи RS, и я ясно вижу, используя RESOURCE_STALLS.RS
, что его мопы могут использовать все 60 записей RS одновременно (при условии, что мои вычисления верны относительно того, как увеличивается занятость RS с помощью инструкции),Это доказывает, что в РС действительно есть ровно 60 записей.Но есть ограничения относительно того, как они используются, о которых мы все еще мало знаем.