2012-11-03 16 views
5

Özet: std::memory_order_relaxed ile std::atomic<int*>::load'un, en azından yüklenen değer nadiren değiştiğinde, doğrudan bir işaretleyicinin yüklenmesi performansına yakın olması beklenirdi. Atomik yük için Visual Studio C++ 2012'deki normal yükten çok daha kötü performans gördüm, bu yüzden araştırmaya karar verdim. Atom yükünün, mümkün olan en hızlı uygulama olmadığını santığım bir compare-and-swap döngü olarak uygulandığı ortaya çıkıyor.std :: atomic <int*> olmalıdır ?: bir karşılaştırma ve takas döngüsü yapmak mı?

Soru: std::atomic<int*>::load'un bir karşılaştırma ve takas döngüsü yapması için bir neden var mı?

Arkaplan:

#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; 
} 

ben amacıyla bir __declspec(noinline) işlevi kullanıyorum: Ben ++ 2012 MSVC bu test programı dayalı bir işaretçi atomik yük bir karşılaştırma ve takas döngü yapıyor inanıyoruz atomik yük ile ilgili montaj talimatlarını ayırmak için. Yeni bir MSVC++ 2012 projesi yaptım, bir x64 platformu ekledim, sürüm konfigürasyonunu seçtim, programı hata ayıklayıcısında çalıştırdım ve söküme baktım. std::atomic<char> ve std::atomic<int> parametrelerinin aynı aramayı loadRelaxed<int> aynı aramayı verdiğini ortaya çıkarır - bu, optimize edicinin yaptığı bir şey olmalıdır.

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 atomik olduğu talimat compare-and-swap ve kod burada bakın: Burada denilen olsun iki loadRelaxed başka örneklerinin sökme İşte bir char, biratomunun yüklenmesi içinveya bir int*, bir karşılaştırma ve takas döngüsüdür. Ayrıca bu kodu 32 bit x86 için oluşturdum ve bu uygulama hala lock cmpxchg'a dayanıyor.

Soru: std::atomic<int*>::load'un bir karşılaştırma ve takas döngüsü yapması için bir neden var mı?

+0

Bu tür bir kodun neden oluşturulduğunu da görmek isterim – James

+0

@James MS'in henüz bunu daha iyi uygulama zamanı olmadığından şüphe ediyorum. Kendi uygulama çabalarımdan, bunu daha hızlı yapmak için çok az miktarda kod aldı, ancak bu kodun ne yapması gerektiği ve bunun belirli bir donanım platformuyla nasıl etkileştiği ayrıntılı olarak anlamak için büyük çaba harcadı. Diğer insanlar tarafından yazılan materyale bağlı kaldım, ama * gerçekten doğru bir şekilde yaptığınızdan emin olmak için, donanım satıcılarına başvurmanın ve standart üzerinde çok fazla zaman ayırmanın gerekli olacağını düşünüyorum. Karşılaştırma ve takas yapmak çok daha kolay ve kesinlikle doğru. –

+0

Bkz. Http://connect.microsoft.com/VisualStudio/geribildirim/ayrıntılar/770885/STD-atom-yük uygulama-is-saçma-yavaş –

cevap

1

Rahat atomik yüklerin karşılaştırma ve takas gerektirdiğine inanmıyorum. Sonunda bu std :: atomik uygulama benim amacım için kullanılamıyordu, ama yine de arayüze sahip olmak istedim, bu yüzden MSVC'nin bariyer içlerini kullanarak kendi std :: atomicimi yaptım. Bu, kullanım durumum için varsayılan std::atomic'dan daha iyi bir performansa sahiptir. here kodunu görebilirsiniz. Yük ve mağaza için tüm siparişler için C++ 11 spesifikasyonuna uygulanması gerekiyordu. Btw GCC 4.6 bu konuda daha iyi değildir. GCC 4.7 hakkında bilmiyorum.