C ++ का उपयोग करके नैनो सेकंड में समय प्रदान करने के लिए टाइमर फ़ंक्शन


101

मैं किसी API को मान वापस करने के लिए लगने वाले समय की गणना करना चाहता हूं। इस तरह की कार्रवाई के लिए समय नैनो सेकंड के स्थान पर है। चूंकि एपीआई एक C ++ क्लास / फंक्शन है, इसलिए मैं टाइमर का उपयोग कर रहा हूं।

  #include <ctime>
  #include <cstdio>

  using namespace std;

  int main(int argc, char** argv) {

      clock_t start;
      double diff;
      start = clock();
      diff = ( std::clock() - start ) / (double)CLOCKS_PER_SEC;
      cout<<"printf: "<< diff <<'\n';

      return 0;
  }

उपरोक्त कोड सेकंड में समय देता है। मैं नैनो सेकंड में और अधिक सटीकता के साथ कैसे प्राप्त करूं?


उपरोक्त कोड सेकंड में गणना करता है, मैं नैनो सेकंड में उत्तर प्राप्त करना चाहता हूँ ...
gagneet

एक अच्छा जवाब पाने के लिए सवाल (और साथ ही शीर्षक के लिए) के लिए मंच को जोड़ने की आवश्यकता है।
पैट्रिक जॉम्नियर 19

इसके अतिरिक्त, समय प्राप्त करने के लिए, किसी को माइक्रोबेनमार्किंग (जो कि बहुत जटिल है) के साथ मुद्दों को देखने की जरूरत है - बस एक निष्पादन करना, और शुरुआत और अंत में समय प्राप्त करना, पर्याप्त सटीकता देने की संभावना नहीं है।
ब्‍लॉसरब्‍लेड

@ ब्लेज़रब्लेड: विशेष रूप से जब से मैंने अपने कुछ परीक्षणों में खोजा है जो clock()लगभग उतना तेज़ नहीं है जितना मैंने सोचा था कि यह था।
मूसिंग डक

जवाबों:


83

फ़ंक्शन को लूप में बार-बार चलाने के बारे में दूसरों ने जो पोस्ट किया है वह सही है।

लिनक्स (और बीएसडी) के लिए आप clock_gettime () का उपयोग करना चाहते हैं ।

#include <sys/time.h>

int main()
{
   timespec ts;
   // clock_gettime(CLOCK_MONOTONIC, &ts); // Works on FreeBSD
   clock_gettime(CLOCK_REALTIME, &ts); // Works on Linux
}

विंडोज़ के लिए आप QueryPerformanceCounter का उपयोग करना चाहते हैं । और यहाँ QPC पर अधिक है

स्पष्ट रूप से कुछ चिपसेट पर QPC के साथ एक ज्ञात समस्या है , इसलिए आप यह सुनिश्चित करना चाहते हैं कि आपके पास उन चिपसेट नहीं हैं। इसके अतिरिक्त कुछ दोहरे कोर एएमडी भी एक समस्या पैदा कर सकते हैं । Sebbbi द्वारा दूसरी पोस्ट देखें, जहाँ वह बताता है:

QueryPerformanceCounter () और QueryPerformanceFrequency () थोड़ा बेहतर रिज़ॉल्यूशन प्रदान करते हैं, लेकिन अलग-अलग मुद्दे हैं। विंडोज एक्सपी में उदाहरण के लिए, सभी एएमडी एथलॉन एक्स 2 दोहरे कोर सीपीयू "कोर को बेतरतीब ढंग से" (पीसी कभी-कभी थोड़ा पीछे कूदता है) के पीसी को वापस कर देते हैं, जब तक कि आप विशेष रूप से समस्या को ठीक करने के लिए एएमडी डुअल कोर ड्राइवर पैकेज स्थापित नहीं करते हैं। हमने किसी अन्य दोहरे + कोर सीपीयू पर ध्यान नहीं दिया है जिसमें समान मुद्दे (p4 दोहरे, p4 ht, core2 दोहरे, core2 क्वाड, फिनोम क्वाड) हैं।

EDIT 2013/07/16:

ऐसा लगता है कि कुछ परिस्थितियों में QPC की प्रभावशीलता पर कुछ विवाद है जैसा कि http://msdn.microsoft.com/en-us/library/windows/desktop/ee417693(v=vs.85).aspx में बताया गया है

... जबकि QueryPerformanceCounter और QueryPerformanceFrequency आम तौर पर कई प्रोसेसर के लिए समायोजित होते हैं, BIOS या ड्राइवरों में बग के परिणामस्वरूप ये रूटीन अलग-अलग मान लौटा सकते हैं क्योंकि थ्रेड एक प्रोसेसर से दूसरे प्रोसेसर पर जाता है ...

