Стоимость неоптимальной предварительной выборки в кешировании - PullRequest
0 голосов
/ 22 февраля 2019

Сколько стоит поздняя предварительная выборка, сделанная с внутренней __builtin_prefetch(..., 1) (предварительная выборка при подготовке к записи)?То есть предварительная выборка, которая не поступает в кэш L1 до загрузки по требованию или записи, которая требует этого?

Например,

void foo(std::uint8_t* line) {
    __builtin_prefetch(line + std::hardware_constructive_interference_size, 1);
    auto next_line = calculate_address_of_next_line(line);
    auto result = transform(line);
    write(next_line, result)
}

В этом случае, если стоимость transformниже, чем предварительная выборка, будет ли этот код менее эффективным, чем если бы предварительной выборки не было?В статье Википедии о предварительной выборке кэша говорится об оптимальном шаге для цикла for, но не упоминается влияние субоптимальной предварительной выборки в этом сценарии (например, что произойдет, если k будет слишком низким?),

Достаточно ли это передано по конвейеру, чтобы неоптимальная предварительная выборка не имела значения?Я рассматриваю только Intel x86 (процессоры во времена Broadwell, может быть) для целей этого вопроса.

1 Ответ

0 голосов
/ 23 февраля 2019

Давайте назовем тип предварительной выборки, на который вы ссылаетесь, поздняя предварительная выборка: где предварительная выборка происходит недостаточно перед загрузкой по требованию или в хранилище, которое использует ту же строку кэша, чтобы полностью скрыть задержку кэша.Мисс.Это в отличие от слишком ранней предварительной выборки, где предварительная выборка происходит так далеко от доступа по требованию, что она вытесняется из, по крайней мере, некоторых уровней кэша до того, как будет получен доступ.

По сравнению с отсутствием предварительной выборки, стоимость такой поздней предварительной выборки , вероятно, очень мала, равна нулю или отрицательна .

Давайте сосредоточимся на отрицательной частито есть сценарий, когда предварительная выборка помогает, даже если уже поздно.Если я правильно понимаю ваш вопрос, вы считаете, что предварительная выборка не приходит до того момента, когда нагрузка, которая нуждается в ней, «пропустила» или неэффективна.Однако это не так: как только начинается запрос на предварительную выборку, часы начинают отсчитывать время для завершения доступа к памяти, и эта работа не теряется , если загрузка по требованию происходит до ее завершения.Например, если доступ к памяти занимает 100 нс, но доступ по требованию происходит только через 20 нс после предварительной выборки, предварительная выборка «слишком поздняя» в том смысле, что полная задержка 100 нс не была скрыта, но затрачивается 20 нс напредварительная выборка все еще полезна: она уменьшила задержку доступа по требованию примерно до 80 нс.

То есть позднее предварительная выборка не является двоичным условием: она колеблется от немного позднего (например, предварительная выборка выдается за 90 нс до доступа с задержкой в ​​100 нс) или действительно с опозданием (почти сразу перед потребляющим доступом).В большинстве сценариев даже довольно поздняя предварительная выборка, вероятно, помогает, предполагая, что задержка памяти была узким местом для вашего алгоритма.

Затраты

Давайте теперь рассмотрим случай совершенно бесполезной предварительной выборки (т. Е.выдан непосредственно перед доступом, поэтому доступ мог быть выдан на его месте, если бы не существовала предварительная выборка) - какова стоимость?В наиболее реалистичных сценариях затраты, вероятно, очень малы: дополнительная инструкция для обработки, некоторое небольшое дополнительное давление на AGU и, возможно, небольшое количество потерянных усилий при сопоставлении последующего доступа с предварительной выборкой в ​​полете 2 .

Поскольку предполагается, что предварительная выборка используется из-за пропущенных к внешним уровням кэша или DRAM, и что работа в функции transform является достаточно значительной, чтобы скрыть некоторую задержку,Относительная стоимость этой дополнительной инструкции, вероятно, будет очень мала.

Конечно, все это при условии, что дополнительная предварительная выборка является одной инструкцией.В некоторых случаях вам, возможно, пришлось несколько упорядочить код, чтобы разрешить предварительную выборку, или выполнить несколько дублирующих вычислений, чтобы разрешить предварительную выборку в соответствующем месте.В этом случае сторона затрат может быть соответственно выше.

Состояния M и E

Наконец, существует дополнительное поведение в отношении доступа к записи и предварительной выборки с намерением записи, что означает, что вв некоторых случаях полезна даже совершенно бесполезная предварительная выборка (т. е. непосредственно перед первым доступом) - когда первый доступ является чтением.

Если данная строка сначала читается, а затем записывается, ядро ​​может получитьстрока в E (xclusive) состояние когерентности , а затем по первому необходимо сделать еще одно обратное путешествие к некоторому уровню кеша, чтобы перевести его в состояние M.Использование предварительной выборки с записью-намерением перед первым доступом позволит избежать этого второго обхода, поскольку в первый раз строка будет приведена в состояние М.Эффект этой оптимизации в целом трудно оценить количественно, не в последнюю очередь потому, что записи обычно буферизуются и не образуют часть цепочки зависимостей (вне пересылки из магазина).


2 Я использую здесь заведомо расплывчатый термин «потраченные впустую усилия», потому что не совсем понятно, имеет ли это производительность или энергопотребление, или это просто дополнительная работа, которая не добавляет клатентность операции.Одна из возможных затрат состоит в том, что нагрузка, которая вызывает первоначальное промах L1, имеет особый статус и может получить свой результат, не совершая еще одного обхода до L1.В сценарии предварительной выборки, за которой сразу следует загрузка, загрузка, по-видимому, не получает особого статуса, который может немного увеличить стоимость.Однако этот вопрос о магазинах не загружается.

...