Когда ЦП с кешем L1 выполняет запись, обычно происходит следующее (при условии, что строка кеша, в которую он пишет, уже находится в кеше L1), кеш (в дополнение к обновлению данных) помечает эту строку кеша как грязную и через некоторое время напишет строку с обновленными данными.
Одной из возможных оптимизаций было бы сравнение кэша с содержимым записи и предыдущим содержимым кэша, и, если они совпадают, не помечайте строку как грязную. Поскольку это может позволить кэш-памяти избегать обратной записи в некоторых случаях, я вижу, как производитель ЦП может счесть это стоящим затратами, необходимыми для выполнения этой логики.
Мой вопрос: есть ли процессоры, которые выполняют эту оптимизацию?
Исходная информация о том, почему я спрашиваю: я пишу некоторый код, который должен иметь постоянный доступ к памяти; то есть кто-то, кто может слушать поведение кэша, не должен уметь делать то, что я делаю. Некоторые из моих обращений - это записи, и очевидным способом реализации этого кода многие записи будут записывать те же данные, которые уже есть. Мне нужно делать записи, потому что, в зависимости от данных, данные, которые я пишу, могут совпадать или не совпадать, и важно выполнять одно и то же действие независимо. Если ЦП оптимизирует, фактически не записывая «без изменений-записи», это будет означать, что поведение кэша будет зависеть от того, что я делаю, что подорвет мою цель.
Итак, есть ли процессор, который пытается оптимизировать записи таким образом?
Ответы:
После нескольких часов поиска я не смог найти процессор, который использует эту специфическую оптимизацию. Большинство упомянутых оптимизаций, как правило, связаны с попаданием / пропуском операций чтения / записи и доступа к данным:
(страницы 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;
. Это только иногда оптимизация для строк общего кэша в многопоточной программе, потому что запись мешает чтению других потоков.Запись в кэш-память первого уровня - очень и очень критичная по времени операция.
Записывать те же самые данные обратно довольно редко. Оптимизация, которая ускоряет процесс в данном конкретном случае, не даст большого ускорения в целом.
С другой стороны, эта оптимизация требует сравнения старых данных и новых данных при каждой записи в кэш-память. Что еще хуже, это то, что требуется, чтобы записываемые данные были действительно доступны во время записи!
Обычно это не так на современном процессоре. Данные, которые должны быть записаны, все еще могут быть рассчитаны, например. Кэш все еще может продолжаться, загружать строку кэша, если это необходимо, помечать строку кэша как измененную и так далее, даже до завершения вычисления. Весь бухгалтерский учет уже может быть выполнен за исключением фактической модификации строки кэша. Если вы хотите сравнить вновь записанный результат и старые данные строки кэша, это невозможно.
Например, если у вас есть код C a [i] = x / y; деление x / y занимает необычайно много времени на большинстве процессоров. Однако большая часть работы, необходимой для сохранения результата в [i], произошла задолго до окончания деления; не хватает только перемещения восьми байтов результата в строку кэша. Операция очистки строки кэша будет автоматически ожидать завершения деления. Операция чтения [i], вероятно, будет перенаправлена, чтобы получить результат прямо из делителя.
источник
Разве такая оптимизация не удвоит время, необходимое процессору для записи чего-либо в кеш? Поскольку каждая запись строки кэша теперь будет сопровождаться операцией сравнения, которая не является бесплатной.
Итак, на самом деле оптимизация теперь будет зависеть от очень расплывчатого фактора: сколько раз среднее программное обеспечение перезаписывает свою кешируемую память с одними и теми же данными.
источник