हालाँकि यह StackOverflow उत्तर https://stackoverflow.com/a/4588605/34329 बताता है कि Win XP सर्विस पैक 2 के बाद QPC को किसी भी MS OS पर ठीक काम करना चाहिए।

यह आलेख दिखाता है कि विंडोज 7 निर्धारित कर सकता है कि प्रोसेसर (एस) में एक अपरिवर्तनीय टीएससी है और नहीं होने पर बाहरी टाइमर पर वापस आ जाता है। http://performancebydesign.blogspot.com/2012/03/high-resolution-clocks-and-timers-for.html प्रोसेसर में सिंक्रनाइज़ करना अभी भी एक मुद्दा है।

टाइमर से संबंधित अन्य ठीक पढ़ने:

अधिक जानकारी के लिए टिप्पणियाँ देखें।


1
मैंने एक पुराने डुअल एक्सोन पीसी पर टीएससी घड़ी तिरछा देखा है, लेकिन लगभग उतना बुरा नहीं है जितना कि एथलोन एक्स 2 पर सी 1 क्लॉक रैंपिंग सक्षम है। C1 घड़ी रैंपिंग के साथ, एक HLT निर्देश निष्पादित करते हुए घड़ी को धीमा कर देती है, जिससे TSC निष्क्रिय कोर पर सक्रिय कोर की तुलना में अधिक धीरे-धीरे वृद्धि होती है।
bk1e

6
CLOCK_MONOTONIC लिनक्स के संस्करणों पर काम करता है जो मेरे पास उपलब्ध है।
बर्नार्ड

1
@ बर्नार्ड - जब से मैंने आखिरी बार इसे देखा था तब से इसे जोड़ा जाना चाहिए। सर उठाने के लिए धन्यवाद।
शोक

3
वास्तव में, आपको उपयोग करना होगा CLOCK_MONOTONIC_RAW, अगर यह उपलब्ध है, ताकि एनटीपी द्वारा हार्डवेयर समय को समायोजित नहीं किया जा सके।

जैसा कि यहां चर्चा की गई है, QPC का सही क्रियान्वयन TSC काउंटर का उपयोग नहीं करता है, कम से कम जहां इसे अविश्वसनीय माना जाता है: stackoverflow.com/q/510462/53974
Blaisorblade

69

