Что именно делают /volatile:ms и /volatile:iso на x86 ?
От: Alexander G Украина  
Дата: 06.01.22 09:04
Оценка: 15 (2) +1
Из ветки Volatile и предупреждение C5220
Автор: Евгений Музыченко
Дата: 31.12.21


Давайте без срача "для портабельного кода нужен atomic" / "не хочу портабельный код, у меня всё работает".

По стандарту, volatile не имеет отношения к атомартности и memory ordering, т.е. не годится для многопоточной синхронизации.

Начиная с Visual Studio 2005, volatile является как бы атомиком с acquire/release семантикой.

В более поздних Visual Studio добавлен флаг /volatile:ms и /volatile:iso
/volatile:ms обеспечивает acquire/release семантику, и установлен по умолчанию на x86
/volatile:iso не обеспечивает acquire/release семантику, и установлен по умолчанию на ARM

Атомарность на самом деле гарантируется для правильно выровненных 32-битных типов, и 64-битных типов на x64.

Memory ordering гарантии бесплатны на x86 и не бесплатны на ARM, поэтому логика в /volatile:iso для ARM понятна.

Вопрос собственно: а к чему приведёт включение /volatile:iso на x86?

Вроде как на первый взгляд ни к чему:
* атомарность есть
* на уровне процессора acquire/release уже есть на x86 из-за total store order
* компилятор не переставляет volatile переменные относительно друг друга (не имеет право)
* компилятор не переставляет volatile переменные относительно другого кода (имеет право, но не был за этим замечен)




Пока только следующиее предположение. С некоторых пор компилятор компилятор создаёт метаданные для эмуляции x86 кода на ARM.
Есть недокументированная опция /volatileMetadata и /volatileMetadata- для управления этим (по умолчанию оно включено).
/volatileMetadata- отключает метаданные, что приводит к тому, что любые переменные становятся атомиками, что замедляет выполнение.

Возможно, при включенной опции /volatileMetadata эти метаданные не создаются для /volatile:iso кода, то есть, volatile не сработает для эмуляции как acquire-release.
Русский военный корабль идёт ко дну!
Re: Что именно делают /volatile:ms и /volatile:iso на x86 ?
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 06.01.22 09:36
Оценка:
Здравствуйте, Alexander G, Вы писали:

AG>Начиная с Visual Studio 2005, volatile является как бы атомиком с acquire/release семантикой.


Атомиком оно является именно "как бы", поскольку компилятор ничего не обещает в плане атомарности. Только запрет оптимизации, ничего больше. По сути — так же, как и в ANSI C, только чуть более конкретизировано поведение.
Re[2]: Что именно делают /volatile:ms и /volatile:iso на x86 ?
От: Alexander G Украина  
Дата: 06.01.22 09:49
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:


ЕМ>поскольку компилятор ничего не обещает в плане атомарности.


Платформа обещает

Simple reads and writes to properly-aligned 32-bit variables are atomic operations. In other words, you will not end up with only one portion of the variable updated; all bits are updated in an atomic fashion. However, access is not guaranteed to be synchronized. If two threads are reading and writing from the same variable, you cannot determine if one thread will perform its read operation before the other performs its write operation.

Simple reads and writes to properly aligned 64-bit variables are atomic on 64-bit Windows. Reads and writes to 64-bit values are not guaranteed to be atomic on 32-bit Windows. Reads and writes to variables of other sizes are not guaranteed to be atomic on any platform.


Да, понимаю, что непонятно как в Platform SDK документации могут обещать за компилятор, компилятор может генерировать что хочет.
На деле он, конечно, не будет разрывать простые типы, такие как инты или указатели.

Чтобы уже наверняка, есть интринсики __iso_volatile_load8 (16,32,64) и __iso_volatile_store8 (16,32,64), изначально для ARM, но уже есть и на x86.
(Через __iso_volatile_load64 / __iso_volatile_store64 можно атомарно загрузить-сохранить 64-битную переменную в 32-битном x86)
Русский военный корабль идёт ко дну!
Re: Что именно делают /volatile:ms и /volatile:iso на x86 ?
От: Максим Россия  
Дата: 06.01.22 09:59
Оценка:
AG> * на уровне процессора acquire/release уже есть на x86 из-за total store order

Вот это очень интересная для меня информация. Я правильно понял, что на х86 если какие-то данные сейчас лежат в store buffer одного ядра, то при попытке чтения соответствующей области памяти из другого ядра данные гарантированно "скинутся" из store buffer в общий кеш/память?
Errare humanum est
Re[2]: Что именно делают /volatile:ms и /volatile:iso на x86 ?
От: Alexander G Украина  
Дата: 06.01.22 10:25
Оценка: +1
Здравствуйте, Максим, Вы писали:

