Загрязнения памяти замедляют работу всех ядер процессора?

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

Итак, мои вопросы:

  • Как сама ОС (или сам ЦП) знает, какие ядра необходимо синхронизировать?

  • Он синхронизирует кеш всех ядер процессора?

  • Если ответ на (2) есть "да" и предполагается, что операции синхронизации не являются дешевыми, использует ли память затворы замедляющие ядра, которые не используются моим приложением? Если, например, у меня есть одно потоковое приложение, работающее на моем 8-ядерном процессоре, это замедлит все остальные 7 ядер процессора, потому что некоторые строки кэша должны синхронизироваться со всеми этими ядрами?

  • Являются ли вышеперечисленные вопросы совершенно неосведомленными и заборы работают совершенно по-другому?

Ответ 1

  • OS не нужно знать, и каждое ядро ​​процессора делает то, что он сказал: каждое ядро ​​с заграждением памяти должно выполнять определенные операции до или после, и все. Ядро не синхронизирует "с" другими ядрами, а синхронизирует доступ к памяти по отношению к себе.
  • Забор в одном ядре не означает, что с ним синхронизируются другие ядра, поэтому обычно у вас есть два (или более) забора: один в записи и один в считывателе. Забор, выполненный на одном сердечнике, не должен воздействовать на другие сердечники. Конечно, в этом нет никакой гарантии, просто надежда, что разумные архитектуры не будут чрезмерно сериализовывать многоядерные исполнения.

Ответ 2

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

load A
load B

Многие CPU не гарантируют, что B действительно загружен после того, как A, B могут быть в строке кэша, которая ранее была загружена в кеш из-за некоторой другой нагрузки на память. Если вы вводите забор,

load A
readFence
load B

у вас есть гарантия, что B загружается из памяти после A. Если B находится в кеше, но старше A, он будет перезагружен.

Ситуация с магазинами одинакова по-другому. С

store A
store B

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


Как правило, вы используете ячейки памяти в парах:

  • Если один поток хочет опубликовать объект, он сначала конструирует объект, затем он выполняет забор записи перед тем, как записать указатель на объект в общеизвестное местоположение.

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

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

Ответ 3

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

Если ядро ​​# 1 использует забор памяти, но никакое другое ядро ​​не обращается к памяти, к которой обращается ядро ​​# 1, то остальные ядра не будут замедляться вообще. Однако, если ядро ​​# 1 записывает в местоположение X, использует забор памяти, тогда ядро ​​# 2 пытается прочитать одно и то же местоположение X, забор памяти будет обеспечивать, чтобы ядро ​​# 2 выбрасывало значение местоположения X, если оно находилось в кеш и считывает данные из ОЗУ, получая те же данные, что и ядро ​​# 1. Конечно, это требует времени, но для этого нужен забор памяти.

(Вместо того, чтобы читать из ОЗУ, если ядра имеют общий кеш, тогда данные будут считаны из кеша.)