2012-11-03 12 views
5

सारांश: मुझे उम्मीद थी कि std::atomic<int*>::loadstd::memory_order_relaxed के साथ केवल एक सूचक सीधे लोड करने के प्रदर्शन के करीब होगा, कम से कम जब भारित मूल्य शायद ही कभी बदलता है। मैंने विजुअल स्टूडियो सी ++ 2012 पर सामान्य लोड की तुलना में परमाणु भार के लिए बहुत खराब प्रदर्शन देखा, इसलिए मैंने जांच करने का फैसला किया। ऐसा लगता है कि परमाणु भार एक compare-and-swap पाश है, जो मुझे लगता है सबसे तेजी से संभव कार्यान्वयन नहीं है के रूप में कार्यान्वित किया जाता है।std चाहिए :: परमाणु <int*> :: लोड एक तुलना और स्वैप पाश कर रहा?

प्रश्न: क्या कोई कारण है कि 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) समारोह का उपयोग कर रहा परमाणु भार से संबंधित विधानसभा निर्देशों को अलग करने के लिए। मैंने एक नया एमएसवीसी ++ 2012 प्रोजेक्ट बनाया, एक एक्स 64 प्लेटफ़ॉर्म जोड़ा, रिलीज कॉन्फ़िगरेशन का चयन किया, प्रोग्राम को डीबगर में चलाया और डिस्सेप्लोर को देखा। पता चला है कि दोनों std::atomic<char> और std::atomic<int> मापदंडों अंत loadRelaxed<int> को एक ही कॉल दे रही है - यह कुछ होना चाहिए अनुकूलक था।

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 परमाणु है compare-and-swap और हम यहाँ देख कि कोड: यहाँ दो loadRelaxed instantiations के disassembly कि कहा जाता हो जाता है char परमाणु रूप से लोड करने के लिए, int या एक int* एक तुलना और स्वैप पाश है। मैंने 32-बिट x86 के लिए यह कोड भी बनाया और यह कार्यान्वयन अभी भी lock cmpxchg पर आधारित है।

प्रश्न: क्या कोई कारण है कि std::atomic<int*>::load तुलना-और-स्वैप लूप करने की आवश्यकता है?

+0

मैं यह भी देखना चाहूंगा कि इस तरह का कोड क्यों उत्पन्न होता है – James

+0

@ जेम्स मुझे संदेह है कि एमएस के पास अभी तक इसे बेहतर करने का समय नहीं है। अपने कार्यान्वयन प्रयास से, इसे तेजी से बनाने के लिए केवल थोड़ी सी मात्रा में कोड लिया गया, लेकिन विस्तार से समझने के लिए बड़ी संख्या में प्रयास किया गया कि यह कोड क्या करना चाहिए और यह किसी दिए गए हार्डवेयर प्लेटफ़ॉर्म के साथ कैसे इंटरैक्ट करता है। मैंने अन्य लोगों द्वारा लिखी गई सामग्री पर निर्भर किया है, लेकिन वास्तव में * यह सुनिश्चित करने के लिए कि आपने यह सही किया है, मुझे लगता है कि हार्डवेयर विक्रेताओं से संपर्क करना और मानक पर अधिक समय लगाना आवश्यक होगा। तुलना-और-स्वैप करना बहुत आसान है और निश्चित रूप से सही है। –

+0

http://connect.microsoft देखें।com/VisualStudio/प्रतिक्रिया/विवरण/770,885/एसटीडी-परमाणु-लोड कार्यान्वयन-है-मूर्खता से धीमी –

उत्तर

1

मैं नहीं मानता कि आराम परमाणु भार की तुलना और स्वैप की आवश्यकता है। अंत में इस std :: परमाणु कार्यान्वयन मेरा उद्देश्य के लिए प्रयोग करने योग्य नहीं था, लेकिन मैं अभी भी इंटरफेस करना चाहते थे, इसलिए मैं MSVC के बाधा intrinsics का उपयोग कर अपने ही std :: परमाणु बना दिया। मेरे उपयोग के मामले के लिए डिफ़ॉल्ट std::atomic से बेहतर प्रदर्शन है। आप कोड here देख सकते हैं। लोड और स्टोर के लिए सभी ऑर्डरिंग के लिए इसे सी ++ 11 स्पेक में लागू किया जाना चाहिए। इस संबंध में बीटीडब्ल्यू जीसीसी 4.6 बेहतर नहीं है। मुझे जीसीसी 4.7 के बारे में पता नहीं है।

संबंधित मुद्दे