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?