C ++ में कोड स्निपेट के निष्पादन समय की गणना कैसे करें


121

मुझे सेकंड में C ++ कोड स्निपेट के निष्पादन समय की गणना करनी होगी। यह या तो विंडोज या यूनिक्स मशीनों पर काम कर रहा होगा।

मैं ऐसा करने के लिए निम्नलिखित कोड का उपयोग करता हूं। (पहले आयात करें)

clock_t startTime = clock();
// some code here
// to compute its execution duration in runtime
cout << double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " seconds." << endl;

हालाँकि छोटे आदानों या छोटे कथनों जैसे a = a + 1 के लिए, मुझे "0 सेकंड" का परिणाम मिलता है। मुझे लगता है कि यह 0.0000001 सेकंड या ऐसा कुछ होना चाहिए।

मुझे याद है कि System.nanoTime()जावा इस मामले में बहुत अच्छा काम करता है। हालाँकि मुझे clock()C ++ के फंक्शन से उतनी सटीक कार्यक्षमता नहीं मिल सकती है।

क्या आपके पास एक समाधान है?


29
ध्यान रखें कि किसी भी समय-अंतर आधारित तुलना इस तथ्य के कारण अच्छी तरह से गलत हो सकती है कि ओएस शुरू से अंत तक आपके धागे को अच्छी तरह से नहीं चला सकता है। यह इसे बाधित कर सकता है और आपके साथ इंटरलेस्ड अन्य थ्रेड्स चला सकता है, जो आपके ऑपरेशन को पूरा करने के लिए वास्तविक समय पर महत्वपूर्ण प्रभाव डालेंगे। आप कई बार चला सकते हैं, और परिणाम औसत कर सकते हैं; आप चल रही अन्य प्रक्रियाओं की संख्या को कम कर सकते हैं। लेकिन इनमें से कोई भी थ्रेड सस्पेंशन प्रभाव को पूरी तरह से खत्म नहीं करेगा।
मोर्दचाई 17

14
मोर्दाची, आप इसे खत्म क्यों करना चाहेंगे? आप यह देखना चाहते हैं कि आपका कार्य वास्तविक दुनिया के माहौल में कैसा प्रदर्शन करता है, न कि एक जादुई दायरे में जहां सूत्र कभी भी बाधित नहीं होते हैं। जब तक आप इसे कई बार चलाते हैं और एक औसत बनाते हैं तब तक यह बहुत सटीक होगा।
थॉमस बोनीनी

हां, मैं इसे कुछ बार चलाता हूं और परिणाम निकालता हूं।
अहमतबी -

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

4
@ मोर्दकै मुझे पता है कि मैं एक पुरानी टिप्पणी का जवाब दे रहा हूं, लेकिन जो कोई भी इस पर ठोकर खाता है, जैसा कि मैंने किया था - एल्गोरिदम के समय के प्रदर्शन के लिए आप कुछ रनों का न्यूनतम लेना चाहते हैं, औसत नहीं। यह वह है जिसमें OS द्वारा कम से कम रुकावट थी और इसलिए ज्यादातर समय आपके कोड का होता है।
बरूच

जवाबों:


115

आप मेरे द्वारा लिखे गए इस फ़ंक्शन का उपयोग कर सकते हैं। आप कॉल करते हैं GetTimeMs64(), और यह सिस्टम क्लॉक का उपयोग करते हुए यूनिक्स युग के बाद से मिलीसेकंड की संख्या को वापस लौटाता है - ठीक उसी तरह time(NULL), जैसे कि मिलीसेकंड में छोड़कर।

यह विंडोज़ और लिनक्स दोनों पर काम करता है; यह धागा सुरक्षित है।

ध्यान दें कि खिड़कियों पर ग्रैन्युलैरिटी 15 एमएस है; लिनक्स पर यह निर्भरता को लागू कर रहा है, लेकिन यह आमतौर पर 15 एमएस भी है।

#ifdef _WIN32
#include <Windows.h>
#else
#include <sys/time.h>
#include <ctime>
#endif

/* Remove if already defined */
typedef long long int64; typedef unsigned long long uint64;

/* Returns the amount of milliseconds elapsed since the UNIX epoch. Works on both
 * windows and linux. */

uint64 GetTimeMs64()
{
#ifdef _WIN32
 /* Windows */
 FILETIME ft;
 LARGE_INTEGER li;

 /* Get the amount of 100 nano seconds intervals elapsed since January 1, 1601 (UTC) and copy it
  * to a LARGE_INTEGER structure. */
 GetSystemTimeAsFileTime(&ft);
 li.LowPart = ft.dwLowDateTime;
 li.HighPart = ft.dwHighDateTime;

 uint64 ret = li.QuadPart;
 ret -= 116444736000000000LL; /* Convert from file time to UNIX epoch time. */
 ret /= 10000; /* From 100 nano seconds (10^-7) to 1 millisecond (10^-3) intervals */

 return ret;
#else
 /* Linux */
 struct timeval tv;

 gettimeofday(&tv, NULL);

 uint64 ret = tv.tv_usec;
 /* Convert from micro seconds (10^-6) to milliseconds (10^-3) */
 ret /= 1000;

 /* Adds the seconds (10^0) after converting them to milliseconds (10^-3) */
 ret += (tv.tv_sec * 1000);

 return ret;
#endif
}