यह नया उत्तर C ++ 11 की <chrono>सुविधा का उपयोग करता है । जबकि अन्य उत्तर हैं जो दिखाते हैं कि कैसे उपयोग करना है <chrono>, उनमें से कोई भी नहीं दिखाता है कि यहां दिए गए कई अन्य उत्तरों में वर्णित सुविधा के <chrono>साथ कैसे उपयोग RDTSCकिया जाए। इसलिए मैंने सोचा कि मैं दिखाऊंगा कि कैसे उपयोग RDTSCकरना है <chrono>। इसके अतिरिक्त मैं प्रदर्शित कि किस प्रकार आप है कि आप तेजी से बीच स्विच कर सकते घड़ी पर परीक्षण कोड templatize कर सकते हैं ताकि RDTSCऔर अपने सिस्टम में निर्मित है घड़ी सुविधाओं (जो की संभावना पर आधारित होगा clock(), clock_gettime()और / या QueryPerformanceCounter

ध्यान दें कि RDTSCनिर्देश x86- विशिष्ट है। QueryPerformanceCounterकेवल विंडोज है। और clock_gettime()केवल POSIX है। नीचे मैं दो नई घड़ियां पेश करता हूं: std::chrono::high_resolution_clockऔर std::chrono::system_clock, यदि आप C ++ 11 मान सकते हैं, तो अब क्रॉस-प्लेटफॉर्म हैं।

सबसे पहले, यहां बताया गया है कि आप इंटेल rdtscअसेंबली इंस्ट्रक्शन से बाहर C ++ 11-कम्पेटिबल क्लॉक कैसे बनाते हैं । मैं इसे कॉल करूंगा x::clock:

#include <chrono>

namespace x
{

struct clock
{
    typedef unsigned long long                 rep;
    typedef std::ratio<1, 2'800'000'000>       period; // My machine is 2.8 GHz
    typedef std::chrono::duration<rep, period> duration;
    typedef std::chrono::time_point<clock>     time_point;
    static const bool is_steady =              true;

    static time_point now() noexcept
    {
        unsigned lo, hi;
        asm volatile("rdtsc" : "=a" (lo), "=d" (hi));
        return time_point(duration(static_cast<rep>(hi) << 32 | lo));
    }
};

}  // x

यह सब घड़ी सीपीयू चक्रों की गणना करता है और इसे एक बिना लाइसेंस वाले 64-बिट पूर्णांक में संग्रहीत करता है। आपको अपने कंपाइलर के लिए असेंबली भाषा के सिंटैक्स को ट्विक करने की आवश्यकता हो सकती है। या आपका कंपाइलर एक आंतरिक प्रदान कर सकता है जिसका आप उपयोग कर सकते हैं (जैसे now() {return __rdtsc();})।

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

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

नीचे उदाहरण कोड है जो दिखाता है कि कैसे उपयोग करना है x::clock। वास्तव में मैंने घड़ी पर कोड को रोक दिया है क्योंकि मैं यह दिखाना चाहता हूं कि आप एक ही समान सिंटैक्स के साथ कई अलग-अलग घड़ियों का उपयोग कैसे कर सकते हैं। यह विशेष परीक्षण दिखा रहा है कि लूपिंग ओवरहेड क्या है जब आप एक लूप के तहत समय देना चाहते हैं:

#include <iostream>

template <class clock>
void
test_empty_loop()
{
    // Define real time units
    typedef std::chrono::duration<unsigned long long, std::pico> picoseconds;
    // or:
    // typedef std::chrono::nanoseconds nanoseconds;
    // Define double-based unit of clock tick
    typedef std::chrono::duration<double, typename clock::period> Cycle;
    using std::chrono::duration_cast;
    const int N = 100000000;
    // Do it
    auto t0 = clock::now();
    for (int j = 0; j < N; ++j)
        asm volatile("");
    auto t1 = clock::now();
    // Get the clock ticks per iteration
    auto ticks_per_iter = Cycle(t1-t0)/N;
    std::cout << ticks_per_iter.count() << " clock ticks per iteration\n";
    // Convert to real time units
    std::cout << duration_cast<picoseconds>(ticks_per_iter).count()
              << "ps per iteration\n";
}

पहली चीज़ जो यह कोड करती है, वह परिणामों को प्रदर्शित करने के लिए एक "वास्तविक समय" इकाई बनाती है। मैंने पिकोसेकंड चुना है, लेकिन आप अपनी पसंद की किसी भी इकाई को चुन सकते हैं, या तो अभिन्न या फ़्लोटिंग पॉइंट आधारित। एक उदाहरण के रूप में एक पूर्व-निर्मित std::chrono::nanosecondsइकाई है जिसका मैं उपयोग कर सकता था।

एक अन्य उदाहरण के रूप में, मैं फ्लोटिंग पॉइंट के रूप में प्रति चलना घड़ी चक्र की औसत संख्या को प्रिंट करना चाहता हूं, इसलिए मैं एक और अवधि बनाता हूं, जो डबल पर आधारित है, जिसमें एक ही इकाइयाँ हैं जैसे कि घड़ी की टिक ( Cycleकोड में कहा जाता है)।

लूप clock::now()दोनों तरफ कॉल के साथ समयबद्ध है । यदि आप इस फ़ंक्शन से लौटाए गए प्रकार को नाम देना चाहते हैं तो यह है:

typename clock::time_point t0 = clock::now();

(जैसा कि स्पष्ट रूप से x::clockउदाहरण में दिखाया गया है , और सिस्टम द्वारा आपूर्ति की गई घड़ियों के बारे में भी सच है)।

फ्लोटिंग पॉइंट क्लॉक के संदर्भ में एक अवधि प्राप्त करने के लिए, एक केवल दो समय बिंदुओं को घटाता है, और प्रति पुनरावृत्ति मान प्राप्त करने के लिए, उस अवधि को पुनरावृत्तियों की संख्या से विभाजित करें।

आप count()सदस्य फ़ंक्शन का उपयोग करके किसी भी अवधि में गणना प्राप्त कर सकते हैं । यह आंतरिक प्रतिनिधित्व लौटाता है। अंत में मैं std::chrono::duration_castअवधि Cycleको अवधि में परिवर्तित करने picosecondsऔर इसे प्रिंट करने के लिए उपयोग करता हूं ।

इस कोड का उपयोग करने के लिए सरल है:

int main()
{
    std::cout << "\nUsing rdtsc:\n";
    test_empty_loop<x::clock>();

    std::cout << "\nUsing std::chrono::high_resolution_clock:\n";
    test_empty_loop<std::chrono::high_resolution_clock>();

    std::cout << "\nUsing std::chrono::system_clock:\n";
    test_empty_loop<std::chrono::system_clock>();
}

ऊपर मैं अपने घर-निर्मित का उपयोग करके परीक्षण का अभ्यास करता हूं x::clock, और उन परिणामों की तुलना सिस्टम-आपूर्ति वाली घड़ियों में से दो का उपयोग करके करता हूं : std::chrono::high_resolution_clockऔर std::chrono::system_clock। मेरे लिए यह प्रिंट आउट:

Using rdtsc:
1.72632 clock ticks per iteration
616ps per iteration

Using std::chrono::high_resolution_clock:
0.620105 clock ticks per iteration
620ps per iteration

Using std::chrono::system_clock:
0.00062457 clock ticks per iteration
624ps per iteration

इससे पता चलता है कि इन घड़ियों में से प्रत्येक की एक अलग टिक अवधि होती है, क्योंकि प्रति प्रवाह की टिक प्रत्येक घड़ी के लिए अलग-अलग होती है। हालांकि, जब समय की एक ज्ञात इकाई में परिवर्तित हो जाता है (उदाहरण के लिए पिकोसेकंड), मुझे प्रत्येक घड़ी के लिए लगभग समान परिणाम मिलता है (आपका माइलेज भिन्न हो सकता है)।

ध्यान दें कि मेरा कोड "जादू रूपांतरण स्थिरांक" से पूरी तरह मुक्त कैसे है। वास्तव में, पूरे उदाहरण में केवल दो मैजिक नंबर हैं:

  1. परिभाषित करने के लिए मेरी मशीन की घड़ी की गति x::clock
  2. परीक्षण करने के लिए पुनरावृत्तियों की संख्या। यदि इस संख्या को बदलने से आपके परिणाम बहुत भिन्न हो जाते हैं, तो आपको संभवतः पुनरावृत्तियों की संख्या को अधिक करना चाहिए, या परीक्षण के दौरान प्रतिस्पर्धात्मक प्रक्रियाओं के अपने कंप्यूटर को खाली करना चाहिए।

5
"आरडीसीटीएस इंटेल-ओनली" द्वारा, आप वास्तव में x86 आर्किटेक्चर और डेरिवेटिव की बात कर रहे हैं, क्या आप नहीं हैं? AMD, Cyrix, Transmeta x86 चिप्स में निर्देश हैं , और Intel RISC और ARM प्रोसेसर नहीं हैं।
बेन वोइग्ट

1
@BenVoigt: +1 हां, आपका सुधार काफी सही है, धन्यवाद।
हावर्ड हिनान्ट

1
CPU थ्रॉटलिंग इसे कैसे प्रभावित करेगा? सीपीयू लोड के आधार पर घड़ी की गति में परिवर्तन नहीं होता है?
तेजस काले

@TejasKale: यह "दो बार एक घड़ी बनाने के लिए ..." से शुरू होने वाले दो लगातार पैराग्राफ में जवाब में वर्णित है। आमतौर पर टाइमिंग कोड काम को मापता नहीं है जो एक थ्रेड को ब्लॉक करता है (लेकिन यह हो सकता है)। और इसलिए आमतौर पर आपका CPU थ्रॉटल नहीं करेगा। लेकिन अगर आप नींद, म्यूटेक्स लॉक, कंडिशन_वेटेबल वेट आदि से जुड़े कोड को माप रहे हैं, तो rdtscघड़ी में अन्य यूनिट के लिए गलत रूपांतरण होने की संभावना है। अपने माप को सेट करना एक अच्छा विचार है ताकि आप घड़ियों को आसानी से बदल सकें और तुलना कर सकें (जैसा कि इस उत्तर में दिखाया गया है)।
हावर्ड हिनांट

27

सटीकता के उस स्तर के साथ, सीपीयू टिक में कारण के बजाय घड़ी () की तरह कॉल करना बेहतर होगा । और यह मत भूलो कि अगर एक निर्देश को निष्पादित करने के लिए एक से अधिक नैनोसेकंड लगते हैं ... एक नैनोसेकंड सटीकता होना बहुत असंभव है।

फिर भी, कुछ ऐसा है जो एक शुरुआत है:

सीपीयू अंतिम बार चालू होने के बाद से 80x86 सीपीयू क्लॉक टिक्स की संख्या प्राप्त करने के लिए यहां वास्तविक कोड है। यह पेंटियम और ऊपर (386/486 समर्थित नहीं) पर काम करेगा। यह कोड वास्तव में MS Visual C ++ विशिष्ट है, लेकिन जब तक यह इनलाइन असेंबली का समर्थन करता है, तब तक शायद इसे और भी बहुत आसान तरीके से चित्रित किया जा सकता है।

inline __int64 GetCpuClocks()
{

    // Counter
    struct { int32 low, high; } counter;

    // Use RDTSC instruction to get clocks count
    __asm push EAX
    __asm push EDX
    __asm __emit 0fh __asm __emit 031h // RDTSC
    __asm mov counter.low, EAX
    __asm mov counter.high, EDX
    __asm pop EDX
    __asm pop EAX

    // Return result
    return *(__int64 *)(&counter);

}

इस फ़ंक्शन का अत्यंत तेज़ होने का लाभ भी है - यह आमतौर पर निष्पादित करने के लिए 50 से अधिक cpu चक्र नहीं लेता है।

टाइमिंग फिगर्स का उपयोग करना :
यदि आपको घड़ी के काउंट्स को सही बीते हुए समय में अनुवाद करना है, तो परिणाम को अपनी चिप की क्लॉक स्पीड से विभाजित करें। याद रखें कि "रेटेड" GHz आपके चिप की वास्तविक गति से थोड़ा अलग होने की संभावना है। अपने चिप की सही गति की जांच करने के लिए, आप कई बहुत अच्छी उपयोगिताओं या Win32 कॉल, QueryPerformanceFrequency () का उपयोग कर सकते हैं।


जानकारी के लिए धन्यवाद, यह उपयोगी है। मैंने समय की गणना करने के लिए सीपीयू चक्रों के बारे में नहीं सोचा था, मुझे लगता है कि ध्यान में रखने के लिए एक बहुत अच्छा बिंदु है :-)
gagneet

