Занятый опрос std :: atomic - msvc оптимизирует петлю - почему и как предотвратить? - PullRequest
0 голосов
/ 29 ноября 2018

Я пытаюсь реализовать простую функцию занятого цикла.

Это должно продолжать опрашивать переменную std :: atomic максимальное количество раз (spinCount) и возвращать true, если статус действительно изменился (на что-либо, кроме NOT_AVAILABLE) в данных попытках, или false в противном случае:

// noinline is just to be able to inspect the resulting ASM a bit easier - in final code, this function SHOULD be inlined!
__declspec(noinline) static bool trySpinWait(std::atomic<Status>* statusPtr, const int spinCount)
{
    int iSpinCount = 0;
    while (++iSpinCount < spinCount && statusPtr->load() == Status::NOT_AVAILABLE);
    return iSpinCount == spinCount;
}

Однако, похоже, что MSVC просто оптимизирует цикл в режиме Release для Win64.Я очень плохо отношусь к Assembly, но мне не кажется, что она вообще пытается прочитать значение statusPtr:

int iSpinCount = 0;
000000013F7E2040  xor         eax,eax  
    while (++iSpinCount < spinCount && statusPtr->load() == Status::NOT_AVAILABLE);
000000013F7E2042  inc         eax  
000000013F7E2044  cmp         eax,edx  
000000013F7E2046  jge         trySpinWait+12h (013F7E2052h)  
000000013F7E2048  mov         r8d,dword ptr [rcx]  
000000013F7E204B  test        r8d,r8d  
000000013F7E204E  je          trySpinWait+2h (013F7E2042h)  
    return iSpinCount == spinCount;
000000013F7E2050  cmp         eax,edx  
000000013F7E2052  sete        al  

У меня сложилось впечатление, что std :: atomic с std ::memory_order_sequential_cst создает барьер компилятора, который должен предотвращать что-то подобное, но, похоже, это не так (или, скорее, мое понимание, вероятно, было неправильным).

Что я делаю здесь неправильно, или, скорее, - как я могу лучше всего реализоватьэтот цикл без его оптимизации, с наименьшим влиянием на общую производительность?

Я знаю, что мог бы использовать #pragma optimize ("", off), но (кроме как в примере выше), в моем конечном кодеЯ бы очень хотел, чтобы этот вызов был встроен в более крупную функцию по соображениям производительности.Кажется, что эта #pragma, как правило, предотвращает встраивание.

Цени любые мысли!

Спасибо

1 Ответ

0 голосов
/ 29 ноября 2018

, но мне не кажется, что он вообще пытается прочитать значение statusPtr

Он перезагружает его на каждой итерации цикла:

000000013F7E2048  mov         r8d,dword ptr [rcx] # rcx is statusPtr

У меня сложилось впечатление, что std::atomic с std::memory_order_sequential_cst создает барьер компилятора, который должен предотвращать что-то подобное,

Вам не нужно ничего больше, чем std::memory_order_relaxed здесь, потому что есть только одна переменная, совместно используемая потоками (более того, этот код не меняет значение атомарной переменной).Нет проблем с переупорядочением.

Другими словами, эта функция работает должным образом.

Возможно, вы захотите использовать инструкцию PAUSE, см. Повышение производительности и производительности Sleep Loops .

...