1
भविष्य के संदर्भ के लिए: मैं इसे एक हेडर फ़ाइल में फेंक देता हूं और इसका उपयोग करता हूं। खुशी है कि यह है।
डैनियल हैंडोजो

1
मेरा मानना ​​है कि gettimeofdayयदि सिस्टम घड़ी बदली जाती है, तो विधि एक अनपेक्षित परिणाम दे सकती है। यदि यह आपके लिए एक समस्या है, तो आप clock_gettimeइसके बजाय देखना चाह सकते हैं ।
अज़्मिसोव

क्या विंडोज के लिए इस विधि का कोई लाभ है GetTickCount?
माइक्रोविरस

का उपयोग करने के लिए संकलन नहीं करता हैgcc -std=c99
एसिस्मिलाटर

@MicroVirus: हां, GetTickCountसिस्टम शुरू होने के बाद का समय समाप्त हो गया है, जबकि मेरा कार्य UNIX युग के बाद का समय देता है जिसका अर्थ है कि आप इसे दिनांक और समय के लिए उपयोग कर सकते हैं। यदि आप केवल दो घटनाओं के बीच बीते हुए समय में रुचि रखते हैं, तो यह अभी भी एक बेहतर विकल्प है क्योंकि यह एक अंतर है; GetTickCount एक int32 है और हर 50 दिनों में ओवरफ्लो हो जाता है जिसका अर्थ है कि आप अजीब परिणाम प्राप्त कर सकते हैं यदि आपके द्वारा पंजीकृत दो घटनाएं ओवरफ्लो के बीच हैं।
थॉमस बोनी

43

मेरे पास एक और काम करने वाला उदाहरण है जो माइक्रोसेकंड (UNIX, POSIX, आदि) का उपयोग करता है।

    #include <sys/time.h>
    typedef unsigned long long timestamp_t;

    static timestamp_t
    get_timestamp ()
    {
      struct timeval now;
      gettimeofday (&now, NULL);
      return  now.tv_usec + (timestamp_t)now.tv_sec * 1000000;
    }

    ...
    timestamp_t t0 = get_timestamp();
    // Process
    timestamp_t t1 = get_timestamp();

    double secs = (t1 - t0) / 1000000.0L;

यहाँ फ़ाइल है जहाँ हमने इसे कोडित किया है:

https://github.com/arhuaco/junkcode/blob/master/emqbit-bench/bench.c


5
आपको #include <sys/time.h>अपने उदाहरण की शुरुआत में जोड़ना चाहिए ।
नीकस

40

यहां C ++ 11 में एक सरल समाधान है जो आपको संतोषजनक समाधान देता है।

#include <iostream>
#include <chrono>

class Timer
{
public:
    Timer() : beg_(clock_::now()) {}
    void reset() { beg_ = clock_::now(); }
    double elapsed() const { 
        return std::chrono::duration_cast<second_>
            (clock_::now() - beg_).count(); }

private:
    typedef std::chrono::high_resolution_clock clock_;
    typedef std::chrono::duration<double, std::ratio<1> > second_;
    std::chrono::time_point<clock_> beg_;
};

या * nix पर, c ++ 03 के लिए

#include <iostream>
#include <ctime>

class Timer
{
public:
    Timer() { clock_gettime(CLOCK_REALTIME, &beg_); }

    double elapsed() {
        clock_gettime(CLOCK_REALTIME, &end_);
        return end_.tv_sec - beg_.tv_sec +
            (end_.tv_nsec - beg_.tv_nsec) / 1000000000.;
    }

    void reset() { clock_gettime(CLOCK_REALTIME, &beg_); }

private:
    timespec beg_, end_;
};

यहाँ उदाहरण उपयोग है:

int main()
{
    Timer tmr;
    double t = tmr.elapsed();
    std::cout << t << std::endl;

    tmr.reset();
    t = tmr.elapsed();
    std::cout << t << std::endl;

    return 0;
}

से https://gist.github.com/gongzhitaao/7062087


मुझे यह त्रुटि आपके c ++ 11 समाधान के साथ मिल रही है:/usr/lib/x86_64-linux-gnu/libstdc++.so.6: version GLIBCXX_3.4.19 not found (required by ../cpu_2d/g500)
user9869932

@julianromera आप किस प्लेटफॉर्म का उपयोग कर रहे हैं? क्या आपने libstdc ++ लाइब्रेरी और g ++ स्थापित किया है?
gongzhitaao

