8

मेरे पास निम्न कोड है और उपयोग किए जाने वाले exp() फ़ंक्शन के आंतरिक संस्करण की अपेक्षा कर रहा हूं। दुर्भाग्य से, यह एक 64 निर्माण में नहीं है, यह एक ऐसी ही Win32 (यानी, 32-बिट का निर्माण) की तुलना में धीमी कर रही:मैं x64 कोड में exp() फ़ंक्शन के लिए आंतरिक कैसे प्राप्त कर सकता हूं?

#include "stdafx.h" 
#include <cmath> 
#include <intrin.h> 
#include <iostream> 

int main() 
{ 
    const int NUM_ITERATIONS=10000000; 
    double expNum=0.00001; 
    double result=0.0; 

    for (double i=0;i<NUM_ITERATIONS;++i) 
    { 
    result+=exp(expNum); // <-- The code of interest is here 
    expNum+=0.00001; 
    } 

    // To prevent the above from getting optimized out... 
    std::cout << result << '\n'; 
} 

मैं अपने निर्माण के लिए निम्नलिखित स्विच का उपयोग कर रहा:

/Zi /nologo /W3 /WX- 
/Ox /Ob2 /Oi /Ot /Oy /GL /D "WIN32" /D "NDEBUG" 
/D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /Gm- 
/EHsc /GS /Gy /arch:SSE2 /fp:fast /Zc:wchar_t /Zc:forScope 
/Yu"StdAfx.h" /Fp"x64\Release\exp.pch" /FAcs /Fa"x64\Release\" 
/Fo"x64\Release\" /Fd"x64\Release\vc100.pdb" /Gd /errorReport:queue 

जैसा कि आप देख सकते हैं, मेरे पास /Oi, /O2 और /fp:fastMSDN article on intrinsics प्रति आवश्यक है। फिर भी, मेरे प्रयासों के बावजूद मानक पुस्तकालय को कॉल किया गया है, जिससे exp() x64 बिल्डों पर धीमी गति से प्रदर्शन कर रहा है।

for (double i=0;i<NUM_ITERATIONS;++i) 
000000013F911030 movsd  xmm10,mmword ptr [[email protected] (13F912248h)] 
000000013F911039 movapd  xmm8,xmm6 
000000013F91103E movapd  xmm7,xmm9 
000000013F911043 movaps  xmmword ptr [rsp+20h],xmm11 
000000013F911049 movsd  xmm11,mmword ptr [[email protected] (13F912240h)] 
    { 
    result+=exp(expNum); 
000000013F911052 movapd  xmm0,xmm7 
000000013F911056 call  exp (13F911A98h) // ***** exp lib call is here ***** 
000000013F91105B addsd  xmm8,xmm10 
    expNum+=0.00001; 
000000013F911060 addsd  xmm7,xmm9 
000000013F911065 comisd  xmm8,xmm11 
000000013F91106A addsd  xmm6,xmm0 
000000013F91106E jb   main+52h (13F911052h) 
    } 

आप ऊपर विधानसभा में देख सकते हैं, वहाँ exp() समारोह के लिए बाहर एक फोन है:

यहाँ उत्पन्न विधानसभा है। अब, चलो एक 32-बिट का निर्माण के साथ कि for पाश के लिए तैयार किए गए कोड को देखो: वहाँ

for (double i=0;i<NUM_ITERATIONS;++i) 
00101031 xorps  xmm1,xmm1 
00101034 rdtsc 
00101036 push  ebx 
00101037 push  esi 
00101038 movsd  mmword ptr [esp+1Ch],xmm0 
0010103E movsd  xmm0,mmword ptr [[email protected] (102188h)] 
00101046 push  edi 
00101047 mov   ebx,eax 
00101049 mov   dword ptr [esp+3Ch],edx 
0010104D movsd  mmword ptr [esp+28h],xmm0 
00101053 movsd  mmword ptr [esp+30h],xmm1 
00101059 lea   esp,[esp] 
    { 
    result+=exp(expNum); 
00101060 call  __libm_sse2_exp (101EC0h) // <--- Quite different from 64-bit 
00101065 addsd  xmm0,mmword ptr [esp+20h] 
0010106B movsd  xmm1,mmword ptr [esp+30h] 
00101071 addsd  xmm1,mmword ptr [[email protected] (102180h)] 
00101079 movsd  xmm2,mmword ptr [[email protected] (102178h)] 
00101081 comisd  xmm2,xmm1 
00101085 movsd  mmword ptr [esp+20h],xmm0 
    expNum+=0.00001; 
0010108B movsd  xmm0,mmword ptr [esp+28h] 
00101091 addsd  xmm0,mmword ptr [[email protected] (102188h)] 
00101099 movsd  mmword ptr [esp+28h],xmm0 
0010109F movsd  mmword ptr [esp+30h],xmm1 
001010A5 ja   wmain+40h (101060h) 
    } 

बहुत अधिक कोड है, फिर भी यह तेजी से है।

32-बिट:

For loop body average exec time: 34.849229 cycles/10.560373 ns

64-बिट: एक समय परीक्षण मैं एक 3.3 गीगा Nehalem-ईपी मेजबान पर किया निम्नलिखित परिणाम का उत्पादन किया

For loop body average exec time: 45.845323 cycles/13.892522 ns

बहुत अजीब व्यवहार, वास्तव में। ऐसा क्यों हो रहा है?

अद्यतन:

