Ложное совместное использование и изменчивость

#java #caching #false-sharing

#java #кэширование #ложное совместное использование

Вопрос:

Добрый день, недавно я обнаружил аннотацию, представленную в Java 8, под названием Contended. Из этого списка рассылки я прочитал, что такое false sharing и как аннотации позволяют объектам или полям выделять целую строку кэша.

После некоторых исследований я обнаружил, что если два ядра хранят одну и ту же строку кэша, а одно из них изменяет ее, то второму приходится перечитывать всю строку из основной памяти. https://en.wikipedia.org/wiki/MESI_protocol. Но мне все еще неясно, почему аппаратное обеспечение заставляет процессор перечитывать его. Я имею в виду, именно поэтому у нас есть ключевое слово volatile в Java, верно? Если переменная объявлена как volatile, потоки будут пропускать эту переменную из кэша и всегда считывать / записывать ее из / в основную память. Если аппаратное обеспечение заставляет процессор перечитывать строки кэша после каждой записи, то как возможна несогласованность данных в многопоточных приложениях?
Заранее спасибо

Ответ №1:

 After some research I found that if two cores store the same cache line and 
one of them modify it then the second one has to reread entire line from main memory. https://en.wikipedia.org/wiki/MESI_protocol.
  

Это неверно. Кэш является источником истины, потому что кэши (по крайней мере, на X86) всегда согласованы. Таким образом, теоретически кэш-линию никогда не нужно считывать из основной памяти; ее всегда можно использовать из одного из кэшей процессора. Если для другого кэша процессора потребуется кэш-строка, он может просто прочитать значение из других кэшей. С помощью MESI может случиться так, что кэш-линия сбрасывается в основную память, когда кэш-линия находится в измененном состоянии и другой процессор хочет ее прочитать; но в противном случае связь с основной памятью не требуется. Это потому, что MESI не поддерживает грязный общий доступ; MOESI решает эту проблему.

  But it still unclear for me why hardware forces CPU to reread it. 
 I mean that is why we do have a volatile keyword in Java right ? 
  

Кэши на X86 всегда согласованы. Для этого не требуется никаких специальных инструкций процессора; это нестандартное поведение. Таким образом, не может случиться так, что, например, значение A = 1 записывается в некоторую строку кэша, в то время как более позднее чтение все еще видит старое значение A = 0.

  If variable is declared as volatile then threads will skip this variable 
 from cache and always read/write it from/to main memory. 
 If hardware forces cpu to reread cache lines after every write then how data inconsistency is possible in multi threaded applications?
  

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

Цель volatile — убедиться, что порядок в отношении других загрузок и хранилищ по разным адресам сохраняется и что хранилища a видны другим потокам.

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

Таким образом, вы получаете много трафика согласованности кэша между разными процессорами .. постоянно сражаясь за одну и ту же кэш-линию. И если вам не повезло, процессор не может выполнить никаких инструкций out of order, поэтому процессор будет в основном простаивать, даже если у вас 100% загрузка процессора.

Комментарии:

1. Спасибо за это замечательное объяснение, оно изменило мое представление о volatile, до сих пор я думал, что атомарная запись / чтение летучих веществ достигается с использованием значений непосредственно из основной памяти. Я все еще не уверен, «что хранилища видны другим потокам». тогда как volatile делает значение видимым для других потоков и почему энергонезависимые переменные этого не делают, если кэши являются «кэшами на X86 всегда согласованными». Не могли бы вы поделиться некоторыми ресурсами, пожалуйста, чтобы я мог продолжить свои исследования по этому вопросу