लिनक्स ubuntu 12 का इसका स्लरम ग्रिड। मैंने अभी इसे ठीक किया है। मैंने लिंकर के अंत में -static-libstdc ++ जोड़ा। @Gongzhitaao
user9869932

18
#include <boost/progress.hpp>

using namespace boost;

int main (int argc, const char * argv[])
{
  progress_timer timer;

  // do stuff, preferably in a 100x loop to make it take longer.

  return 0;
}

जब progress_timerयह दायरे से बाहर हो जाता है तो इसके निर्माण के बाद से बीता हुआ समय प्रिंट हो जाएगा।

अद्यतन : यहाँ एक संस्करण है जो बिना बूस्ट के काम करता है (macOS / iOS पर परीक्षण किया गया है):

#include <chrono>
#include <string>
#include <iostream>
#include <math.h>
#include <unistd.h>

class NLTimerScoped {
private:
    const std::chrono::steady_clock::time_point start;
    const std::string name;

public:
    NLTimerScoped( const std::string & name ) : name( name ), start( std::chrono::steady_clock::now() ) {
    }


    ~NLTimerScoped() {
        const auto end(std::chrono::steady_clock::now());
        const auto duration_ms = std::chrono::duration_cast<std::chrono::milliseconds>( end - start ).count();

        std::cout << name << " duration: " << duration_ms << "ms" << std::endl;
    }

};

int main(int argc, const char * argv[]) {

    {
        NLTimerScoped timer( "sin sum" );

        float a = 0.0f;

        for ( int i=0; i < 1000000; i++ ) {
            a += sin( (float) i / 100 );
        }

        std::cout << "sin sum = " << a << std::endl;
    }



    {
        NLTimerScoped timer( "sleep( 4 )" );

        sleep( 4 );
    }



    return 0;
}

2
यह काम करता है, लेकिन ध्यान दें कि प्रगति_टाइमर को पदावनत किया जाता है (1.50 को बढ़ावा देने से पहले) - auto_cpu_timer अधिक उपयुक्त हो सकता है।
davidA

3
@meowsqueak हम्म, auto_cpu_timer को बूस्ट सिस्टम लाइब्रेरी को जोड़ने की आवश्यकता प्रतीत होती है, इसलिए यह हेडर-ओनली सॉल्यूशन नहीं है। बहुत बुरा ... अचानक अन्य विकल्पों को और अधिक आकर्षक बनाता है।
टॉमस एंड्रले

1
हाँ, यह एक अच्छा बिंदु है, अगर आप पहले से ही बूस्ट को लिंक नहीं करते हैं, तो यह मूल्य की तुलना में अधिक परेशानी है। लेकिन अगर आप पहले से ही ऐसा करते हैं, तो यह काफी अच्छा काम करता है।
davidA

@meowsqueak हाँ, या कुछ त्वरित बेंचमार्क परीक्षणों के लिए, बूस्ट के पुराने संस्करण को प्राप्त करें।
टॉमस एंड्रेल

@TomasAndrle लिंक अब मौजूद नहीं है।
झेंग क्व

5

विंडोज QueryPerformanceCounter () फ़ंक्शन प्रदान करता है, और यूनिक्स में गेटटाइमऑफडे () दोनों फ़ंक्शन कम से कम 1 माइक्रो-सेकंड अंतर को माप सकते हैं।


लेकिन windows.h का उपयोग प्रतिबंधित है। समान संकलित स्रोत को विंडोज और यूनिक्स दोनों पर चलना चाहिए। इस समस्या को कैसे संभालें?
अहमत -


4
एक ही संकलित स्रोत लगता है जैसे आप दोनों सिस्टम पर एक ही बाइनरी चलाना चाहते हैं, जो मामला नहीं लगता है। यदि आपका मतलब एक ही स्रोत है तो #ifdefठीक होना चाहिए (और यह आपके द्वारा स्वीकार किए गए उत्तर से आंका जाता है), और फिर मुझे समस्या दिखाई नहीं देती #ifdef WIN32 #include <windows.h> ... #else ... #endif:।
किसी को

3

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

(लिंक ऊपर एक फ्रेंच विकिपीडिया पृष्ठ पर है, लेकिन इसमें C ++ कोड नमूने हैं, अंग्रेजी संस्करण यहां है )


2

मैं सिस्टम से समय की जानकारी प्राप्त करने के लिए मानक पुस्तकालय कार्यों का उपयोग करने का सुझाव देता हूं।

यदि आप बेहतर समाधान चाहते हैं, तो अधिक निष्पादन पुनरावृत्तियों का प्रदर्शन करें। एक बार कार्यक्रम चलाने और नमूने प्राप्त करने के बजाय, इसे 1000 बार या अधिक चलाएं।


2