М>Вот это очень интересная для меня информация. Я правильно понял, что на х86 если какие-то данные сейчас лежат в store buffer одного ядра, то при попытке чтения соответствующей области памяти из другого ядра данные гарантированно "скинутся" из store buffer в общий кеш/память?


Нет. Для store buffer лишь гарантируется, что операции в нём не переупорядочиваются.
Русский военный корабль идёт ко дну!
Re[3]: Что именно делают /volatile:ms и /volatile:iso на x86 ?
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 06.01.22 10:29
Оценка:
Здравствуйте, Alexander G, Вы писали:

ЕМ>>поскольку компилятор ничего не обещает в плане атомарности.


AG>Платформа обещает


Я не увидел там обещания атомарности какого-нибудь x++. Это уже не simple read or write, оно может его раздельно прочитать и записать.

AG>Да, понимаю, что непонятно как в Platform SDK документации могут обещать за компилятор, компилятор может генерировать что хочет.


Так она написана под стандартный (для них) компилятор, кажется.
The God is real, unless declared integer.
Re[3]: Что именно делают /volatile:ms и /volatile:iso на x86 ?
От: Максим Россия  
Дата: 06.01.22 10:39
Оценка:
AG>Нет. Для store buffer лишь гарантируется, что операции в нём не переупорядочиваются.

Да, но тогда получается что, время когда второй поток увидит эти изменения никому неизвестно. Если логика программы завязана на данной переменной, то возможны сюрпризы, Разве не так?
Errare humanum est
Re[4]: Что именно делают /volatile:ms и /volatile:iso на x86 ?
От: Максим Россия  
Дата: 06.01.22 10:43
Оценка:
N>Я не увидел там обещания атомарности какого-нибудь x++.

Мне кажется, это уже CAS. Под атомарностью, скорее всего, подразумевается, что если писать одновременно 1 и 2, то не получишь в итоге 3, а будет валидное состояние.
Errare humanum est
Re[4]: Что именно делают /volatile:ms и /volatile:iso на x86 ?
От: Alexander G Украина  
Дата: 06.01.22 10:46
Оценка: 3 (1) +1
Здравствуйте, Максим, Вы писали:

М>Да, но тогда получается что, время когда второй поток увидит эти изменения никому неизвестно. Если логика программы завязана на данной переменной, то возможны сюрпризы, Разве не так?


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

Для любого store, что никто не увидит последующие store раньше данного.
Для любого load, никакой предшествующий load не будет позже данного.

Это достаточно для acquire/release.

Для sequentially consistent этого недостаточно, да, ибо store могут быть переупорядочены после load.
Русский военный корабль идёт ко дну!
Re[4]: Что именно делают /volatile:ms и /volatile:iso на x86 ?
От: Alexander G Украина  
Дата: 06.01.22 10:51
Оценка:
Здравствуйте, netch80, Вы писали:

N>Я не увидел там обещания атомарности какого-нибудь x++.


Разумеется, её нет.

Имелась в виду атомарность только load / store.
Русский военный корабль идёт ко дну!
Re[3]: Что именно делают /volatile:ms и /volatile:iso на x86 ?
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 06.01.22 11:02
Оценка:
Здравствуйте, Alexander G, Вы писали:

ЕМ>>поскольку компилятор ничего не обещает в плане атомарности.


AG>Платформа обещает


Это лишь о чтении/записи, и только выровненных данных в пределах ширины магистрали. Разве такие операции не везде атомарны? Даже представить не могу, для чего могло бы потребоваться выполнять их иначе, чем за один цикл.

AG>Да, понимаю, что непонятно как в Platform SDK документации могут обещать за компилятор, компилятор может генерировать что хочет.


MS уже давно перемешала C++ и Platform SDK. Традиционные malloc.h, stdio.h, errno.h и прочие теперь идут только в SDK, а с компилятором — только std, и excpt.h, stdarg.h и еще несколько файлов. Если поставить нынешнюю студию без SDK, то просто так собрать "Hello, world" не получится.

AG>Через __iso_volatile_load64 / __iso_volatile_store64 можно атомарно загрузить-сохранить 64-битную переменную в 32-битном x86


Это уже откровенное извращение через XMM.
Re[2]: Что именно делают /volatile:ms и /volatile:iso на x86 ?
От: okman Беларусь https://searchinform.ru/
Дата: 06.01.22 11:08
Оценка: 9 (1)
Здравствуйте, Максим, Вы писали:

М>...

М>Вот это очень интересная для меня информация. Я правильно понял, что на х86 если какие-то данные сейчас лежат в store buffer одного ядра,
М>то при попытке чтения соответствующей области памяти из другого ядра данные гарантированно "скинутся" из store buffer в общий кеш/память?

Максим, у Intel (и у AMD тоже) есть PDF в открытом доступе, там подробно расписано про гарантии атомарности, store buffers, сброс кэшей и т.п.
Посмотрите, если еще до этого не видели:

