Я могу вызвать когерентность кэш-памяти на многоядерном x86 ЦП?

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

В этом случае есть ли возможность заменить вызовы exit () на коды возврата ошибок из функций, чтобы вызывающие абоненты могли выполнять такие действия, как приведение в порядок или состояние журнала, перед тем, как фактически завершить работу? Если это так, то это одновременно упрощает тестирование и, вероятно, упростит поиск ошибок, когда код фактически используется в выпуске / производстве, так как может быть довольно сложно понять, почему программа просто «взлетает» и умирает, особенно если код спрятан в библиотечной функции!

33
задан Ciro Santilli 新疆改造中心法轮功六四事件 17 March 2015 в 13:36
поделиться

9 ответов

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

нет большого количества инструкций по когерентности кэш-памяти в x86. Существуют инструкции по упреждающей выборке как prefetchnta , но это не влияет на заказывающую память семантику. Это раньше реализовывалось путем обеспечения значения к кэшу L1, не загрязняя L2, но вещи более сложны для современных проектов Intel с большим общим содержащий кэш L3.

x86 центральные процессоры используют вариацию на протокол MESI (MESIF для Intel, MOESI для AMD) для хранения их кэшей когерентными друг с другом (включая частные кэши L1 различных ядер). Ядро, которое хочет записать строку кэша, должно вынудить другие ядра делать недействительным свою копию ее, прежде чем она сможет изменить свою собственную копию от Общего до Измененного состояния.

<час>

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

действительно необходимо предотвратить время компиляции, переупорядочив , потому что модель памяти C++ слабо заказана. volatile старый, плохой способ сделать это; C++ 11 станд.:: атомарный намного лучший способ написать свободный от блокировок код.

31
ответ дан Peter Cordes 27 November 2019 в 17:41
поделиться

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

24
ответ дан 27 November 2019 в 17:41
поделиться

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

, Если core#1 пишет в переменную, которая делает недействительным все другие копии строки кэша в других ядрах (потому что это должно добраться эксклюзивное владение из строки кэша прежде, чем фиксировать хранилище). Когда core#2 считает ту же самую переменную, он будет отсутствовать в кэше (если core#1 уже не записал его обратно до общего уровня кэша).

, Так как вся строка кэша (64 байта) должна быть считана из памяти (или записана обратно к общему кэшу и затем чтению core#2), это будет иметь некоторую стоимость производительности. В этом случае это неизбежно. Это - желаемое поведение.

<час>

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

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

15
ответ дан Peter Cordes 27 November 2019 в 17:41
поделиться

Энергозависимый не сделает этого. В C++, энергозависимом только, влияет что оптимизация компилятора, такая как хранение переменной в регистре вместо памяти или удаления его полностью.

6
ответ дан dsimcha 27 November 2019 в 17:41
поделиться

Вы не указывали, какой компилятор Вы используете, но если Вы находитесь на окнах, смотрите на эта статья здесь . Также смотрите на доступные функции synchronization здесь . Вы могли бы хотеть отметить, что в общем volatile недостаточно, чтобы сделать то, что Вы хотите, чтобы это сделало, но под VC 2005 и 2008, существует нестандартная семантика, добавленная к нему, которые добавляют подразумеваемые барьеры памяти вокруг чтения и записей.

, Если Вы хотите вещи быть портативными, Вы собираетесь иметь намного более твердую дорогу перед Вами.

6
ответ дан Eclipse 27 November 2019 в 17:41
поделиться

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

Статьи очень читаемы и хорошо проиллюстрированы. Наслаждайтесь!

3
ответ дан davidnr 27 November 2019 в 17:41
поделиться

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

Редактирование: при использовании компилятора Intel или GCC можно использовать атомарный builtins, которые, кажется, прилагают все усилия для вытеснения кэша, если это возможно.

1
ответ дан greyfade 27 November 2019 в 17:41
поделиться

В вашем вопросе есть несколько подвопросов, поэтому я отвечу на них, насколько мне известно. [1274 В настоящее время в C ++ нет переносимого способа реализации взаимодействий без блокировки. Предложение C ++ 0x решает эту проблему, представляя библиотеку atomics.

  • Volatile не гарантирует атомарность в многоядерных системах, а его реализация зависит от поставщика.
  • В x86 вам не нужно ничего делать особый, за исключением того, что объявляют общие переменные как volatile, чтобы предотвратить некоторые оптимизации компилятора, которые могут нарушить многопоточный код. Volatile указывает компилятору не кэшировать значения.
  • Существуют некоторые алгоритмы (например, Dekker), которые не будут работать даже на x86 с переменными переменными.
  • Если вы точно не знаете, что передача доступа к данным между потоками является основным узким местом производительности вашей программы, избегайте решений без блокировок. Используйте передачу данных по значению или блокировкам.
  • 3
    ответ дан Bartosz Milewski 27 November 2019 в 17:41
    поделиться

    Ниже приводится хорошая статья, посвященная использованию volatile с многопоточными программами.

    Энергозависимость почти бесполезна для многопоточного программирования .

    2
    ответ дан 27 November 2019 в 17:41
    поделиться
    Другие вопросы по тегам:

    Похожие вопросы: