सारांश: मुझे उम्मीद थी कि std::atomic<int*>::load
std::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
तुलना-और-स्वैप लूप करने की आवश्यकता है?
मैं यह भी देखना चाहूंगा कि इस तरह का कोड क्यों उत्पन्न होता है – James
@ जेम्स मुझे संदेह है कि एमएस के पास अभी तक इसे बेहतर करने का समय नहीं है। अपने कार्यान्वयन प्रयास से, इसे तेजी से बनाने के लिए केवल थोड़ी सी मात्रा में कोड लिया गया, लेकिन विस्तार से समझने के लिए बड़ी संख्या में प्रयास किया गया कि यह कोड क्या करना चाहिए और यह किसी दिए गए हार्डवेयर प्लेटफ़ॉर्म के साथ कैसे इंटरैक्ट करता है। मैंने अन्य लोगों द्वारा लिखी गई सामग्री पर निर्भर किया है, लेकिन वास्तव में * यह सुनिश्चित करने के लिए कि आपने यह सही किया है, मुझे लगता है कि हार्डवेयर विक्रेताओं से संपर्क करना और मानक पर अधिक समय लगाना आवश्यक होगा। तुलना-और-स्वैप करना बहुत आसान है और निश्चित रूप से सही है। –
http://connect.microsoft देखें।com/VisualStudio/प्रतिक्रिया/विवरण/770,885/एसटीडी-परमाणु-लोड कार्यान्वयन-है-मूर्खता से धीमी –