Существуют ли процессоры, которые выполняют эту возможную оптимизацию записи в кэш L1?

9

Когда ЦП с кешем L1 выполняет запись, обычно происходит следующее (при условии, что строка кеша, в которую он пишет, уже находится в кеше L1), кеш (в дополнение к обновлению данных) помечает эту строку кеша как грязную и через некоторое время напишет строку с обновленными данными.

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

Мой вопрос: есть ли процессоры, которые выполняют эту оптимизацию?

Исходная информация о том, почему я спрашиваю: я пишу некоторый код, который должен иметь постоянный доступ к памяти; то есть кто-то, кто может слушать поведение кэша, не должен уметь делать то, что я делаю. Некоторые из моих обращений - это записи, и очевидным способом реализации этого кода многие записи будут записывать те же данные, которые уже есть. Мне нужно делать записи, потому что, в зависимости от данных, данные, которые я пишу, могут совпадать или не совпадать, и важно выполнять одно и то же действие независимо. Если ЦП оптимизирует, фактически не записывая «без изменений-записи», это будет означать, что поведение кэша будет зависеть от того, что я делаю, что подорвет мою цель.

Итак, есть ли процессор, который пытается оптимизировать записи таким образом?

пончо
источник
11
Говорят, что в компьютерных науках есть две действительно трудные проблемы: аннулирование кэша, правильное именование и ошибки типа «один на один». Это пример того, почему первый из них хитрый.
Мейсон Уилер,
@poncho, вы говорите, что «тот, кто умеет слушать поведение кеша, не должен уметь делать то, что я делаю». Теперь, если некоторые процессоры реализуют эту функцию «умной обратной записи», которая не делает кэш недействительным, если данные действительно не обновляются, тогда, если перейти на один уровень дальше от процессора в иерархии памяти, можно будет наблюдать за трафиком / временем различия между реальными и фиктивными записями. Вас это беспокоит?
TheCodeArtist
@poncho Кроме того, ваш реальный вопрос, похоже, касается реализации лучшего привилегированного / безопасного режима, который не пропускает информацию об использовании. Может быть, вы должны спросить это? ...
TheCodeArtist
1
@TheCodeArtist: хорошо, были опубликованы криптографические атаки по побочным каналам, где подпрограмма шифрования могла быть атакована другой программой, работающей на другом ядре того же CPU, с помощью программы атаки, контролирующей общий кэш. Я полагаю, что такая программа потенциально могла бы определить, были ли очищены строки кэша L1, и, следовательно, могла бы вывести информацию о программе, которая мне интересна, если ЦП выполняет обсуждаемую оптимизацию. Я не говорю о «безопасном режиме», так как я не предполагаю возможность изменять процессор или ОС.
Пончо
4
Даже если это правда сегодня, это не гарантировано, чтобы быть завтра.
pjc50

Ответы:

4

После нескольких часов поиска я не смог найти процессор, который использует эту специфическую оптимизацию. Большинство упомянутых оптимизаций, как правило, связаны с попаданием / пропуском операций чтения / записи и доступа к данным:

(страницы 7 и) https://cseweb.ucsd.edu/classes/fa14/cse240A-a/pdf/08/CSE240A-MBT-L15-Cache.ppt.pdf

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

Получение текущего значения в кеше реестра

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

Чтение содержимого кэша процессора

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

Еще одна возможность, которую я нашел, связана с согласованностью кэша:

Соответствующий отрывок из статьи в Википедии о согласованности

Основным моментом, который привлек мое внимание в связи с этим вопросом, было описание Снарфинга:

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

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

Сообщество
источник
Также возможно получить доступ к текущим значениям в регистрах кеша, но это несколько опасно. Да, это не имеет смысла. Вы имеете в виду регистры процессора? Генерируемый компилятором или написанный от руки ассемблерный код использует регистры для хранения значений, над которыми он работает ...
Питер Кордес
Если вы пытаетесь реализовать это в программном обеспечении, вам просто нужно, чтобы компилятор генерировал код, который это делает if (mem != x) { mem = x; }вместо mem = x;. Это только иногда оптимизация для строк общего кэша в многопоточной программе, потому что запись мешает чтению других потоков.
Питер Кордес
1
«Снарфинг» не имеет к этому никакого отношения. Это просто пассивное слежка. Кэши ЦП используют MESI, поэтому они могут иметь согласованные кеши обратной записи.
Питер Кордес
@PeterCordes Если вы найдете мой ответ неприятным, я прошу прощения. Тем не менее, похоже, что у вас есть больше понимания, чем я по этому вопросу. Так почему бы не ответить на вопрос самостоятельно? Мой ответ был явно неадекватным по вашим меркам ...
3

Запись в кэш-память первого уровня - очень и очень критичная по времени операция.

Записывать те же самые данные обратно довольно редко. Оптимизация, которая ускоряет процесс в данном конкретном случае, не даст большого ускорения в целом.

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

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

Например, если у вас есть код C a [i] = x / y; деление x / y занимает необычайно много времени на большинстве процессоров. Однако большая часть работы, необходимой для сохранения результата в [i], произошла задолго до окончания деления; не хватает только перемещения восьми байтов результата в строку кэша. Операция очистки строки кэша будет автоматически ожидать завершения деления. Операция чтения [i], вероятно, будет перенаправлена, чтобы получить результат прямо из делителя.

gnasher729
источник
Кэш, использующий MESI для согласованности, все еще может выполнять RFO, но если данные будут сравниваться, как только они будут готовы, оставьте строку в состоянии Exclusive вместо Modified. Реальная причина того, что это не сделано в аппаратном обеспечении, состоит в том, что это требует дополнительных чтений кеша, когда данные фиксируются в кеше, и потребует своего рода атомарных циклов чтения / сравнения / записи (с необязательной установкой грязного бита), которые заставляют его сосать для конвейерная реализация.
Питер Кордес
1

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

Разве такая оптимизация не удвоит время, необходимое процессору для записи чего-либо в кеш? Поскольку каждая запись строки кэша теперь будет сопровождаться операцией сравнения, которая не является бесплатной.

Итак, на самом деле оптимизация теперь будет зависеть от очень расплывчатого фактора: сколько раз среднее программное обеспечение перезаписывает свою кешируемую память с одними и теми же данными.

Владислав Раструсный
источник
Это сравнение будет реализовано в логике процессора. Это не потребует дополнительной работы процессора, но время сигнала может увеличиться, что может быть проблемой или нет.
Ziggystar
@ziggystar Ну, я не мастер аппаратного обеспечения, но я привык к мысли, что все идет со стоимостью. Так что сравнивайте операцию с строкой кэша. Это может быть быстро. Но это все еще стоит. И я думаю, что разработчики решили не платить. Может быть, даже после некоторых размышлений и измерений.
Владислав Раструсный
1
Но вы говорите о времени, когда стоимость может быть только увеличением количества ворот.
Ziggystar
1
@ziggystar: Это не просто ворота. Когда данные отправляются в кэш, обычно процесс отправки данных может пометить строку кэша как измененную. При такой «оптимизации» и старые данные, и новые данные должны проходить через эти шлюзы, что приведет к некоторой задержке, и только тогда кеш может быть признан недействительным. Вы должны сжать все это в один процессорный цикл, иначе запись в строку кэша внезапно займет два цикла. А теперь, чтобы усложнить задачу, рассмотрим, что происходит, когда я записываю восемь последовательных слов в строку кэша.
gnasher729
1
И каждая из этих записей задерживает решение о том, изменена ли строка кэша. Поэтому, когда происходит вторая запись, строка кэша не знает, изменена она или нет (пока). Это будет весело.
gnasher729