Czy std :: atomic <int *> :: load wykonuje pętlę porównania i zamiany?

streszczenie: Spodziewałem się tegostd::atomic<int*>::load zstd::memory_order_relaxed byłby zbliżony do wydajności bezpośredniego ładowania wskaźnika, przynajmniej wtedy, gdy załadowana wartość rzadko się zmienia. Widziałem znacznie gorszą wydajność dla obciążenia atomowego niż normalne obciążenie w Visual Studio C ++ 2012, więc postanowiłem zbadać. Okazuje się, że obciążenie atomowe jest zaimplementowane jakoporównaj i zamień pętla, która, jak podejrzewam, nie jest najszybszą możliwą implementacją.

Pytanie: Czy jest jakiś powódstd::atomic<int*>::load musi wykonać pętlę porównania i zamiany?

tło: Wierzę, że MSVC ++ 2012 wykonuje pętlę porównania i wymiany na obciążeniu atomowym wskaźnika opartego na tym programie testowym:

#include <atomic>
#include <iostream>

template<class T>
__declspec(noinline) T loadRelaxed(const std::atomic<T>& t) {
  return t.load(std::memory_order_relaxed);
}

int main() {
  int i = 42;
  char c = 42;
  std::atomic<int*> ptr(&i);
  std::atomic<int> integer;
  std::atomic<char> character;
  std::cout
    << *loadRelaxed(ptr) << ' '
    << loadRelaxed(integer) << ' '
    << loadRelaxed(character) << std::endl;
  return 0;
}

Używam__declspec(noinline) funkcja w celu odizolowania instrukcji montażu związanych z obciążeniem atomowym. Zrobiłem nowy projekt MSVC ++ 2012, dodałem platformę x64, wybrałem konfigurację wydania, uruchomiłem program w debuggerze i sprawdziłem demontaż. Okazuje się, że obastd::atomic<char> istd::atomic<int> parametry kończą się tym samym wywołaniemloadRelaxed<int> - to musi być coś, co zrobił optymalizator. Oto demontaż dwóch nazwanych instancji loadRelaxed:

loadRelaxed<int * __ptr64>

000000013F4B1790  prefetchw   [rcx]  
000000013F4B1793  mov         rax,qword ptr [rcx]  
000000013F4B1796  mov         rdx,rax  
000000013F4B1799  lock cmpxchg qword ptr [rcx],rdx  
000000013F4B179E  jne         loadRelaxed<int * __ptr64>+6h (013F4B1796h)  

loadRelaxed<int>

000000013F3F1940  prefetchw   [rcx]  
000000013F3F1943  mov         eax,dword ptr [rcx]  
000000013F3F1945  mov         edx,eax  
000000013F3F1947  lock cmpxchg dword ptr [rcx],edx  
000000013F3F194B  jne         loadRelaxed<int>+5h (013F3F1945h)  

Instrukcjalock cmpxchg jest atomowyporównaj i zamień i widzimy tutaj, że kod atomowego ładowania achar, anint lubint* jest pętlą porównania i wymiany. Zbudowałem również ten kod dla 32-bitowego x86 i że implementacja jest nadal oparta nalock cmpxchg.

Pytanie: Czy jest jakiś powódstd::atomic<int*>::load musi wykonać pętlę porównania i zamiany?

questionAnswers(1)

yourAnswerToTheQuestion