मैं एक Microsoft Connect bug report बनाया है। फ्लोटिंग पॉइंट इंट्रिनिक्स के उपयोग पर विशेष रूप से x64 कोड में माइक्रोसॉफ्ट से आधिकारिक उत्तर प्राप्त करने के लिए इसे अपनाने के लिए स्वतंत्र महसूस करें।

+0

[यह आलेख] (http://blogs.msdn.com/b/ricom/archive/2009/06/10/visual-studio-why-is-there-no-64-bit-version.aspx) (यह बताते हुए कि वीएस में 64 बिट संस्करण क्यों नहीं है) बताता है कि 64 बिट बिल्ड 32 बिट की तुलना में धीमा हो सकता है। मुझे नहीं पता कि यह स्पष्टीकरण वह है जो आपके विशिष्ट मामले पर लागू होता है। – Attila

+1

यह आलेख विजुअल स्टूडियो के 64-बिट संस्करण के बारे में है, इसका सवाल उठाने के लिए कुछ भी नहीं है। ऐसे कई कारक हैं जो 64-बिट अनुप्रयोग को 32-बिट एक से धीमा कर सकते हैं। जब तक, मुझे कुछ याद नहीं आ रहा है, हालांकि इन कारकों में से कोई भी फ्लोटिंग पॉइंट गणना के बारे में मेरे प्रश्न के साथ कुछ भी नहीं करना है। –

+0

@ माइकलगोल्डशेटिन - मेरी गलती – Attila

उत्तर

5

64 पर है, चल बिन्दु अंकगणितीय SSE का उपयोग किया जाता है। इसमें exp() के लिए अंतर्निहित ऑपरेशन नहीं है और इसलिए मानक लाइब्रेरी में एक कॉल अपरिहार्य है। मुझे कल्पना है कि आप जिस एमएसडीएन लेख का जिक्र कर रहे हैं वह 32 बिट कोड के साथ लिखा गया था जो 8087 एफपी का उपयोग करता है।

+0

कृपया मेरा संपादित प्रश्न देखें जिसमें 32-बिट बिल्ड द्वारा उत्पन्न कोड और 32-बिट बनाम 64-बिट की समय तुलना शामिल है । न तो निर्माण एक "सत्य" आंतरिक का उपयोग कर रहा है, लेकिन फ़ंक्शन में अंतर हैं जिन्हें 32-बिट बिल्ड काफी तेज़ है। –

+0

शायद, लेकिन तथ्य यह है कि किसी भी एसएसई ऑपकोड्स –

+0

में कोई अंतर अंतर्निहित नहीं है, यह सच है, लेकिन मैं उम्मीद कर रहा था कि एमएसडीएन दस्तावेज के अनुसार मेरे (असेंबली) कोड में उल्लिखित एक्सप() के आंतरिक कार्यान्वयन के लिए । –

0

EDIT मैं इस चर्चा में AMD's x64 instruction set manuals और Intel's reference पर लिंक जोड़ना चाहता हूं।

प्रारंभिक निरीक्षण में, घातीय गणना करने के लिए F2XM1 का उपयोग करने का एक तरीका होना चाहिए। हालांकि, यह, x87 अनुदेश सेट में है hidden in x64 mode.

वहाँ MMX/x87 स्पष्ट रूप से उपयोग करने में आशा है, VirtualDub discussion boards. पर एक पोस्टिंग में वर्णित और के रूप में, इस how to actually write asm in VC++.

+0

क्षमा करें, '/ MD' जोड़ना कुछ भी नहीं बदला ... –

0

मुझे लगता है कि माइक्रोसॉफ्ट 32-बिट एसएसई 2 एक्सपी() का एक आंतरिक संस्करण प्रदान करने का एकमात्र कारण मानक कॉलिंग सम्मेलन है। 32-बिट कॉलिंग सम्मेलनों के लिए मुख्य स्टैक पर ऑपरेंड को धक्का दिया जाना चाहिए, और परिणाम एफपीयू स्टैक के शीर्ष रजिस्टर में वापस किया जाना चाहिए।यदि आपके पास एसएसई 2 कोड जनरेशन सक्षम है, तो वापसी मूल्य को एफपीयू स्टैक से मेमोरी में पॉप किया जा सकता है, फिर उस स्थान से एसएसई 2 रजिस्टर में लोड किया जा सकता है जिसके परिणामस्वरूप आप जो भी गणित करना चाहते हैं। जाहिर है, एसएसई 2 रजिस्टर में ऑपरेंड पास करना और एसएसई 2 रजिस्टर में परिणाम वापस करना तेज है। यह __libm_sse2_exp() करता है। 64-बिट कोड में, मानक कॉलिंग सम्मेलन ऑपरेंड पास करता है और परिणामस्वरूप एसएसई 2 रजिस्टरों में परिणाम देता है, इसलिए आंतरिक संस्करण होने में कोई फायदा नहीं होता है।

32-बिट एसएसई 2 और एक्सपी (64) के 64-बिट कार्यान्वयन के बीच प्रदर्शन अंतर का कारण यह है कि माइक्रोसॉफ्ट दो कार्यान्वयन में विभिन्न एल्गोरिदम का उपयोग करता है। मुझे नहीं पता कि वे ऐसा क्यों करते हैं, और वे कुछ ऑपरेटरों के लिए अलग-अलग परिणाम (1ulp द्वारा अलग) उत्पन्न करते हैं।

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

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