आंतरिक लूप को कई बार केवल एक बार प्रदर्शन समय के साथ चलाना बेहतर होता है और आंतरिक लूप पुनरावृत्ति को विभाजित करके औसतन पूरी चीज (लूप + प्रदर्शन समय) को कई बार और औसत से चलाना होता है। यह प्रदर्शन समय कोड के ओवरहेड को कम कर देगा बनाम आपका वास्तविक प्रोफाइल अनुभाग।

उपयुक्त प्रणाली के लिए अपने टाइमर कॉल लपेटें। विंडोज के लिए, QueryPerformanceCounter उपयोग करने के लिए बहुत तेज़ और "सुरक्षित" है।

आप किसी भी आधुनिक X86 पीसी पर "rdtsc" का उपयोग कर सकते हैं, लेकिन कुछ मल्टीकोर मशीनों पर समस्याएँ हो सकती हैं (कोर होपिंग टाइमर बदल सकती है) या यदि आपके पास किसी प्रकार का स्पीड-स्टेप चालू है।


2

(विंडोज़ विशिष्ट समाधान) खिड़कियों के नीचे सटीक समय प्राप्त करने का वर्तमान (लगभग 2017) तरीका "क्वेरपेरफॉर्मेंस एनकाउंटर" का उपयोग करना है। इस दृष्टिकोण को बहुत सटीक परिणाम देने का लाभ है और एमएस द्वारा अनुशंसित है। बस काम के नमूने को पाने के लिए एक नए कंसोल ऐप में कोड बूँद को दबाएं। यहाँ एक लंबी चर्चा है: उच्च रिज़ॉल्यूशन समय टिकटों को प्राप्त करना

#include <iostream>
#include <tchar.h>
#include <windows.h>

int main()
{
constexpr int MAX_ITER{ 10000 };
constexpr __int64 us_per_hour{ 3600000000ull }; // 3.6e+09
constexpr __int64 us_per_min{ 60000000ull };
constexpr __int64 us_per_sec{ 1000000ull };
constexpr __int64 us_per_ms{ 1000ull };

// easy to work with
__int64 startTick, endTick, ticksPerSecond, totalTicks = 0ull;

QueryPerformanceFrequency((LARGE_INTEGER *)&ticksPerSecond);

for (int iter = 0; iter < MAX_ITER; ++iter) {// start looping
    QueryPerformanceCounter((LARGE_INTEGER *)&startTick); // Get start tick
    // code to be timed
    std::cout << "cur_tick = " << iter << "\n";
    QueryPerformanceCounter((LARGE_INTEGER *)&endTick); // Get end tick
    totalTicks += endTick - startTick; // accumulate time taken
}

// convert to elapsed microseconds
__int64 totalMicroSeconds =  (totalTicks * 1000000ull)/ ticksPerSecond;

__int64 hours = totalMicroSeconds / us_per_hour;
totalMicroSeconds %= us_per_hour;
__int64 minutes = totalMicroSeconds / us_per_min;
totalMicroSeconds %= us_per_min;
__int64 seconds = totalMicroSeconds / us_per_sec;
totalMicroSeconds %= us_per_sec;
__int64 milliseconds = totalMicroSeconds / us_per_ms;
totalMicroSeconds %= us_per_ms;


std::cout << "Total time: " << hours << "h ";
std::cout << minutes << "m " << seconds << "s " << milliseconds << "ms ";
std::cout << totalMicroSeconds << "us\n";

return 0;
}

2

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

OS-free में जाने का एक अच्छा विकल्प सिर्फ वर्तमान थ्रेड की आत्मीयता को 1 कोर पर सेट करना और सर्वोच्चता को प्राथमिकता देना है। इस विकल्प को लगातार-पर्याप्त परिणाम प्रदान करना चाहिए।

इसके अलावा, आपको उन ऑप्टिमाइज़ेशन को बंद करना चाहिए जो डिबगिंग में हस्तक्षेप करेंगे, जो कि जी ++ या जीसीसी के लिए कमांड लाइन को जोड़ने -Ogका मतलब है , ताकि कोड को अनुकूलित होने से रोका जा सके। -O0झंडा, क्योंकि यह अतिरिक्त अनावश्यक भूमि के ऊपर जो समय परिणामों में शामिल किया जाएगा पेश करता है, इस प्रकार कोड के समय की गति को बढ़ा नहीं किया जाना चाहिए।

इसके विपरीत, दोनों मानते हैं कि आप अंतिम उत्पादन बिल्ड पर " -Ofast(या बहुत कम से कम -O3) का उपयोग करते हैं और" मृत "कोड उन्मूलन के मुद्दे को अनदेखा करते हैं, -Ogकी तुलना में बहुत कम अनुकूलन करते हैं -Ofast; इस प्रकार -Ogअंतिम उत्पाद में कोड की वास्तविक गति का गलत विवरण दिया जा सकता है।

