Гость
Форумы / C++ [игнор отключен] [закрыт для гостей] / Помогите понять макрос / 11 сообщений из 11, страница 1 из 1
09.09.2021, 01:10
    #40096181
euru
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите понять макрос
Помогите понять, что делает следующий макрос:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
#define SET_CAPT_VALUE(x,v) \
do { uint8_t dummy = v; _asm_( \
"movb %0, %%al\n" \
"0:\n\t" \
"cmpb %1, %%al\n\t" \
"jbe 1f\n\t" \
"lock cmpxchgb %1, %0\n\t" \
"jnz 0b\n" \
"1:" \
: "+m" (x), "+r" (dummy) : : "eax"); } while (0)
...
Рейтинг: 0 / 0
09.09.2021, 05:21
    #40096193
White Owl
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите понять макрос
Фигня это какая-то.
Выбор максимального значения при сравнении младшего байта. Нафига тут ассемблер совершенно не понятно.
...
Рейтинг: 0 / 0
09.09.2021, 09:52
    #40096233
euru
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите понять макрос
На вход макроса подаются значения размером 1 байт.
У меня тоже получилось, что макрос возвращает только не максимальное, а минимальное значение.
Но такое нагромождение кода заставило меня усомниться, что я, возможно, что-то упускаю.
...
Рейтинг: 0 / 0
09.09.2021, 11:48
    #40096293
rdb_dev
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите понять макрос
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:"
...
Рейтинг: 0 / 0
09.09.2021, 12:10
    #40096301
rdb_dev
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите понять макрос
Так как макрос оторван от контекста использования, моё предположение об использовании в качестве счётчика захватов ресурса может быть ошибочным.
...
Рейтинг: 0 / 0
10.09.2021, 00:32
    #40096580
euru
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите понять макрос
rdb_dev, правильно ли я понимаю, что этот макрос - это некий аналог функции min, учитывающий особенности многопоточного выполнения?

И еще пара вопросов:
1. Зачем нужен внешний цикл "do { } while (0)"? Только для того чтобы гарантировать отсутствие конфликта имен переменной dummy в макросе с такой же переменной вне макроса?

2. Допустим, при вызове макроса значение "x" было меньше значения "v". Но пока мы его копировали в регистр, сравнивали копию со значением "v", значение в "x" обновилось и стало больше значения в "v". Тогда, получается, упрощенная проверка с "mov" и "cmp" становится некорректной. и макрос вернет неправильное значение. В чем смысл тогда такой сложной обработки для варианта, когда "x" больше "v"?
...
Рейтинг: 0 / 0
10.09.2021, 00:58
    #40096583
Siemargl
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите понять макрос
euru,

потокобезопасная запись в x:=v если x < v

какой то многопоточный поиск максимума
...
Рейтинг: 0 / 0
10.09.2021, 05:38
    #40096593
White Owl
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите понять макрос
euru
1. Зачем нужен внешний цикл "do { } while (0)"? Только для того чтобы гарантировать отсутствие конфликта имен переменной dummy в макросе с такой же переменной вне макроса?

Не только. Это еще и защита для случаев если кто-то запихнул вызов макроса в выражение в качестве операнда, или параметром в функцию.
...
Рейтинг: 0 / 0
10.09.2021, 10:48
    #40096641
rdb_dev
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите понять макрос
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.
#ifndef MYSYNC_H
#define MYSYNC_H

#include <stdint.h>

static
inline __attribute__( (always_inline) )
uint8_t set_capt_value
    (
      volatile      
      uint8_t & x,
      uint8_t   v
    )
{
  asm volatile
  ("\
    .p2align 3\n\
    again%=:\n\
      cmp %[v], %%al\n\
      jbe done%=\n\
      lock cmpxchg %[v], %[x]\n\
      je done%=\n\
      pause\n\
      jmp again%=\n\
    done%=:\n\
    "
    : "=a" (v), [x] "=m" (x)
    : "0" (x), [v] "r" (v)
    : "cc"
  );
  return v;
}

#endif  //-- #ifndef MYSYNC_H

main.cpp
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
#include <cstdlib>
#include <cstdio>

#include "mysync.h"

int main( int argc, char** argv )
{
  volatile
  uint8_t x = 10;

  uint8_t v = set_capt_value( x, 5 );

  std::printf( "\nx = %hhu\nv = %hhu\n", x, v );

  return 0;
}

Кстати, в макросе из топикстарта ошибка - не указан клоббер изменения регистра флагов.
Компилятор 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.
main:
.LFB81:
	subq	$56, %rsp
	.seh_stackalloc	56
	.seh_endprologue
	call	__main
	movb	$10, 47(%rsp)
	movl	$5, %edx
	movzbl	47(%rsp), %eax
/APP
 # 15 "mysync.h" 1
	    .p2align 3
    again42:
      cmp %dl, %al
      jbe done42
      lock cmpxchg %dl, 47(%rsp)
      je done42
      pause
      jmp again42
    done42:
    
 # 0 "" 2
/NO_APP
	movzbl	47(%rsp), %edx
	movzbl	%al, %r8d
	leaq	.LC0(%rip), %rcx
	call	_Z6printfPKcz
	xorl	%eax, %eax
	addq	$56, %rsp
	ret

Результат:
Код: plaintext
1.
x = 5
v = 10
...
Рейтинг: 0 / 0
10.09.2021, 13:47
    #40096702
Siemargl
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите понять макрос
rdb_dev,

в клоббере на измы и указан eax
...
Рейтинг: 0 / 0
10.09.2021, 14:08
    #40096707
rdb_dev
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите понять макрос
Siemargl, клоббер "eax" там не нужен, потому как в моём примере, в параметрах есть прямое указание на использование аккумулятора: "=a" для получения результата и "0" - для установки AL.
...
Рейтинг: 0 / 0
Форумы / C++ [игнор отключен] [закрыт для гостей] / Помогите понять макрос / 11 сообщений из 11, страница 1 из 1
Целевая тема:
Создать новую тему:
Автор:
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]