4
TSC मायने रखता है QueryPerformanceFrequency () का उपयोग कर बीमित समय में काम करने के लिए मायने नहीं रखता है। उपलब्ध होने पर QueryPerformanceCounter () एचपीईटी (हाई प्रिसिजन इवेंट टाइमर) का उपयोग करता है। उपयोगकर्ता ACPI पावर प्रबंधन टाइमर का उपयोग करता है यदि उपयोगकर्ता boot.ini में / USEPMTIMER जोड़ता है।
bk1e

23

इसे सही ढंग से करने के लिए आप दो तरीकों में से एक का उपयोग कर सकते हैं, या तो साथ RDTSCया साथ जाएं clock_gettime()। दूसरा लगभग 2 गुना तेज है और सही निरपेक्ष समय देने का फायदा है। ध्यान दें कि RDTSCसही ढंग से काम करने के लिए आपको इसे संकेत के रूप में उपयोग करने की आवश्यकता है (इस पृष्ठ पर अन्य टिप्पणियों में त्रुटियां हैं, और कुछ प्रोसेसर पर गलत समय मान प्राप्त कर सकते हैं)

inline uint64_t rdtsc()
{
    uint32_t lo, hi;
    __asm__ __volatile__ (
      "xorl %%eax, %%eax\n"
      "cpuid\n"
      "rdtsc\n"
      : "=a" (lo), "=d" (hi)
      :
      : "%ebx", "%ecx" );
    return (uint64_t)hi << 32 | lo;
}