इसके अलावा, सभी गति परीक्षण (कुछ हद तक) perjure: के साथ संकलित अंतिम उत्पादन उत्पाद में -Ofast, प्रत्येक स्निपेट / अनुभाग / कोड के फ़ंक्शन को अलग नहीं किया जाता है; बल्कि, कोड का प्रत्येक स्निपेट लगातार अगले में बहता है, इस प्रकार संकलक को संभावित रूप से जुड़ने, विलय करने और सभी जगह से कोड के टुकड़ों को एक साथ अनुकूलित करने की अनुमति मिलती है।

उसी समय, यदि आप कोड के एक स्निपेट को बेंचमार्क कर रहे हैं, जिसका भारी उपयोग हो रहा है realloc(), तो कोड का स्निप उच्च उत्पादन में धीमी स्मृति विखंडन के साथ उत्पादन उत्पाद में धीमी गति से चल सकता है। इसलिए, अभिव्यक्ति "पूरी तरह से इसके भागों के योग से अधिक है" इस स्थिति पर लागू होती है क्योंकि अंतिम उत्पादन बिल्ड में कोड व्यक्तिगत स्निपेट की तुलना में काफी तेज या धीमी गति से चल सकता है जिसे आप गति परीक्षण कर रहे हैं।

एक आंशिक समाधान जो असंगति को कम कर सकता है -Ofastगति परीक्षण के लिए उपयोग कर रहा है asm volatile("" :: "r"(var))जिसमें मृत कोड / लूप उन्मूलन को रोकने के लिए परीक्षण में शामिल चर शामिल किए गए हैं।

यहाँ एक उदाहरण है कि विंडोज कंप्यूटर पर स्क्वायर रूट फ़ंक्शन को कैसे बेंच दिया जाए।

// set USE_ASM_TO_PREVENT_ELIMINATION  to 0 to prevent `asm volatile("" :: "r"(var))`
// set USE_ASM_TO_PREVENT_ELIMINATION  to 1 to enforce `asm volatile("" :: "r"(var))`
#define USE_ASM_TO_PREVENT_ELIMINATION 1

#include <iostream>
#include <iomanip>
#include <cstdio>
#include <chrono>
#include <cmath>
#include <windows.h>
#include <intrin.h>
#pragma intrinsic(__rdtsc)
#include <cstdint>

class Timer {
public:
    Timer() : beg_(clock_::now()) {}
    void reset() { beg_ = clock_::now(); }
    double elapsed() const { 
        return std::chrono::duration_cast<second_>
            (clock_::now() - beg_).count(); }
private:
    typedef std::chrono::high_resolution_clock clock_;
    typedef std::chrono::duration<double, std::ratio<1> > second_;
    std::chrono::time_point<clock_> beg_;
};

unsigned int guess_sqrt32(register unsigned int n) {
    register unsigned int g = 0x8000;
    if(g*g > n) {
        g ^= 0x8000;
    }
    g |= 0x4000;
    if(g*g > n) {
        g ^= 0x4000;
    }
    g |= 0x2000;
    if(g*g > n) {
        g ^= 0x2000;
    }
    g |= 0x1000;
    if(g*g > n) {
        g ^= 0x1000;
    }
    g |= 0x0800;
    if(g*g > n) {
        g ^= 0x0800;
    }
    g |= 0x0400;
    if(g*g > n) {
        g ^= 0x0400;
    }
    g |= 0x0200;
    if(g*g > n) {
        g ^= 0x0200;
    }
    g |= 0x0100;
    if(g*g > n) {
        g ^= 0x0100;
    }
    g |= 0x0080;
    if(g*g > n) {
        g ^= 0x0080;
    }
    g |= 0x0040;
    if(g*g > n) {
        g ^= 0x0040;
    }
    g |= 0x0020;
    if(g*g > n) {
        g ^= 0x0020;
    }
    g |= 0x0010;
    if(g*g > n) {
        g ^= 0x0010;
    }
    g |= 0x0008;
    if(g*g > n) {
        g ^= 0x0008;
    }
    g |= 0x0004;
    if(g*g > n) {
        g ^= 0x0004;
    }
    g |= 0x0002;
    if(g*g > n) {
        g ^= 0x0002;
    }
    g |= 0x0001;
    if(g*g > n) {
        g ^= 0x0001;
    }
    return g;
}

unsigned int empty_function( unsigned int _input ) {
    return _input;
}

unsigned long long empty_ticks=0;
double empty_seconds=0;
Timer my_time;

