MESI- что происходит при чтении изменяемых данных?
Если у меня есть строка данных кэша, а первый байт атомарно изменяется, могу ли я по-прежнему считывать разные байты данных из этой строки кэша одновременно? Или моя попытка прочитать будет знать о происходящем обновлении атома и ждать его?
Я пытаюсь понять влияние на производительность вышеописанного сценария.
1 ответ
Когерентность кэша поддерживается на уровне детализации строки, обычно 64B в большинстве процессоров в наши дни. Ядро, выполняющее модификацию, сначала запросит право владения всей строкой, что означает, что все остальные ядра должны сделать свои копии недействительными (если они были). Любое другое ядро, пытающееся выполнить чтение, будет запрашивать эту строку, что приведет к тому, что отслеживание будет отправлено в модифицирующее ядро. Оттуда у вас есть два варианта:
Либо модифицирующее ядро завершило последовательность чтения-изменения-записи, и строка помещается в кэш с последними измененными данными - в этом случае анализатор инициирует последовательность WB, обновленная строка станет доступной для всех, а 2-е ядро может прочитать любой байт из него.
Модифицирующее ядро получило линию через нагрузку, но его хранилище все еще не внесло изменения (что возможно, поскольку хранилища обычно выполняются намного позже в трубе, в то время как нагрузки часто делаются спекулятивно). В этом случае ядро должно защищать линию от взлома, обычно путем реализации внутренней блокировки для таких операций. Обратите внимание, что на x86, например, для большинства атомарных операций чтения-изменения-записи требуется префикс блокировки. Также обратите внимание, что обычная последовательность чтения + записи (не атомарная) просто потеряет строку в этой точке, а затем снова получит ее для сохранения, что приведет к потере согласованности.
Редактировать: после комментария Пола, действительно возможно разработать систему кеша, которая позволяет отслеживать детализацию подстроки. Это в основном означает отделение базового блока протокола MESI от базового размера блока, используемого для кэширования, вам нужно будет добавить биты состояния для каждого подмножества (но все равно можно использовать один тег для всех), сделать недействительными только локальные подмножества и, в конечном итоге, выполнить слияние как-то, чтобы восстановить полную линию. Тем не менее, накладные расходы сделали бы это довольно редко, и я не знаком с коммерческими процессорами, делающими все это только для того, чтобы избежать ложного обмена. В любом случае, поскольку такой субблок, вероятно, не будет иметь размер в байтах, исходный вопрос все еще применяется для байтов в том же блоке.