tgoop.com/gdb_dbg/8
Last Update:
Про software-barriers (часть 1)
Недавно у нас во внутреннем тестировании стали происходить спорадичные развалы в части рантайма, где уже очень давно все было прекрасно отлажено и работало, как часы. Точнее не скажу, чтобы не нарушать NDA, да это и не так важно.
Но что интересно: случаться они стали на новом тестовом сервере, который совсем недавно пришел (12th Gen Intel(R) Core i7-12700). А что еще интереснее: авторы этого модуля в рантайме не очень удивились, отреагировали буквально: "Что же, это все-таки случилось, ожидаемо. Чиним". Стоит ли говорить, что я был жутко заинтригован, когда это услышал! (совершенно был не в контексте этого куска кода).
--
Поспрашивал у ребят, потом почитал сам, и вот что выяснилось.
Довольно известный факт, что написанные подряд машинные инструкции могут исполнится в "переставленном" порядке. Процессор имеет на это право в некоторых случаях, а уж особенно интересными становятся инструкции работающие с памятью. Гарантируется ли вам, что значение, которое вы записали по некоторому адресу, будет видно при последующих чтениях? Все не так просто при наличии многих CPU. Про такую вещь, как store buffering рассказывал Саша Филатов на последнем SnowOne, вот здесь (рекомендую весь доклад к просмотру, он отличный). Этим особенно славятся слабые модели памяти (привет, ARM), хотя и на интеле это тоже вполне себе встречается:
8.2.3.4 Loads May Be Reordered with Earlier Stores to Different Locations
The Intel-64 memory-ordering model allows a load to be reordered with an earlier store to a different location. However, loads are not reordered with stores to the same location.
Но, как видите, некоторые гарантии все-таки имеются: load-ы не будут поменяны со store-ами в одну и туже память (звучит, конечно, очень логично).
Однако, тут возникает интересный вопрос: а что, если наши чтения и запись оперируют с разными размерами? Допустим, есть у вас адрес, вы туда сначала пишите байт, а потом читаете машинной слово:
mov byte [rcx], 1
mov eax, qword [rcx]
И еще интереснее, а что, если мы запишем нижний байт по этому адресу, а потом прочитаем все слово (т.е. по факту даже адрес будет отличаться):
mov byte [rcx + 8], 1
mov eax, qword [rcx]
Можно консервативно предположить, что такие инструкции могут быть переставлены (обратного в спеке не сказано). Тогда здесь мы просто обязаны вставлять тяжелые хардверные барьеры (типа
mfence
), если хотим этого избежать. Что очень грустно, ведь это резко просадит производительность такого кода.Но по факту то в спеке не сказано и того, что такие инструкции могут переставляться. И вот мы в некой серой зоне, и тут то и начинается самое интересное!
--
Оказывается, есть некое тайное знание, что хоть спека явного этого и не гарантирует, интеловское железо обычно устроено так, что на это можно полагаться. Такой трюк как раз и называется software barriers (вы вместо тяжелых машинных инструкций для барьера просто генерируете специальный легковесный паттерн в коде, который дает такую же семантику).
Вот здесь можно наблюдать косвенные признаки такого поведения в виде отсутствия store to load forwarding. Кроме того, это поведение упоминалось в Intel VTune мануале (чуваки явно что-то знали). Наконец, в статье про похожую на нашу часть рантайма от 2004 года упоминалось, что бенчи были померены именно в предположении такого поведения процессора, а еще похожий трюк использовался в рантайме OpenJ9 VM.
При этом, если заглянуть чуть глубже в устройство процессора, вспомнить про протоколы когерентностей кэшей, а именно MESI, то станет понятно, что никаких гарантий тут быть не может. Подробный разбор есть в первых двух прекрасных ответах на вот этот вопрос на StackOverflow.
Итого, на лицо ситуация:
BY Алло, это отладочная?

Share with your friend now:
tgoop.com/gdb_dbg/8