template<unsigned int benchmark_repetitions>
void benchmark( char* function_name, auto (*function_to_do)( auto ) ) {
    register unsigned int i=benchmark_repetitions;
    register unsigned long long start=0;
    my_time.reset();
    start=__rdtsc();
    while ( i-- ) {
        auto result = (*function_to_do)( i << 7 );
        #if USE_ASM_TO_PREVENT_ELIMINATION == 1
            asm volatile("" :: "r"(
                // There is no data type in C++ that is smaller than a char, so it will
                //  not throw a segmentation fault error to reinterpret any arbitrary
                //  data type as a char. Although, the compiler might not like it.
                result
            ));
        #endif
    }
    if ( function_name == nullptr ) {
        empty_ticks = (__rdtsc()-start);
        empty_seconds = my_time.elapsed();
        std::cout<< "Empty:\n" << empty_ticks
              << " ticks\n" << benchmark_repetitions << " repetitions\n"
               << std::setprecision(15) << empty_seconds
                << " seconds\n\n";
    } else {
        std::cout<< function_name<<":\n" << (__rdtsc()-start-empty_ticks)
              << " ticks\n" << benchmark_repetitions << " repetitions\n"
               << std::setprecision(15) << (my_time.elapsed()-empty_seconds)
                << " seconds\n\n";
    }
}


int main( void ) {
    void* Cur_Thread=   GetCurrentThread();
    void* Cur_Process=  GetCurrentProcess();
    unsigned long long  Current_Affinity;
    unsigned long long  System_Affinity;
    unsigned long long furthest_affinity;
    unsigned long long nearest_affinity;

    if( ! SetThreadPriority(Cur_Thread,THREAD_PRIORITY_TIME_CRITICAL) ) {
        SetThreadPriority( Cur_Thread, THREAD_PRIORITY_HIGHEST );
    }
    if( ! SetPriorityClass(Cur_Process,REALTIME_PRIORITY_CLASS) ) {
        SetPriorityClass( Cur_Process, HIGH_PRIORITY_CLASS );
    }
    GetProcessAffinityMask( Cur_Process, &Current_Affinity, &System_Affinity );
    furthest_affinity = 0x8000000000000000ULL>>__builtin_clzll(Current_Affinity);
    nearest_affinity  = 0x0000000000000001ULL<<__builtin_ctzll(Current_Affinity);
    SetProcessAffinityMask( Cur_Process, furthest_affinity );
    SetThreadAffinityMask( Cur_Thread, furthest_affinity );

    const int repetitions=524288;

    benchmark<repetitions>( nullptr, empty_function );
    benchmark<repetitions>( "Standard Square Root", standard_sqrt );
    benchmark<repetitions>( "Original Guess Square Root", original_guess_sqrt32 );
    benchmark<repetitions>( "New Guess Square Root", new_guess_sqrt32 );


    SetThreadPriority( Cur_Thread, THREAD_PRIORITY_IDLE );
    SetPriorityClass( Cur_Process, IDLE_PRIORITY_CLASS );
    SetProcessAffinityMask( Cur_Process, nearest_affinity );
    SetThreadAffinityMask( Cur_Thread, nearest_affinity );
    for (;;) { getchar(); }

    return 0;
}

इसके अलावा, अपने टाइमर के लिए माइक जार्विस को श्रेय दिया।

कृपया ध्यान दें (यह बहुत महत्वपूर्ण है) कि यदि आप बड़े कोड स्निपेट चलाने जा रहे हैं, तो आपको वास्तव में अपने कंप्यूटर को ठंड से बचाने के लिए पुनरावृत्तियों की संख्या को बंद करना होगा।


2
अनुकूलन को अक्षम करने के अलावा अच्छा जवाब। बेंचमार्किंग -O0कोड समय की एक बड़ी बर्बादी है क्योंकि -O0 एक सामान्य के बजाय ओवरहेड -O2या कोड और कार्यभार के आधार पर बेतहाशा-O3 -march=native भिन्न होता है । उदाहरण के लिए अतिरिक्त नाम tmp vars पर समय खर्च होता है । चीजों को अनुकूलित करने से बचने के अन्य तरीके हैं, जैसे कि आशावादी से चीजों को छिपाना , गैर-इनलाइन फ़ंक्शन या खाली इनलाइन बयानों को छिपाना । प्रयोग करने योग्य के करीब भी नहीं है क्योंकि कोड में अलग-अलग अड़चनें हैं , समान नहीं बल्कि बदतर। -O0volatile-O0-O0
पीटर कॉर्डेस

1
उह, -Ogकोड के आधार पर अभी भी बहुत यथार्थवादी नहीं है। कम से कम -O2, अधिमानतः -O3अधिक यथार्थवादी है। asm volatile("" ::: "+r"(var))संकलक को किसी रजिस्टर में मान देने के लिए उपयोग करें या कुछ करें , और इसके माध्यम से निरंतर प्रसार को पराजित करें।
पीटर कॉर्डेस

@PeterCordes अपनी अंतर्दृष्टि के लिए फिर से धन्यवाद। मैंने सामग्री -O3और कोड स्निपेट के साथ अपडेट किया है asm volatile("" ::: "+r"(var))
जैक गिफिन

