2012-09-09 17 views
7

मेरे पास प्रोग्रामिंग के क्षेत्र में कुछ लोगों के साथ एक दोस्ताना प्रतिस्पर्धा है और हाल ही में हम कुशल कोड लिखने में इतनी दिलचस्पी ले चुके हैं। हमारी चुनौती किसी भी कीमत (पठनीयता, पुन: प्रयोज्यता, आदि) पर कोड (सीपीयू समय और जटिलता के भाव में) को अनुकूलित करने का प्रयास करना था।कोड के दो टुकड़ों के प्रदर्शन की तुलना कैसे करें

समस्या यह है कि अब हमें अपने कोड की तुलना करने की आवश्यकता है और देखें कि कौन सा दृष्टिकोण दूसरों की तुलना में बेहतर है लेकिन हम इस उद्देश्य के लिए किसी भी उपकरण को नहीं जानते हैं।

मेरा प्रश्न है, वहाँ कुछ (किसी भी!) उपकरण है कि इनपुट के रूप में कोड का एक टुकड़ा लेता है और फ्लॉप या CPU निर्देश इसे चलाने के लिए आवश्यक की गणना करती हैं? क्या कोई उपकरण कोड के अनुकूलता को माप सकता है?

पीएस लक्ष्य भाषा सी ++ है लेकिन जानना अच्छा होगा कि ऐसे उपकरण जावा के लिए भी मौजूद हैं या नहीं।

+2

+1। क्या यह समय '/ प्रोग' चलाने के लिए पर्याप्त है? –

+1

@KerrekSB मेरा मानना ​​है कि ओपी एक प्रोफाइलर चाहता है। –

+3

