2015-08-07 5 views
8

मुझे कुछ साधारण 32 बिट कोड मिला है जो 32 बिट पूर्णांक की सरणी के उत्पाद की गणना करता है। भीतरी पाश इस तरह दिखता है:राउंड-ट्रिप नहीं करने से स्मृति मेमोरी राउंड-ट्रिप क्यों तेज है?

@@loop: 
mov esi,[ebx] 
mov [esp],esi 
imul eax,[esp] 
add ebx, 4 
dec edx 
jnz @@loop 

क्या मैं समझने की कोशिश कर रहा हूँ क्यों उपरोक्त कोड 6% कोड है, जो अनावश्यक स्मृति राउंड ट्रिप प्रदर्शन नहीं करता के ये दो संस्करण की तुलना में तेजी है:

@@loop: 
mov esi,[ebx] 
imul eax,esi 
add ebx, 4 
dec edx 
jnz @@loop 

और

@@loop: 
imul eax,[ebx] 
add ebx, 4 
dec edx 
jnz @@loop 

कोड के दो बाद के टुकड़े लगभग एक ही समय में, निष्पादित और के रूप में उल्लेख दोनों 6% पहले टुकड़ा (165ms बनाम 155ms, 200 मिलियन तत्व) की तुलना में धीमी है।

मैंने कूद लक्ष्य को 16 बाइट सीमा पर मैन्युअल रूप से संरेखित करने का प्रयास किया है, लेकिन इससे कोई फर्क नहीं पड़ता।

मैं इसे इंटेल i7 4770k, विंडोज 10 x64 पर चला रहा हूं।

नोट: मुझे पता है कि सभी प्रकार के अनुकूलन करके कोड को बेहतर किया जा सकता है, हालांकि मुझे केवल कोड के उपरोक्त टुकड़ों के बीच प्रदर्शन अंतर में दिलचस्पी है।

+0

मैं आपको संदर्भ नहीं दे सकता (क्योंकि वे संभवतः अस्तित्व में नहीं हैं, क्योंकि वे व्यापार रहस्य प्रकट करेंगे), लेकिन संभवतः आप असाधारण प्रयासों का एक आर्टिफैक्ट देख रहे हैं जो इंटेल एल 1 कैश प्रदर्शन में डालता है। – Gene

+2

क्या यह तब भी होता है जब आप दूसरे संस्करण में एक डमी लोड 'mov ecx, [ebx] 'डालते हैं? – harold

+0

कैश किए गए मामले में प्रदर्शन कैसा है? पहले लूप को प्रति 2 चक्रों में लूप बफर से बाहर होना चाहिए (क्योंकि यह आपके हैसवेल सीपीयू पर 5 फ़्यूज्ड-डोमेन यूपीएस है)। अन्य दो प्रति चक्र एक चक्र में जारी कर सकते हैं। हालांकि, लूप-ले जाने वाली 'imul' निर्भरता श्रृंखला उन्हें प्रति पुनरावृत्ति के लिए सभी 3 चक्रों तक सीमित करनी चाहिए।पहले में महत्वपूर्ण पथ निर्भरता श्रृंखला में स्टोर और पुनः लोड नहीं होता है, और हैसवेल हर चक्र में 2x लोड + 1x स्टोर निष्पादित कर सकता है। (प्री-हैसवेल में एक समर्पित स्टोर एजीई नहीं था)। मैं नहीं देख सकता कि यह तेज़ क्यों है, लेकिन यह समझ में आता है कि यह धीमा नहीं है। –

उत्तर

1

मुझे लगता है लेकिन यकीन है कि आप एक डेटा निर्भरता पर एक स्टाल रोक रहे हैं नहीं किया जा सकता:

कोड इस तरह दिखता है:

@@loop: 
    mov esi,[ebx] # (1)Load the memory location to esi reg 
    (mov [esp],esi) # (1)optionally store the location on the stack  
    imul eax,[esp] # (3) Perform the multiplication 
    add ebx, 4  # (1) Add 4 
    dec edx   # (1)decrement counter 
    jnz @@loop  # (0**) loop 

कोष्ठक में उन संख्याओं को निर्देश की सुप्तावस्था हैं ... अगर शाखा भविष्यवाणीकर्ता सही ढंग से अनुमान लगाता है तो वह कूद 0 है (जो तब से ज्यादातर लूप इसे अधिकतर समय तक लूप करेगा)।

तो: जबकि गुणा अभी भी चल रहा है (3 निर्देश) हम 2 के बाद लूप के शीर्ष पर वापस आते हैं और स्मृति में लोड करने का प्रयास करते हैं और उन्हें रोकना पड़ता है। या हम एक स्टोर कर सकते हैं ... जो हम अपने गुणा के रूप में एक ही समय में कर सकते हैं और फिर बिल्कुल नहीं रोक सकते हैं।

डमी स्टोर के बारे में आप क्या पूछते हैं? वह क्यों काम करता है? ध्यान दें कि आप उस महत्वपूर्ण मूल्य को संग्रहीत कर रहे हैं जिसका उपयोग हम स्मृति में गुणा करने के लिए कर रहे हैं। इस प्रकार प्रोसेसर इस मान का उपयोग कर सकता है जिसे स्मृति में संग्रहीत किया जा रहा है और रजिस्टर को रोकता है।

तो प्रोसेसर वैसे भी ऐसा क्यों नहीं कर सकता है? प्रोसेसर आपसे पूछने के मुकाबले ज्यादा मेमोरी एक्सेस नहीं दे सकता है या यह बहु-प्रोसेसर प्रोग्राम में हस्तक्षेप कर सकता है (कल्पना करें कि कैश लाइन जिसे आप लिख रहे हैं साझा किया गया है और आपको इसे लिखकर प्रत्येक लूप को अन्य सीपीयू पर अमान्य करना होगा ... आउच!)।

यह सब शुद्ध अटकलें हैं, लेकिन ऐसा लगता है कि यह सब सबूत (आपका कोड और इंटेल आर्किटेक्चर का मेरा ज्ञान ... और x86 असेंबली) से मेल खाता है। उम्मीद है कि कोई मुझे बता सकता है कि मेरे पास कुछ गलत है या नहीं।

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