要約:少なくとも、ロードされた値がめったに変更されない場合は、ポインターを直接ロードするだけのパフォーマンスに近いとstd::atomic<int*>::load
予想していました。std::memory_order_relaxed
Visual Studio C ++ 2012の通常の負荷よりもアトミック負荷のパフォーマンスがはるかに悪いことがわかったので、調査することにしました。アトミックロードはコンペアアンドスワップループとして実装されていることがわかりましたが、これは可能な限り最速の実装ではないと思います。
質問std::atomic<int*>::load
:コンペアアンドスワップループを実行する必要がある理由はありますか?
背景:MSVC ++ 2012は、このテストプログラムに基づいて、ポインターのアトミックロードでコンペアアンドスワップループを実行していると思います。
#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;
}
__declspec(noinline)
アトミックロードに関連するアセンブリ命令を分離するために関数を使用しています。新しいMSVC++2012プロジェクトを作成し、x64プラットフォームを追加し、リリース構成を選択し、デバッガーでプログラムを実行して、逆アセンブリを確認しました。std::atomic<char>
とパラメータの両方std::atomic<int>
が同じ呼び出しを行うことにloadRelaxed<int>
なります-これはオプティマイザが行ったことである必要があります。呼び出される2つの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)
命令lock cmpxchg
はアトミックコンペアアンドスワップであり、ここで、、、またはをアトミックにロードするためのコードがchar
コンペアint
アンドint*
スワップループであることがわかります。また、このコードを32ビットx86用にビルドしましたが、その実装はまだに基づいていlock cmpxchg
ます。
質問std::atomic<int*>::load
:コンペアアンドスワップループを実行する必要がある理由はありますか?