मुझे नहीं लगता कि गिनती फ्लॉप या सीपीयू निर्देश दक्षता का एक अच्छा उपाय है। [कृत्रिम काम-रहित कोड को एक साथ थप्पड़ मारना आसान है जो अधिकतम हो सकता है।] (Http://stackoverflow.com/questions/8389648/how-to-achieve-4-flops-per-cycle) – Mysticial

उत्तर

8

यहाँ एक छोटे से सी ++ 11 स्टॉपवॉच मैं शुरू करने जब मैं समय कुछ करने की जरूरत है की तरह है बहुत सटीक समय की जानकारी।

+0

दृश्य स्टूडियो पर ' high_resolution_clock' भयानक है, इस तरह के मामले में बढ़ावा पुस्तकालय संस्करण का उपयोग करें। – ronag

+0

@ronag: सलाह के लिए धन्यवाद! –

+0

+1: यह निर्धारित करने की बात आती है कि कोड का कौन सा टुकड़ा तेज़ है, समय आमतौर पर प्रोफाइलिंग से बेहतर होता है। प्रोफाइलिंग आमतौर पर कैशिंग प्रभाव और इसी तरह की याद आती है जो प्रदर्शन पर एक बड़ा प्रभाव डाल सकती है। – Leo

0

कोड के ब्लॉक से सीपीयू समय की विस्तृत संख्या की गणना करना काफी मुश्किल है। ऐसा करने का सामान्य तरीका परीक्षण मामलों के रूप में खराब/औसत/सर्वोत्तम इनपुट डेटा को डिज़ाइन करना है। और इन परीक्षण मामलों के साथ अपने असली कोड के आधार पर एक समय प्रोफाइलिंग करें। विस्तारित इनपुट परीक्षण डेटा और शर्तों के बिना जब कोई उपकरण आपको फ्लॉप नहीं बता सकता है।

#include <chrono> 
#include <ctime> 

template <typename T> class basic_stopwatch 
{ 
    typedef T clock; 
    typename clock::time_point p; 
    typename clock::duration d; 

public: 
    void tick() { p = clock::now();   } 
    void tock() { d += clock::now() - p;  } 
    void reset() { d = clock::duration::zero(); } 

    template <typename S> unsigned long long int report() const 
    { 
     return std::chrono::duration_cast<S>(d).count(); 
    } 

    unsigned long long int report_ms() const 
    { 
     return report<std::chrono::milliseconds>(); 
    } 

    basic_stopwatch() : p(), d() { } 
}; 

struct c_clock 
{ 
    typedef std::clock_t time_point; 
    typedef std::clock_t duration; 
    static time_point now() { return std::clock(); } 
}; 

template <> unsigned long long int basic_stopwatch<c_clock>::report_ms() const 
{ 
    return 1000. * double(d)/double(CLOCKS_PER_SEC); 
} 

typedef basic_stopwatch<std::chrono::high_resolution_clock> stopwatch; 
typedef basic_stopwatch<c_clock> cstopwatch; 

उपयोग::

stopwatch sw; 
sw.tick(); 

run_long_code(); 

sw.tock(); 
std::cout << "This took " << sw.report_ms() << "ms.\n"; 

किसी भी सभ्य कार्यान्वयन पर, डिफ़ॉल्ट high_resolution_clock देना चाहिए

3

<ctime> से फ़ंक्शन है जो वर्तमान प्रक्रिया पर कितना CPU समय बिताया गया है (इसका मतलब है कि यह प्रोग्राम उस समय की गणना नहीं करता है जब सीपीयू अन्य कार्यों को निष्पादित कर रहा था)। इस फ़ंक्शन का उपयोग एल्गोरिदम के निष्पादन समय को सटीक रूप से मापने के लिए किया जा सकता है। रिटर्न वैल्यू सेकेंड में कनवर्ट करने के लिए स्थिर std::CLOCKS_PER_SEC (<ctime> से भी) का उपयोग करें।

0

profilers नामक सॉफ़्टवेयर के टुकड़े हैं जो वास्तव में आप जो चाहते हैं वह करते हैं।

विंडोज के लिए एक उदाहरण AMD code analyser और gprof पॉज़िक्स के लिए एक उदाहरण है।

+0

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

+0

@ फिलिप मैं अंधेरे से प्रोफाइलर्स पर भरोसा नहीं करता, मैं उस गणित के आदमी के सनकी प्रकार नहीं हूं। मैंने सोचा कि उनका उल्लेख करना एक अच्छा विचार होगा क्योंकि ऐसा लगता है कि ओपी को उनके बारे में बिल्कुल पता नहीं था। –

+0

@ फिलिप न तो मुझे लगता है कि यह जवाब क्यों कम किया जाना चाहिए - यह तकनीकी रूप से सही है ... –

0

बेस्ट अपने उद्देश्यों के लिए मापने सीपीयू निर्देश की संख्या बहुत बेकार है valgrind/callgrind

0

है।

प्रदर्शन बाधा के सापेक्ष है, समस्या के आधार पर बाधा नेटवर्क, डिस्क आईओएस, मेमोरी या सीपीयू हो सकती है।

सिर्फ एक दोस्ताना प्रतिस्पर्धा के लिए, मैं समय का सुझाव दूंगा। जो कि परीक्षण मामलों को प्रदान करता है जो निश्चित रूप से सार्थक उपायों के लिए पर्याप्त हैं।

यूनिक्स पर, आप अपेक्षाकृत सटीक उपायों के लिए gettimeofday का उपयोग कर सकते हैं।

1

इनलाइन-असेंबली से, आप ईडीएक्स में 32-बिट (कम से कम महत्वपूर्ण हिस्सा) काउंटर और 32-बिट (उच्चतम महत्वपूर्ण भाग) प्राप्त करने के लिए rdtsc निर्देश का उपयोग कर सकते हैं। यदि आपका कोड बहुत छोटा है, तो आप केवल ईएक्स रजिस्टर के साथ कुल-सीपीयू-चक्रों की जांच कर सकते हैं। यदि गिनती अधिकतम से अधिक है। 32-बिट मान का, अधिकतम अधिकतम 32-बिट मान चक्र में edx increments।

int cpu_clk1a=0; 
int cpu_clk1b=0; 
int cpu_clk2a=0; 
int cpu_clk2b=0; 
int max=0; 
std::cin>>max; //loop limit 

__asm 
{ 
    push eax 
    push edx 
    rdtsc //gets current cpu-clock-counter into eax&edx 
    mov [cpu_clk1a],eax 
    mov [cpu_clk1b],edx 
    pop edx 
    pop eax 

} 

long temp=0; 
for(int i=0;i<max;i++) 
{ 

    temp+=clock();//needed to defy optimization to actually measure something 
          //even the smartest compiler cannot know what 
          //the clock would be 
} 

__asm 
{ 
    push eax 
    push edx 
    rdtsc  //gets current cpu-clock-counter into aex&edx 
    mov [cpu_clk2a],eax 
    mov [cpu_clk2b],edx 
    pop edx 
    pop eax 

} 
std::cout<<(cpu_clk2a-cpu_clk1a)<<std::endl; 
    //if your loop takes more than ~2billions of cpu-clocks, use cpu_clk1b and 2b 
getchar(); 
getchar(); 

आउटपुट: 1000 पुनरावृत्तियों के लिए 74000 cpu-चक्र और मेरे मशीन पर 10000 पुनरावृत्तियों के लिए 800000 cpu-चक्र। क्योंकि घड़ी() समय लेने वाली है।

मेरी मशीन पर सीपीयू-चक्र संकल्प: ~ 1000 चक्र। हां, इसे अपेक्षाकृत सही मापने के लिए आपको हजारों अतिरिक्त/घटाव (तेज़ निर्देश) की आवश्यकता है।

मानते हुए सीपीयू काम करने की आवृत्ति निरंतर है, 1000 सीपीयू-चक्र लगभग 1 गीगाहर्ट्ज सीपीयू के लिए 1 माइक्रो-सेकंड के बराबर है। ऐसा करने से पहले आपको अपने सीपीयू को गर्म करना चाहिए। "ऑप्टिसी" शब्द के लिए

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