@IwillnotexistIdonotexist: Хорошо заметили. Я думаю, это означает, что вы можете получить одну широкую запись MMIO для смежных немаскированных элементов или две узкие. Но выполнение одного выровненного 8-байтового атомарного хранилища все же дает атомарность для 4-байтовых половинок, хотя для MMIO это не так. Поэтому я не думаю, что это исключает атомарность для каждого элемента, потому что специфичная для реализации часть может быть только объединением хранилищ элементов в более широкие и все еще атомарные хранилища.

отрим массив какatomic<int32_t> shared_array[], Что делать, если вы хотите SIMD векторизацииfor(...) sum += shared_array[i].load(memory_order_relaxed)?. Или искать в массиве первый ненулевой элемент или обнулять его диапазон? Это, вероятно, редко, но рассмотримЛюбой случай использования, где разрыв внутри элемента не разрешен, но переупорядочение между элементами в порядке. (Возможно, поиск, чтобы найти кандидата на CAS).

I думать Выровненные по x86 векторные загрузки / хранилища на практике было бы безопасно использовать для SIMD сmo_relaxed$7, Что делать, если вы хотите SIMD векторизации8$

«Инструкция x87 или инструкция SSE, которая осуществляет доступ к данным, большим, чем четырехугольное слово, может быть реализована с использованием множественного доступа к памяти».

Нет гарантии, что доступ к этим компонентам будет естественным, неперекрывающимся или чем-то еще. (Забавный факт: x87 10-байтовыйfld m80 нагрузки, выполненные с помощью двух загрузочных мопов и двух ALU-мопов на Haswell,по словам Агнер Фог, предположительно qword + word.)

Если вы хотите векторизовать подход, ориентированный на будущее, который, как говорят текущие руководства по x86, будет работать на всех будущих процессорах x86, вы можете загрузить / сохранить в виде фрагментов 8B сmovq / movhps.

Или, может быть, вы могли бы использовать 256bvpmaskmovd с истинной маскойпотому что в разделе «Эксплуатация» руководства он определяется в терминах нескольких отдельных 32-разрядных нагрузок, напримерLoad_32(mem + 4), Означает ли это, что каждый элемент действует как отдельный 32-битный доступ, гарантируя атомарность внутри этого элемента?

(На реальном оборудовании, это 1 загрузка и 2 порта5 uops на Haswell, или на Ryzen только 1 или 2 загрузки + ALU uops (128/256). Я предполагаю, что это для случая, когда не нужно исключать исключения из элементов, которые идут на неотображенную страницу, так как это может быть медленнее (но IDK, если ему нужна помощь с микрокодом). Во всяком случае, это говорит нам, что это по крайней мере так же атомарно, как обычноvmovdqa загрузить на Haswell, но это ничего не говорит нам о x86 Deathstation 9000, где векторные обращения 16B / 32B разбиты на однобайтовые, так что внутри каждого элемента может быть разрыв.

Я думаю, что в действительности можно предположить, что вы не увидите разрыв в 16, 32 или 64-битном элементе длявыровненный вектор загружает / сохраняет на любом реальном процессоре x86, потому что это не имеет смысла для эффективной реализации, которая уже должна сохранять естественным образом выровненные 64-битные скалярные хранилища на атомарном уровне, ноИнтересно узнать, как далеко идут гарантии в руководствах.)

Сбор (AVX2, AVX512) / Scatter (AVX512)

Инструкции какvpgatherdd более очевидно состоят из нескольких отдельных 32b или 64b доступов. Форма AVX2задокументировано как делать несколькоFETCH_32BITS(DATA_ADDR); по-видимому, на это распространяются обычные гарантии атомарности, и каждый элемент будет собираться атомарно, если он не пересекает границу.

AVX512 собираетсязадокументированы в справочном руководстве Intel в формате PDF insn. как
DEST[i+31:i] <- MEM[BASE_ADDR + SignExtend(VINDEX[i+31:i]) * SCALE + DISP]), 1) для каждого элемента в отдельности. (Упорядочение: элементы могут быть собраны в любом порядке, но ошибки должны доставляться в порядке справа налево. Упорядочение памяти с другими инструкциями следует модели упорядочения памяти Intel-64.)

AVX512рассеивает задокументированы (страница 1802 предыдущей ссылки) таким же образом. Атомность не упоминается, но они охватывают некоторые интересные угловые случаи:

Если два или более целевых индекса полностью перекрываются, «более ранние» записи могут быть пропущены.

Элементы могут быть разбросаны в любом порядке, но ошибки должны доставляться в порядке справа налево

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

Только записи в перекрывающиеся индексы векторов гарантированно упорядочены относительно друг друга (от LSB до MSB исходных регистров). Обратите внимание, что это также включает частично перекрывающиеся векторные индексы. Записи, которые не перекрываются, могут происходить в любом порядке. Упорядочение памяти с другими инструкциями следует модели упорядочения памяти Intel-64. Обратите внимание, что это не учитывает неперекрывающиеся индексы, которые отображаются в те же местоположения физических адресов.

(то есть, потому что одна и та же физическая страница отображается в виртуальной памяти по двум разным виртуальным адресам. Таким образом, обнаружение перекрытия может происходить до (или параллельно) с преобразованием адресов без перепроверки после.)

Я включил последние два, потому что это интересные угловые случаи, о которых я даже не думал удивляться. Самомодифицирующийся случай забавен, хотя я думаюrep stosd будет иметь ту же проблему (это также прерывается, используяrcx отслеживать прогресс).

Я думаю, что атомарность является частью модели упорядочения памяти Intel-64, поэтому тот факт, что они упоминают об этом и не говорят ничего другого, по-видимому, подразумевает, что доступ к элементу является атомарным. (Сбор двух соседних элементов 4B почти наверняка не считается одним доступом 8B.)

Какие инструкции по загрузке / сохранению векторов гарантируются в руководствах x86 как атомарные для каждого элемента?

Экспериментальное тестирование на реальном оборудовании почти наверняка скажет мне, что на моем процессоре Skylake все атомарно, и вопрос не в этом.Я спрашиваю, правильна ли моя интерпретация руководств дляvmaskmov / vpmaskmov нагрузки, а для сбора / разброса.

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

Сноска: основы атомности x86:

В x86 естественно выровненные нагрузки и накопители 8B или ужегарантированно будут атомнымив соответствии с инструкциями Intel и AMD. Фактически, для кэшированных обращений любой доступ, который не пересекает границу 8B, также является атомарным. (На Intel P6 и более поздних версиях дайте более сильную гарантию, чем AMD: невыровненный в строке кэша (например, 64B) является атомарным для кэшированного доступа).

Векторные нагрузки / хранилища 16B или более не гарантируются как атомарные. Они находятся на некоторых процессорах (по крайней мере, для кэшированного доступа, когда наблюдателями являются другие процессоры), но даже атомарный доступ шириной 16B к кэшу L1D не делает его атомарным. Например, протокол связности HyperTransport между сокетами для AMD K10 Opteronsвводит разрыв между половинами выровненного вектора 16Bдаже если тестирование потоков в одном сокете (физическом процессоре) не вызывает разрывов.

(Если вам нужна полная 16B атомная нагрузка или хранилище, вы можете взломать ее с помощьюlock cmpxchg16b как GCC делает дляstd::atomic<T>, но этоужасный для исполнения. Смотрите такжеАтомная двойная с плавающей точкой или SSE / AVX векторная загрузка / сохранение на x86_64.)

Ответы на вопрос(0)

Ваш ответ на вопрос