|
Помогите понять макрос
|
|||
---|---|---|---|
#18+
Помогите понять, что делает следующий макрос: Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.
... |
|||
:
Нравится:
Не нравится:
|
|||
09.09.2021, 01:10 |
|
Помогите понять макрос
|
|||
---|---|---|---|
#18+
Фигня это какая-то. Выбор максимального значения при сравнении младшего байта. Нафига тут ассемблер совершенно не понятно. ... |
|||
:
Нравится:
Не нравится:
|
|||
09.09.2021, 05:21 |
|
Помогите понять макрос
|
|||
---|---|---|---|
#18+
На вход макроса подаются значения размером 1 байт. У меня тоже получилось, что макрос возвращает только не максимальное, а минимальное значение. Но такое нагромождение кода заставило меня усомниться, что я, возможно, что-то упускаю. ... |
|||
:
Нравится:
Не нравится:
|
|||
09.09.2021, 09:52 |
|
Помогите понять макрос
|
|||
---|---|---|---|
#18+
euru, во-первых, White Owl упускает тот факт, что код на ассемблере приведён не в нотации Intel, а в нотации AT&T - сначала источник, затем приёмник, поэтому в "dummy" возвращается минимальное значение. Во-вторых, ты упускаешь тот факт, что "lock cmpxchg" (сравнить и обменяться значениями, если аргумент в памяти равен значению в аккумуляторе) выполняется с блокировкой системной шины (если контроллер памяти на чипсете) или шины памяти (если контроллер памяти на процессоре) и оперирует с данными непосредственно в памяти. Причём, в приведённом алгоритме, вначале используется "relaxed" сравнение - сравнение со значением аргумента "x", которое уже может находится в кэше процессора, с аргументом "dummy" и если "x" < "dummy", то алгоритм пытается поменять значения "x" и "dummy" (в "dummy" будет старое значение из "x", а в "x" - новое значение из "dummy") командой cmpxchg с блокировкой шины и если значение в регистре AL, прочитанное командой "movb %0, %%al" всё ещё равно значению "x" непосредственно в памяти, то выполняется обмен значениями между "dummy" и "x" в памяти. Такая последовательность сделана из-за того, что операции с блокировкой шины очень затратны и их частое использование приводит к снижению производительности, поэтому сначала используется менее затратные "mov" и "cmp", выполнение которых не приводит к блокировке шины, если кэшлайн с "x" не инвалидирован. Если при выполнении "cmpxchg" выяснится, что реальное значение в памяти не совпадает с прочитанным ранее (значение из кэша устарело), то процедура повторяется. Иными словами, это обычная, использующая счётчик захватов спин-блокировка какого-то ресурса для, как правило, многопоточного приложения. Написана, правда, кривовато, и не воткнули выравнивание метки "0:", и pause . Если вставлять pause, то надо переписать концовку: "lock cmpxchgb %1, %0;\n\ je 1f\n\ pause;\n\ jmp 0b;\n\ 1:" ... |
|||
:
Нравится:
Не нравится:
|
|||
09.09.2021, 11:48 |
|
Помогите понять макрос
|
|||
---|---|---|---|
#18+
Так как макрос оторван от контекста использования, моё предположение об использовании в качестве счётчика захватов ресурса может быть ошибочным. ... |
|||
:
Нравится:
Не нравится:
|
|||
09.09.2021, 12:10 |
|
Помогите понять макрос
|
|||
---|---|---|---|
#18+
rdb_dev, правильно ли я понимаю, что этот макрос - это некий аналог функции min, учитывающий особенности многопоточного выполнения? И еще пара вопросов: 1. Зачем нужен внешний цикл "do { } while (0)"? Только для того чтобы гарантировать отсутствие конфликта имен переменной dummy в макросе с такой же переменной вне макроса? 2. Допустим, при вызове макроса значение "x" было меньше значения "v". Но пока мы его копировали в регистр, сравнивали копию со значением "v", значение в "x" обновилось и стало больше значения в "v". Тогда, получается, упрощенная проверка с "mov" и "cmp" становится некорректной. и макрос вернет неправильное значение. В чем смысл тогда такой сложной обработки для варианта, когда "x" больше "v"? ... |
|||
:
Нравится:
Не нравится:
|
|||
10.09.2021, 00:32 |
|
Помогите понять макрос
|
|||
---|---|---|---|
#18+
euru, потокобезопасная запись в x:=v если x < v какой то многопоточный поиск максимума ... |
|||
:
Нравится:
Не нравится:
|
|||
10.09.2021, 00:58 |
|
Помогите понять макрос
|
|||
---|---|---|---|
#18+
euru 1. Зачем нужен внешний цикл "do { } while (0)"? Только для того чтобы гарантировать отсутствие конфликта имен переменной dummy в макросе с такой же переменной вне макроса? Не только. Это еще и защита для случаев если кто-то запихнул вызов макроса в выражение в качестве операнда, или параметром в функцию. ... |
|||
:
Нравится:
Не нравится:
|
|||
10.09.2021, 05:38 |
|
Помогите понять макрос
|
|||
---|---|---|---|
#18+
euru, по хорошему, это можно реализовать вообще без ассемблера - на std::atomic в C++ или на built-in функциях GNU C . Если очень хочется, можно и на GNU inline assembler, но без дурацких макроопределений: mysync.h Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34.
main.cpp Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16.
Компилятор C++ не "смотрит" что внутри ассемблерной вставки, поэтому ему нужно правильно задавать клобберы, по которым компилятор будет знать что и как меняется внутри. Клоббер "cc" после третьего двоеточия как раз отвечает за уведомление компилятору о возможном изменении регистра флагов внутри ассемблерной вставки. Компилируем, и смотрим, что получилось: g++ -m64 -O2 -S -std=c++11 -o main.asm main.cpp Код: asm 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30.
Код: plaintext 1.
... |
|||
:
Нравится:
Не нравится:
|
|||
10.09.2021, 10:48 |
|
Помогите понять макрос
|
|||
---|---|---|---|
#18+
rdb_dev, в клоббере на измы и указан eax ... |
|||
:
Нравится:
Не нравится:
|
|||
10.09.2021, 13:47 |
|
|
start [/forum/topic.php?fid=57&msg=40096181&tid=2017174]: |
0ms |
get settings: |
17ms |
get forum list: |
14ms |
check forum access: |
1ms |
check topic access: |
1ms |
track hit: |
38ms |
get topic data: |
6ms |
get forum data: |
1ms |
get page messages: |
349ms |
get tp. blocked users: |
0ms |
others: | 11ms |
total: | 438ms |
0 / 0 |