Combined Volume Set of Intel® 64 and IA-32 Architectures Software Developer’s Manuals
https://www.intel.com/content/dam/develop/public/us/en/documents/325462-sdm-vol-1-2abcd-3abcd.pdf
(декабрь'2021)

См., например, Volume 3, 8.2 Memory Ordering, 8.3 Serializing instructions, 11.10 Store Buffer и т.д.
Re: Что именно делают /volatile:ms и /volatile:iso на x86 ?
От: okman Беларусь https://searchinform.ru/
Дата: 06.01.22 11:10
Оценка:
Здравствуйте, Alexander G, Вы писали:

AG>Есть недокументированная опция /volatileMetadata и /volatileMetadata- для управления этим (по умолчанию оно включено).

AG>/volatileMetadata- отключает метаданные, что приводит к тому, что любые переменные становятся атомиками, что замедляет выполнение.

Спасибо. Можно ли где-то узнать больше про эту опцию? Сходу не загуглил...
Re[4]: Что именно делают /volatile:ms и /volatile:iso на x86
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 06.01.22 11:21
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>>>поскольку компилятор ничего не обещает в плане атомарности.

AG>>Платформа обещает
ЕМ>Это лишь о чтении/записи, и только выровненных данных в пределах ширины магистрали. Разве такие операции не везде атомарны? Даже представить не могу, для чего могло бы потребоваться выполнять их иначе, чем за один цикл.

Ну вот пример: у тебя есть структура вида

struct moo {
  unsigned a: 31;
  unsigned b: 5;
  unsigned c: 22;
  unsigned d: 6;
  unsigned e: 16;
} __attribute__((packed));


Посмотри, как твой компилятор делает чтение поля b. Он его сложно собирает из частей. Возможно, это байты. Это ещё понятно. А что будет с полем e? Его соберёт или нет? Оно ведь чётко 2 байта на границе 2 байт, почему бы и нет?
Я закинул код чтения двух полей на godbolt и начал смотреть разные компиляторы. И опаньки — clang для x86 нормально читает двухбайтное значение чтением по word ptr, а вот для RV32 почему-то начал побайтно извлекать:

get_e:                                  # @get_e
        lbu     a1, 9(a0)
        lbu     a0, 8(a0)
        slli    a1, a1, 8
        or      a0, a0, a1
        ret


Аааа за что, дяденьки? Он же мог простейший lhu применить...

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

(Ну да, если ты заточен на одну платформу и один компилятор, тебе пофиг. Мне не так.)

AG>>Через __iso_volatile_load64 / __iso_volatile_store64 можно атомарно загрузить-сохранить 64-битную переменную в 32-битном x86


ЕМ>Это уже откровенное извращение через XMM.


Почему, если XMM декларирован доступным?
The God is real, unless declared integer.
Отредактировано 06.01.2022 11:24 netch80 . Предыдущая версия .
Re[5]: Что именно делают /volatile:ms и /volatile:iso на x86 ?
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 06.01.22 11:29
Оценка: +1
Здравствуйте, Alexander G, Вы писали:

AG>Гарантии получаются из-за того, что относительно других изменений, сделанных данным потоком, конкретное изменение всегда будет видно всем другим потоком в том же порядке.


AG>Для любого store, что никто не увидит последующие store раньше данного.

AG>Для любого load, никакой предшествующий load не будет позже данного.

AG>Это достаточно для acquire/release.


Не совсем так, для acquire/release гарантии лучше сформулировать так:
— Для любого store, никто не увидит предшествующие load или store позже данного.
— Для любого load, никто не увидит последующие load или store раньше данного.

Разница с вашей формулировкой, что добавляется, что более поздний store упорядочен с более ранним load, а у вас этого нет.

Тут надо быть исключительно внимательным в мелочах, иначе потеряешь существенное

AG>Для sequentially consistent этого недостаточно, да, ибо store могут быть переупорядочены после load.


Да. Вот тут вы это сказали, а в предшествующих словах не уточнили
The God is real, unless declared integer.
Re[4]: Что именно делают /volatile:ms и /volatile:iso на x86
От: Alexander G Украина  
Дата: 06.01.22 11:35
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:


ЕМ>Это лишь о чтении/записи, и только выровненных данных в пределах ширины магистрали. Разве такие операции не везде атомарны? Даже представить не могу, для чего могло бы потребоваться выполнять их иначе, чем за один цикл.


Ну вот 64битный тип на 32-битной системе нет.
Но 32битный тип на 64битной системе — да.
Это уже менее "очевидно, что везде так".

На каком-нибудь CUDA нативных атомарных операций на 16 бит нет, что мешало бы иметь 64-битную архитектуру и без 32-битных атомарных операций?

ЕМ>Это уже откровенное извращение через XMM.


Или ещё большее извращение с FPU при /arch:IA32, но оно того может стоить, чтобы не все операции на 64-битный атомике делать через CAS.
(Чтобы случай чтения оптимизировать; также, если верить комментарию в исходниках, чтобы 64-битный атомик мог читаться из расшаренной только-для-чтения памяти)

Жаль, для на x64 для 128битного атомика такое "извращение" не пройдёт (нет гарантий со стороны процессора, хоть и на большинстве x64 процессоров выровненный 128битный тип разрываться не будет)
Русский военный корабль идёт ко дну!
Отредактировано 06.01.2022 11:45 Alexander G . Предыдущая версия .
Re[4]: Что именно делают /volatile:ms и /volatile:iso на x86
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 06.01.22 11:37
Оценка: 9 (1)
Здравствуйте, Максим, Вы писали:

AG>>Нет. Для store buffer лишь гарантируется, что операции в нём не переупорядочиваются.


М>Да, но тогда получается что, время когда второй поток увидит эти изменения никому неизвестно. Если логика программы завязана на данной переменной, то возможны сюрпризы, Разве не так?


В схожем обсуждении один коллега утверждал (ссылку не нахожу), что есть гарантия выдачи всех результатов команд в память-и-кэши в течение 10 наносекунд.
И в общем случае процессор заинтересован скинуть результаты выполнения команд как можно быстрее, потому что store buffer не резиновый и нефиг тянуть со сбросом его результатов.

Поэтому, если, например, там какие-то счётчики, которые потом снимаются раз в секунду, то ускорение сброса этих значений всем по барабану.

А вот правило, что каждая операция записи имеет release semantics, приводит к тому, что при активной работе задержки с публикацией не будет совсем. Ну а где надо — можно и через sfence подпереть костыликом.

Мааленькая поправка — Intel сейчас дословно говорит

Writes to memory are not reordered with other writes, with the following exceptions:

— streaming stores (writes) executed with the non-temporal move instructions (MOVNTI, MOVNTQ, MOVNTDQ, MOVNTPS, and MOVNTPD); and
— string operations (see Section 8.2.4.1).


Про string operations — там порядок может нарушаться только между разными записями в одной операции. А вот NT запись... ну кто её применяет — следить надо.
The God is real, unless declared integer.
Отредактировано 06.01.2022 11:40 netch80 . Предыдущая версия .
Re[2]: Что именно делают /volatile:ms и /volatile:iso на x86 ?
От: Alexander G Украина  
Дата: 06.01.22 11:38
Оценка: 10 (1)
Здравствуйте, okman, Вы писали:

O>Спасибо. Можно ли где-то узнать больше про эту опцию? Сходу не загуглил...


Очередная недокументированная опция, всё что я знаю — из этого комментария:
https://developercommunity.visualstudio.com/t/-readwritebarrier-intrinsic-emits-unnecessary-code/1538997#T-N1629968
Русский военный корабль идёт ко дну!
Re[5]: Что именно делают /volatile:ms и /volatile:iso на x86 ?
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 06.01.22 11:50
Оценка:
Здравствуйте, Alexander G, Вы писали:

AG>На каком-нибудь CUDA нативных атомарных операций на 16 бит нет, что мешало бы иметь 64-битную архитектуру и без 32-битных атомарных операций?


Вообще-то более широкая атомарная операция автоматом подразумевает атомарность для данных менее широкой операции.
Чтение, запись, CAS — именно так. Инкремент какой-нибудь — уже надо следить, чтобы соседние данные не запортить,
но если ABA пофиг (почти всегда), то CAS и тут поможет.

RISC-V имеет атомарные операции на 32 и 64 бита, но не на более узкий тип. Реальный живой пример. CAS делается через LL/SC (ABA проблемы нет).

x86 и ARM с атомарными операциями любого размера тут откровенно расслабили всех.

AG>Жаль, для на x64 для 128битного атомика такое "извращение" не пройдёт (нет гарантий со стороны процессора, хоть и на большинстве x64 процессоров выровненный 128битный тип разрываться не будет)


Почему не пройдёт? CMPXCHG16B уже много лет как есть.
The God is real, unless declared integer.
Re[6]: Что именно делают /volatile:ms и /volatile:iso на x86 ?
От: Alexander G Украина  
Дата: 06.01.22 11:58
Оценка:
Здравствуйте, netch80, Вы писали:


AG>>Жаль, для на x64 для 128битного атомика такое "извращение" не пройдёт (нет гарантий со стороны процессора, хоть и на большинстве x64 процессоров выровненный 128битный тип разрываться не будет)


N>Почему не пройдёт? CMPXCHG16B уже много лет как есть.


Вот им и делать всё, даже load/store.
Что несколько не то по эффективности, чем если бы можно было рассчитывать на атомарность movdq.
Русский военный корабль идёт ко дну!
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.