1
asm volatile("" ::: "+r"( i ));अनावश्यक लगता है। अनुकूलित कोड में, संकलक के iसाथ-साथ i<<7लूप के अंदर भी मजबूर करने का कोई कारण नहीं है । आप इसे tmp -= 128हर बार स्थानांतरित करने के बजाय अनुकूलन से रोक रहे हैं । फ़ंक्शन कॉल के परिणाम का उपयोग करना अच्छा है, हालांकि, यदि यह गैर है- void। की तरह int result = (*function_to_do)( i << 7 );। आप asmउस परिणाम पर एक बयान का उपयोग कर सकते हैं ।
पीटर कॉर्डेस

@PeterCordes बहुत बहुत धन्यवाद फिर से या अपनी अंतर्दृष्टि। मेरी पोस्ट में अब रिटर्न वैल्यू के लिए सुधार शामिल हैं function_to_doताकि function_to_doइसे समाप्त किए बिना इनलाइन किया जा सके। यदि आपके कोई और सुझाव हों तो कृपया मुझे बताएं।
जैक गिफिन

1

उन मामलों के लिए जहां आप हर बार कोड के एक ही खंड को निष्पादित करना चाहते हैं (उदाहरण के लिए कोड जो आपको लगता है कि अड़चन हो सकता है) के लिए, यहाँ एक रैपर है (थोड़ा संशोधन) एंड्रियास बोनिनी के कार्य के लिए जो उपयोगी लगता है:

#ifdef _WIN32
#include <Windows.h>
#else
#include <sys/time.h>
#endif

/*
 *  A simple timer class to see how long a piece of code takes. 
 *  Usage:
 *
 *  {
 *      static Timer timer("name");
 *
 *      ...
 *
 *      timer.start()
 *      [ The code you want timed ]
 *      timer.stop()
 *
 *      ...
 *  }
 *
 *  At the end of execution, you will get output:
 *
 *  Time for name: XXX seconds
 */
class Timer
{
public:
    Timer(std::string name, bool start_running=false) : 
        _name(name), _accum(0), _running(false)
    {
        if (start_running) start();
    }

    ~Timer() { stop(); report(); }

    void start() {
        if (!_running) {
            _start_time = GetTimeMicroseconds();
            _running = true;
        }
    }
    void stop() {
        if (_running) {
            unsigned long long stop_time = GetTimeMicroseconds();
            _accum += stop_time - _start_time;
            _running = false;
        }
    }
    void report() { 
        std::cout<<"Time for "<<_name<<": " << _accum / 1.e6 << " seconds\n"; 
    }
private:
    // cf. http://stackoverflow.com/questions/1861294/how-to-calculate-execution-time-of-a-code-snippet-in-c
    unsigned long long GetTimeMicroseconds()
    {
#ifdef _WIN32
        /* Windows */
        FILETIME ft;
        LARGE_INTEGER li;

        /* Get the amount of 100 nano seconds intervals elapsed since January 1, 1601 (UTC) and copy it
         *   * to a LARGE_INTEGER structure. */
        GetSystemTimeAsFileTime(&ft);
        li.LowPart = ft.dwLowDateTime;
        li.HighPart = ft.dwHighDateTime;

        unsigned long long ret = li.QuadPart;
        ret -= 116444736000000000LL; /* Convert from file time to UNIX epoch time. */
        ret /= 10; /* From 100 nano seconds (10^-7) to 1 microsecond (10^-6) intervals */
#else
        /* Linux */
        struct timeval tv;

        gettimeofday(&tv, NULL);

        unsigned long long ret = tv.tv_usec;
        /* Adds the seconds (10^0) after converting them to microseconds (10^-6) */
        ret += (tv.tv_sec * 1000000);
#endif
        return ret;
    }
    std::string _name;
    long long _accum;
    unsigned long long _start_time;
    bool _running;
};

1

एक साधारण वर्ग जो कोडब्लॉक को बेंचमार्क करता है:

using namespace std::chrono;

class benchmark {
  public:
  time_point<high_resolution_clock>  t0, t1;
  unsigned int *d;
  benchmark(unsigned int *res) : d(res) { 
                 t0 = high_resolution_clock::now();
  }
  ~benchmark() { t1 = high_resolution_clock::now();
                  milliseconds dur = duration_cast<milliseconds>(t1 - t0);
                  *d = dur.count();
  }
};
// simple usage 
// unsigned int t;
// { // put the code in a block
//  benchmark bench(&t);
//  // ...
//  // code to benchmark
// }
// HERE the t contains time in milliseconds