और घड़ी के समय के लिए: (मैंने मनमाने ढंग से माइक्रोसेकंड संकल्प चुना)

#include <time.h>
#include <sys/timeb.h>
// needs -lrt (real-time lib)
// 1970-01-01 epoch UTC time, 1 mcs resolution (divide by 1M to get time_t)
uint64_t ClockGetTime()
{
    timespec ts;
    clock_gettime(CLOCK_REALTIME, &ts);
    return (uint64_t)ts.tv_sec * 1000000LL + (uint64_t)ts.tv_nsec / 1000LL;
}

समय और मूल्यों का उत्पादन:

Absolute values:
rdtsc           = 4571567254267600
clock_gettime   = 1278605535506855

Processing time: (10000000 runs)
rdtsc           = 2292547353
clock_gettime   = 1031119636

22

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

#include <time.h>
#include <iostream>
using namespace std;

int main (int argc, char** argv)
{
    // reset the clock
    timespec tS;
    tS.tv_sec = 0;
    tS.tv_nsec = 0;
    clock_settime(CLOCK_PROCESS_CPUTIME_ID, &tS);
    ...
    ... <code to check for the time to be put here>
    ...
    clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tS);
    cout << "Time taken is: " << tS.tv_sec << " " << tS.tv_nsec << endl;

    return 0;
}

2
मैंने डाउनवोट किया क्योंकि इस कोड को लागू करने की कोशिश में मुझे पहले गूगल करना था कि टाइमस्पेस को परिभाषित क्यों नहीं किया गया है। तब मुझे whats POSIX को google करना पड़ा ... और जैसा कि मैंने इसे समझा, यह कोड उन विंडोज उपयोगकर्ताओं के लिए प्रासंगिक नहीं है, जो मानक पुस्तकालय के साथ चिपके रहते हैं।
डैनियल काट्ज़

8

के लिए सी ++ 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_;
};

या सी + 03 के लिए * निक्स पर,

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


5

