Если я не использую заборы, сколько времени понадобится ядру, чтобы увидеть записи другого ядра?
Я пытался найти в Google мой вопрос, но, честно говоря, не знаю, как кратко сформулировать вопрос.
Предположим, у меня есть два потока в многоядерной системе Intel. Эти потоки работают на том же узле NUMA. Предположим, что поток 1 записывает в X один раз, а затем читает только изредка, продвигаясь вперед. Предположим далее, что, помимо прочего, поток 2 читает X непрерывно. Если я не использую забор памяти, сколько времени может быть между потоком 1, пишущим X, и потоком 2, видящим обновленное значение?
Я понимаю, что запись X пойдет в буфер хранилища и оттуда в кеш, после чего MESIF начнет работу, и поток 2 увидит обновленное значение через QPI. (Или, по крайней мере, это то, что я почерпнул). Я предполагаю, что буфер хранилища будет записан в кеш либо на заборе хранилища, либо если эта запись буфера хранилища потребуется использовать повторно, но я не знаю, буферы хранилища выделяются для записи.
В конечном счете, вопрос, на который я пытаюсь ответить для себя, заключается в том, возможно ли для потока 2 не видеть запись потока 1 в течение нескольких секунд в довольно сложном приложении, которое выполняет другую работу.
1 ответ
Барьеры памяти не заставляют другие потоки видеть ваши магазины быстрее.(За исключением того, что блокирование более поздних загрузок может немного уменьшить конкуренцию за фиксацию буферизованных хранилищ.)
Буфер хранилища всегда пытается зафиксировать удаленные (известные не спекулятивные) хранилища в кэш L1d как можно быстрее. Это делает их глобально видимыми из-за MESI/MESIF/MOESI. Буфер хранилища не предназначен для использования в качестве подходящего кеша или буфера объединения записей (хотя он может объединять резервные хранилища в одну и ту же строку кэша), поэтому он должен опустошаться, чтобы освободить место для новых хранилищ. В отличие от кэша, он хочет держать себя пустым, а не полным.
Заборы / барьеры работают, заставляя текущий поток ждать, а не ускоряя видимость магазина.
Простая реализация полного барьера (mfence
илиlock
Операция ed) должна останавливать конвейер до тех пор, пока не будет исчерпан буфер хранилища, но высокопроизводительные реализации могут работать лучше и разрешать выполнение вне очереди отдельно от ограничения порядка памяти.
(К сожалению Skylake'smfence
полностью блокирует выполнение не по порядку, чтобы исправить неясную ошибку SKL079, связанную с загрузкой NT из памяти WC. Но lock add
или же xchg
или любой другой блок позже загружается из чтения L1d или буфера хранения, пока барьер не достигнет конца буфера хранения. А также mfence
на более ранних процессорах, вероятно, также не имеет этой проблемы.)
В целом, для архитектур не-x86 (которые имеют явные инструкции asm для более слабых барьеров памяти, как, например, только заборы StoreStore, не заботясь о нагрузках), принцип тот же: блокировать любые операции, которые ему нужно блокировать, пока это ядро не завершит более ранние операции любого типа. тип.
Связанные с:
Глобально невидимые инструкции по загрузке рассказывают о том, что означает, что груз должен стать глобально видимым.
Гарантирует ли барьер памяти, что согласованность кэша была завершена?
В конечном счете, вопрос, на который я пытаюсь ответить для себя, заключается в том, возможно ли для потока 2 не видеть запись потока 1 в течение нескольких секунд
Нет, в худшем случае задержка может быть чем-то вроде длины буфера хранилища ( 56 записей в Skylake, вместо 42 в BDW), умноженной на задержку кэширования, потому что сильная модель памяти x86 (без переупорядочения StoreStore) требует, чтобы хранилища фиксировали в порядке, Но RFO для нескольких строк кэша могут быть запущены одновременно, поэтому максимальная задержка может составлять 1/5 от этой (консервативная оценка: имеется 10 буферов заполнения строки). Также могут возникнуть конфликты с нагрузками, также находящимися в полете, но мы просто хотим получить номер обратной последовательности на порядок величины.
Допустим, задержка RFO (DRAM или от другого ядра) составляет 300 тактовых циклов (в основном составленных) на процессоре 3GHz. Так что наихудшая задержка для магазина, чтобы стать глобально видимой, может быть что-то вроде 300 * 56 / 5
= 3360 тактов ядра. Таким образом, на порядок, наихудший случай составляет около 1 микросекунды на процессоре 3GHz, который мы предполагаем. (Частота процессора компенсируется, поэтому оценка задержки RFO в наносекундах была бы более полезной).
Именно тогда все ваши магазины должны долго ждать RFO, потому что все они находятся в местах, которые не кэшированы или принадлежат другим ядрам. И ни один из них не находится в одной и той же строке кэша, поэтому никто не может объединиться в буфере хранилища. Поэтому обычно вы ожидаете, что это будет значительно быстрее.
Я не думаю, что есть какой-то вероятный механизм, чтобы он занимал даже сотню микросекунд, не говоря уже о целой секунде.