// one way to use it can be :
#define BENCH(TITLE,CODEBLOCK) \
  unsigned int __time__##__LINE__ = 0;  \
  { benchmark bench(&__time__##__LINE__); \
      CODEBLOCK \
  } \
  printf("%s took %d ms\n",(TITLE),__time__##__LINE__);


int main(void) {
  BENCH("TITLE",{
    for(int n = 0; n < testcount; n++ )
      int a = n % 3;
  });
  return 0;
}

0

बढ़ावा :: टाइमर शायद आपको उतनी ही सटीकता देगा जितनी आपको आवश्यकता होगी। यह कहीं भी सटीक नहीं है कि आपको यह बताएं कि आपको कितना समय a = a+1;लगेगा, लेकिन मुझे क्या कारण होगा कि आप कुछ ऐसा कर सकते हैं जो एक जोड़ी नैनोसेकंड्स में ले जाए?


यह clock()C ++ मानक हेडर से फ़ंक्शन पर निर्भर करता है ।
पेट्टर

0

मैंने एक लैम्ब्डा बनाया है जो आपको एन कॉल कॉल फंक्शन बार और आपको औसत लौटाता है।

double c = BENCHMARK_CNT(25, fillVectorDeque(variable));

आप c ++ 11 हेडर यहां पा सकते हैं ।


0

मैंने क्रोनो लाइब्रेरी के high_resolution_clock: https://github.com/nfergu/codetimer का उपयोग करके कोड के ब्लॉकों के प्रदर्शन को मापने के लिए एक सरल उपयोगिता बनाई ।

समय अलग-अलग कुंजी के खिलाफ दर्ज किया जा सकता है, और प्रत्येक कुंजी के लिए समय का एक समग्र दृश्य प्रदर्शित किया जा सकता है।

उपयोग निम्नानुसार है:

#include <chrono>
#include <iostream>
#include "codetimer.h"

int main () {
    auto start = std::chrono::high_resolution_clock::now();
    // some code here
    CodeTimer::record("mykey", start);
    CodeTimer::printStats();
    return 0;
}

0

आप [cxx-rtimers][1]GitHub पर भी देख सकते हैं , जो किसी भी कोड-ब्लॉक के रन-टाइम पर आंकड़े इकट्ठा करने के लिए कुछ हेडर-मात्र दिनचर्या प्रदान करते हैं जहां आप एक स्थानीय चर बना सकते हैं। उन टाइमर के संस्करण हैं जो C ++ 11 पर std :: chrono का उपयोग करते हैं, या बूस्ट लाइब्रेरी से टाइमर, या मानक POSIX टाइमर फ़ंक्शन। ये टाइमर एक फ़ंक्शन के भीतर खर्च की गई औसत, अधिकतम और न्यूनतम अवधि की रिपोर्ट करेंगे, साथ ही इसे कितनी बार कहा जाएगा। उनका उपयोग केवल इस प्रकार किया जा सकता है:

#include <rtimers/cxx11.hpp>

void expensiveFunction() {
    static rtimers::cxx11::DefaultTimer timer("expensive");
    auto scopedStartStop = timer.scopedStart();
    // Do something costly...
}

0

Thats मैं यह कैसे करते हैं, ज्यादा कोड नहीं, समझने में आसान है, मेरी जरूरतों को पूरा करता है:

void bench(std::function<void()> fnBench, std::string name, size_t iterations)
{
    if (iterations == 0)
        return;
    if (fnBench == nullptr)
        return;
    std::chrono::high_resolution_clock::time_point start, end;
    if (iterations == 1)
    {
        start = std::chrono::high_resolution_clock::now();
        fnBench();
        end = std::chrono::high_resolution_clock::now();
    }
    else
    {
        start = std::chrono::high_resolution_clock::now();
        for (size_t i = 0; i < iterations; ++i)
            fnBench();
        end = std::chrono::high_resolution_clock::now();
    }
    printf
    (
        "bench(*, \"%s\", %u) = %4.6lfs\r\n",
        name.c_str(),
        iterations,
        std::chrono::duration_cast<std::chrono::duration<double>>(end - start).count()
    );
}

उपयोग:

bench
(
    []() -> void // function
    {
        // Put your code here
    },
    "the name of this", // name
    1000000 // iterations
);

0
#include <omp.h>

double start = omp_get_wtime();

// code 

double finish = omp_get_wtime();

double total_time = finish - start;

2
हालांकि यह कोड प्रश्न को हल कर सकता है, जिसमें यह भी बताया गया है कि यह समस्या कैसे और क्यों हल करती है, इससे वास्तव में आपके पोस्ट की गुणवत्ता को बेहतर बनाने में मदद मिलेगी, और संभवत: अधिक वोट मिले। याद रखें कि आप भविष्य में पाठकों के लिए प्रश्न का उत्तर दे रहे हैं, न कि केवल उस व्यक्ति से जो अब पूछ रहा है। स्पष्टीकरण जोड़ने के लिए कृपया अपना उत्तर संपादित करें और संकेत दें कि क्या सीमाएँ और मान्यताएँ लागू होती हैं।
धर्मन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.