सामान्य तौर पर, किसी फ़ंक्शन को कॉल करने में कितना समय लगता है, आप इसे केवल एक बार की तुलना में कई गुना अधिक करना चाहते हैं। यदि आप केवल एक बार अपने फ़ंक्शन को कॉल करते हैं और इसे चलाने के लिए बहुत कम समय लगता है, तो आपके पास वास्तव में टाइमर फ़ंक्शन को कॉल करने का ओवरहेड है और आपको नहीं पता कि कितना समय लगता है।

उदाहरण के लिए, यदि आप अनुमान लगाते हैं कि आपके फ़ंक्शन को चलाने के लिए 800 ns लग सकते हैं, तो इसे दस मिलियन बार (जो तब लगभग 20 सेकंड का समय लगेगा) में कॉल करें। प्रति कॉल का समय पाने के लिए कुल समय को दस मिलियन से विभाजित करें।


वास्तविक रूप से, मैं एक विशेष कॉल के लिए एपीआई के प्रदर्शन को प्राप्त करने की कोशिश कर रहा हूं। प्रत्येक रन के लिए, यह एक अलग समय दे सकता है, यह प्रदर्शन सुधार के लिए मेरे द्वारा किए गए ग्राफ को प्रभावित कर सकता है ... इसलिए नैनो सेकंड में समय। लेकिन हाँ, यह एक महान विचार है, इस पर विचार करेंगे।
gagneet

5

आप x86 प्रोसेसर के तहत gcc के साथ निम्न फ़ंक्शन का उपयोग कर सकते हैं:

unsigned long long rdtsc()
{
  #define rdtsc(low, high) \
         __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high))

  unsigned int low, high;
  rdtsc(low, high);
  return ((ulonglong)high << 32) | low;
}

डिजिटल मंगल C ++ के साथ:

unsigned long long rdtsc()
{
   _asm
   {
        rdtsc
   }
}

जो चिप पर उच्च प्रदर्शन टाइमर पढ़ता है। मैं प्रोफाइलिंग करते समय इसका उपयोग करता हूं।


2
यह उपयोगी है, मैं जाँच करूँगा कि क्या प्रोसेसर x86 है, जैसा कि मैं प्रयोग के लिए एक ऐप्पल मैक का उपयोग कर रहा हूँ ... धन्यवाद :-)
gagneet

1
उच्च और निम्न के लिए उपयोगकर्ता को क्या मान देना चाहिए? आप किसी फ़ंक्शन के शरीर के अंदर मैक्रो को क्यों परिभाषित करते हैं? इसके अलावा, ulonglong, संभवतः लंबे समय तक अहस्ताक्षरित typedef'd, एक मानक प्रकार नहीं है। मैं इसका उपयोग करना चाहता हूं लेकिन मुझे यकीन नहीं है कि कैसे?)
जोसेफ गार्विन

1
अहस्ताक्षरित लंबे समय तक लिनक्स के तहत उपयोग करने के लिए सही बात नहीं है। आप इसके बजाय इंट का उपयोग करने पर विचार करना चाह सकते हैं क्योंकि लंबे और लंबे दोनों 64-बिट लिनक्स पर 64-बिट हैं।
Marius

3
टीएससी काउंटर आजकल अविश्वसनीय है: यह आवृत्ति बदलने पर कई प्रोसेसर पर अपनी गति बदलता है, और विभिन्न कोर में असंगत है, इसलिए टीएससी हमेशा नहीं बढ़ता है।
१०:३०

1
@ मार्स: मैंने unsigned intआंतरिक प्रकार का उपयोग करते हुए, आपकी टिप्पणी को लागू किया ।
ब्‍लॉसरब्‍लेड

3

यदि आपको उप-सीस परिशुद्धता की आवश्यकता है, तो आपको सिस्टम-विशिष्ट एक्सटेंशन का उपयोग करने की आवश्यकता है, और ऑपरेटिंग सिस्टम के लिए प्रलेखन के साथ जांचना होगा। POSIX gettimeofday के साथ माइक्रोसेकंड तक का समर्थन करता है , लेकिन कुछ भी अधिक सटीक नहीं है क्योंकि कंप्यूटर में 1GHz से अधिक आवृत्तियों नहीं है।

यदि आप बूस्ट का उपयोग कर रहे हैं, तो आप बढ़ावा देख सकते हैं :: posix_time


कोड को पोर्टेबल रखना चाहते हैं, बूस्ट लाइब्रेरी देखेंगे और जांचें कि क्या मैं इसे कोड के साथ बंडल कर सकता हूं। धन्यवाद :-)
gagneet

3

मैं यहाँ Borland कोड का उपयोग कर रहा हूँ, कोड ti_hund है जो मुझे कुछ समय के लिए निगेटीबार्न देता है लेकिन समय काफी अच्छा है।

#include <dos.h>

