powered by simpleCommunicator - 2.0.27     © 2024 Programmizd 02
Map
Форумы / C++ [игнор отключен] [закрыт для гостей] / Помогите понять макрос
11 сообщений из 11, страница 1 из 1
Помогите понять макрос
    #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
Помогите понять макрос
    #40096193
White Owl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Фигня это какая-то.
Выбор максимального значения при сравнении младшего байта. Нафига тут ассемблер совершенно не понятно.
...
Рейтинг: 0 / 0
Помогите понять макрос
    #40096233
euru
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
На вход макроса подаются значения размером 1 байт.
У меня тоже получилось, что макрос возвращает только не максимальное, а минимальное значение.
Но такое нагромождение кода заставило меня усомниться, что я, возможно, что-то упускаю.
...
Рейтинг: 0 / 0
Помогите понять макрос
    #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
Помогите понять макрос
    #40096301
rdb_dev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Так как макрос оторван от контекста использования, моё предположение об использовании в качестве счётчика захватов ресурса может быть ошибочным.
...
Рейтинг: 0 / 0
Помогите понять макрос
    #40096580
euru
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
rdb_dev, правильно ли я понимаю, что этот макрос - это некий аналог функции min, учитывающий особенности многопоточного выполнения?

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

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

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

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

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

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


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