2011-07-19 16 views
11

मैं सी ++ में एक निश्चित-बिंदु वर्ग को लागू करने की कोशिश कर रहा हूं, लेकिन मुझे प्रदर्शन के साथ समस्याएं आ रही हैं। मैंने समस्या को फ्लोट प्रकार के एक साधारण आवरण में कम कर दिया है और यह अभी भी धीमा है। मेरा सवाल है - संकलक इसे पूरी तरह अनुकूलित क्यों कर सकता है?सी ++ में एक साधारण संख्यात्मक प्रकार रैपर वर्ग को कैसे अनुकूलित करें?

'फ्लोट' संस्करण 'फ्लोट' से 50% तेज है। क्यूं कर?!

(मैं विजुअल सी ++ 2008 का उपयोग करता हूं, सभी संभावित कंपाइलर विकल्पों का परीक्षण किया जाता है, पाठ्यक्रम की रिलीज कॉन्फ़िगरेशन)।

देखें नीचे दिए गए कोड:

#include <cstdio> 
#include <cstdlib> 
#include "Clock.h"  // just for measuring time 

#define real Float  // Option 1 
//#define real float  // Option 2 

struct Float 
{ 
private: 
    float value; 

public: 
    Float(float value) : value(value) {} 
    operator float() { return value; } 

    Float& operator=(const Float& rhs) 
    { 
     value = rhs.value; 
     return *this; 
    } 

    Float operator+ (const Float& rhs) const 
    { 
     return Float(value + rhs.value); 
    } 

    Float operator- (const Float& rhs) const 
    { 
     return Float(value - rhs.value); 
    } 

    Float operator* (const Float& rhs) const 
    { 
     return Float(value * rhs.value); 
    } 

    bool operator< (const Float& rhs) const 
    { 
     return value < rhs.value; 
    } 
}; 

struct Point 
{ 
    Point() : x(0), y(0) {} 
    Point(real x, real y) : x(x), y(y) {} 

    real x; 
    real y; 
}; 

int main() 
{ 
    // Generate data 
    const int N = 30000; 
    Point points[N]; 
    for (int i = 0; i < N; ++i) 
    { 
     points[i].x = (real)(640.0f * rand()/RAND_MAX); 
     points[i].y = (real)(640.0f * rand()/RAND_MAX); 
    } 

    real limit(20 * 20); 

    // Check how many pairs of points are closer than 20 
    Clock clk; 

    int count = 0; 
    for (int i = 0; i < N; ++i) 
    { 
     for (int j = i + 1; j < N; ++j) 
     { 
      real dx = points[i].x - points[j].x; 
      real dy = points[i].y - points[j].y; 
      real d2 = dx * dx + dy * dy; 
      if (d2 < limit) 
      { 
       count++; 
      } 
     } 
    } 

    double time = clk.time(); 

    printf("%d\n", count); 
    printf("TIME: %lf\n", time); 

    return 0; 
} 
+2

क्या आपने अधिकतम अनुकूलन झंडे चालू किए हैं। मैंने जादूगरों को तब देखा है जब आप उन्हें चालू करते हैं। – iammilind

+0

असेंबली जेनरेट करें और जांचें कि मतभेद कहाँ हैं ... –

+0

आप सभी तरीकों को स्पष्ट रूप से 'इनलाइन' –

उत्तर

4

IMO, यह अनुकूलन झंडे से कोई लेना देना नहीं है। मैंने आपके प्रोग्राम को g ++ linux-64 मशीन में चेक किया है। किसी भी अनुकूलन के बिना, यह वही परिणाम देता है जैसा आपने बताया था कि 50% कम है।

अधिकतम अनुकूलन चालू रखने के साथ (यानी -O4)। दोनों संस्करण समान हैं। अनुकूलन चालू करें और जांचें।

+1

मैंने जीसीसी स्थापित किया है और वास्तव में यह अच्छी तरह से काम करता है! जीसीसी के साथ समय 1.13 एस है, जबकि वीसी ++ के साथ यह 1.70 एस (फ्लोट) या 2.58 एस (फ्लोट) है। मैंने यह भी पाया कि सीधे 'डीएक्स * डीएक्स + डीई * डीई' को सीधे स्थिति में ले जाने से वीसी ++ पर 21% तक प्रदर्शन में सुधार होता है! यह कैसे संभव है कि वीसी ++ इतना खराब अनुकूलित करता है ?! मेरे पास सभी संभावित अनुकूलन विकल्प चालू हैं और कई अलग-अलग संयोजनों का परीक्षण किया गया है। –

+0

वाह ... जब मैंने 'Win32' से 'x64' प्लेटफॉर्म पर स्विच किया तो निष्पादन समय 2.58 से 0.77 एस तक गिर गया! और यह 'फ्लोट' और 'फ्लोट' के लिए समान है। –

2

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

4

संदर्भ से गुजरने का प्रयास करें। आपकी कक्षा इतनी छोटी है कि संदर्भ द्वारा इसे पारित करने के ऊपरी हिस्से (हां, अगर कंपाइलर इसे अनुकूलित नहीं करता है तो ओवरहेड होता है), क्लास की प्रतिलिपि बनाने से कहीं अधिक हो सकता है। तो यह है ...

Float operator+ (const Float& rhs) const 
{ 
    return Float(value + rhs.value); 
} 

कुछ इस तरह हो जाता है ...

Float operator+ (Float rhs) const 
{ 
    rhs.value+=value; 
    return rhs; 
} 

जो एक अस्थायी वस्तु से बचा जाता है और एक संकेतक भिन्नता के कुछ अविवेक से बचने कर सकते हैं।

+2

मैंने कोशिश की - काम नहीं करता है। यह 5 9% तक भी समय बढ़ाता है। –