void main() 
{
struct  time t;
int Hour,Min,Sec,Hun;
gettime(&t);
Hour=t.ti_hour;
Min=t.ti_min;
Sec=t.ti_sec;
Hun=t.ti_hund;
printf("Start time is: %2d:%02d:%02d.%02d\n",
   t.ti_hour, t.ti_min, t.ti_sec, t.ti_hund);
....
your code to time
...

// read the time here remove Hours and min if the time is in sec

gettime(&t);
printf("\nTid Hour:%d Min:%d Sec:%d  Hundreds:%d\n",t.ti_hour-Hour,
                             t.ti_min-Min,t.ti_sec-Sec,t.ti_hund-Hun);
printf("\n\nAlt Ferdig Press a Key\n\n");
getch();
} // end main

3

एक साधारण वर्ग के साथ, ब्रॉक एडम्स की विधि का उपयोग करना:

int get_cpu_ticks()
{
    LARGE_INTEGER ticks;
    QueryPerformanceFrequency(&ticks);
    return ticks.LowPart;
}

__int64 get_cpu_clocks()
{
    struct { int32 low, high; } counter;

    __asm cpuid
    __asm push EDX
    __asm rdtsc
    __asm mov counter.low, EAX
    __asm mov counter.high, EDX
    __asm pop EDX
    __asm pop EAX

    return *(__int64 *)(&counter);
}

class cbench
{
public:
    cbench(const char *desc_in) 
         : desc(strdup(desc_in)), start(get_cpu_clocks()) { }
    ~cbench()
    {
        printf("%s took: %.4f ms\n", desc, (float)(get_cpu_clocks()-start)/get_cpu_ticks());
        if(desc) free(desc);
    }
private:
    char *desc;
    __int64 start;
};

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

int main()
{
    {
        cbench c("test");
        ... code ...
    }
    return 0;
}

परिणाम:

परीक्षा ली गई: 0.0002 मि

कुछ समारोह कॉल उपरि है, लेकिन अभी भी तेजी से पर्याप्त से अधिक होना चाहिए :)


3

आप एंबेडेड प्रोफाइलर (विंडोज और लिनक्स के लिए मुफ्त) का उपयोग कर सकते हैं, जिसमें एक मल्टीप्लायर टाइमर (एक प्रोसेसर चक्र गणना में) के लिए एक इंटरफ़ेस है और आपको प्रति सेकंड कई चक्र दे सकते हैं:

EProfilerTimer timer;
timer.Start();

... // Your code here

const uint64_t number_of_elapsed_cycles = timer.Stop();
const uint64_t nano_seconds_elapsed =
    mumber_of_elapsed_cycles / (double) timer.GetCyclesPerSecond() * 1000000000;

समय-समय पर चक्र गणना की पुनर्गणना संभवतः आधुनिक प्रोसेसर के साथ एक खतरनाक ऑपरेशन है जहां सीपीयू आवृत्ति को गतिशील रूप से बदला जा सकता है। इसलिए यह सुनिश्चित करने के लिए कि परिवर्तित समय सही है, प्रोफाइलिंग से पहले प्रोसेसर की आवृत्ति को ठीक करना आवश्यक है।


2

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


clock_gettime () अब के लिए चाल करना चाहिए। मेरे उद्देश्य के लिए उसी का उपयोग करने की कोशिश करेंगे ...
gagneet

2

तुम उसके बारे में क्या सोचते हो:

    int iceu_system_GetTimeNow(long long int *res)
    {
      static struct timespec buffer;
      // 
    #ifdef __CYGWIN__
      if (clock_gettime(CLOCK_REALTIME, &buffer))
        return 1;
    #else
      if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &buffer))
        return 1;
    #endif
      *res=(long long int)buffer.tv_sec * 1000000000LL + (long long int)buffer.tv_nsec;
      return 0;
    }

2

यहाँ एक अच्छा बूस्ट टाइमर है जो अच्छी तरह से काम करता है:

//Stopwatch.hpp

#ifndef STOPWATCH_HPP
#define STOPWATCH_HPP

//Boost
#include <boost/chrono.hpp>
//Std
#include <cstdint>

class Stopwatch
{
public:
    Stopwatch();
    virtual         ~Stopwatch();
    void            Restart();
    std::uint64_t   Get_elapsed_ns();
    std::uint64_t   Get_elapsed_us();
    std::uint64_t   Get_elapsed_ms();
    std::uint64_t   Get_elapsed_s();
private:
    boost::chrono::high_resolution_clock::time_point _start_time;
};

#endif // STOPWATCH_HPP


//Stopwatch.cpp

#include "Stopwatch.hpp"

Stopwatch::Stopwatch():
    _start_time(boost::chrono::high_resolution_clock::now()) {}

Stopwatch::~Stopwatch() {}

void Stopwatch::Restart()
{
    _start_time = boost::chrono::high_resolution_clock::now();
}

std::uint64_t Stopwatch::Get_elapsed_ns()
{
    boost::chrono::nanoseconds nano_s = boost::chrono::duration_cast<boost::chrono::nanoseconds>(boost::chrono::high_resolution_clock::now() - _start_time);
    return static_cast<std::uint64_t>(nano_s.count());
}

std::uint64_t Stopwatch::Get_elapsed_us()
{
    boost::chrono::microseconds micro_s = boost::chrono::duration_cast<boost::chrono::microseconds>(boost::chrono::high_resolution_clock::now() - _start_time);
    return static_cast<std::uint64_t>(micro_s.count());
}

std::uint64_t Stopwatch::Get_elapsed_ms()
{
    boost::chrono::milliseconds milli_s = boost::chrono::duration_cast<boost::chrono::milliseconds>(boost::chrono::high_resolution_clock::now() - _start_time);
    return static_cast<std::uint64_t>(milli_s.count());
}

std::uint64_t Stopwatch::Get_elapsed_s()
{
    boost::chrono::seconds sec = boost::chrono::duration_cast<boost::chrono::seconds>(boost::chrono::high_resolution_clock::now() - _start_time);
    return static_cast<std::uint64_t>(sec.count());
}

2

न्यूनतम कॉपी और पेस्ट-स्ट्रक्चर + आलसी उपयोग

यदि विचार में एक न्यूनतर संरचना है जिसे आप त्वरित परीक्षणों के लिए उपयोग कर सकते हैं, तो मैं आपको सुझाव देता हूं कि आप अपनी सी ++ फ़ाइल में कहीं भी कॉपी और पेस्ट करें #include। यह एकमात्र उदाहरण है जिसमें मैं ऑलमैन-शैली प्रारूपण का त्याग करता हूं।

आप संरचना की पहली पंक्ति में परिशुद्धता को आसानी से समायोजित कर सकते हैं। संभावित मान हैं: nanoseconds, microseconds, milliseconds, seconds, minutes, या hours

#include <chrono>
struct MeasureTime
{
    using precision = std::chrono::microseconds;
    std::vector<std::chrono::steady_clock::time_point> times;
    std::chrono::steady_clock::time_point oneLast;
    void p() {
        std::cout << "Mark " 
                << times.size()/2
                << ": " 
                << std::chrono::duration_cast<precision>(times.back() - oneLast).count() 
                << std::endl;
    }
    void m() {
        oneLast = times.back();
        times.push_back(std::chrono::steady_clock::now());
    }
    void t() {
        m();
        p();
        m();
    }
    MeasureTime() {
        times.push_back(std::chrono::steady_clock::now());
    }
};

प्रयोग

MeasureTime m; // first time is already in memory
doFnc1();
m.t(); // Mark 1: next time, and print difference with previous mark
doFnc2();
m.t(); // Mark 2: next time, and print difference with previous mark
doStuff = doMoreStuff();
andDoItAgain = doStuff.aoeuaoeu();
m.t(); // prints 'Mark 3: 123123' etc...

मानक आउटपुट परिणाम

Mark 1: 123
Mark 2: 32
Mark 3: 433234

यदि आप निष्पादन के बाद सारांश चाहते हैं

यदि आप बाद में रिपोर्ट चाहते हैं, क्योंकि उदाहरण के लिए बीच में आपका कोड भी मानक आउटपुट को लिखता है। फिर निम्न फ़ंक्शन को संरचना में जोड़ें (मेजरमेट के ठीक पहले ()):

void s() { // summary
    int i = 0;
    std::chrono::steady_clock::time_point tprev;
    for(auto tcur : times)
    {
        if(i > 0)
        {
            std::cout << "Mark " << i << ": "
                    << std::chrono::duration_cast<precision>(tprev - tcur).count()
                    << std::endl;
        }
        tprev = tcur;
        ++i;
    }
}

तो आप अभी उपयोग कर सकते हैं:

MeasureTime m;
doFnc1();
m.m();
doFnc2();
m.m();
doStuff = doMoreStuff();
andDoItAgain = doStuff.aoeuaoeu();
m.m();
m.s();

जो पहले की तरह ही सभी चिह्नों को सूचीबद्ध करेगा, लेकिन फिर दूसरे कोड के निष्पादित होने के बाद। ध्यान दें कि आपको m.s()और दोनों का उपयोग नहीं करना चाहिए m.t()


Ubuntu 16.04 पर OpenMP के साथ पूरी तरह से काम करता है। बहुत बहुत धन्यवाद, यह सबसे अच्छा जवाब चाहिए IMO!
56hor Mé
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.