2010-07-02 16 views
8

सी/सी ++ प्रोग्रामर का सबसे तेज़ समय सिस्टम क्या उपयोग कर सकता है?सबसे तेज़ समय संकल्प प्रणाली

उदाहरण के लिए:
समय() 01 जनवरी 1 9 00 00:00 के बाद से सेकंड देगा।
विंडोज पर GetTickCount() सिस्टम के स्टार्ट-अप समय के बाद, मिलीसेकंड में समय देगा, लेकिन यह 49.7 दिनों तक सीमित है (उसके बाद यह केवल शून्य पर वापस आ जाता है)।

मैं मिलीसेकंड में सिस्टम/ऐप स्टार्ट-अप समय के बाद वर्तमान समय, या टिक प्राप्त करना चाहता हूं।

सबसे बड़ी चिंता विधि का ओवरहेड है - मुझे सबसे हल्का चाहिए, क्योंकि मैं इसे प्रति सेकंड कई बार कॉल करने वाला हूं।

मेरा मामला यह है कि मेरे पास एक कार्यकर्ता धागा है, और उस कार्यकर्ता धागे में मैंने लंबित नौकरियां पोस्ट की हैं। प्रत्येक नौकरी में "निष्पादन समय" होता है। इसलिए, मुझे कोई परवाह नहीं है कि समय वर्तमान "वास्तविक" समय है या सिस्टम के अपटाइम के बाद का समय - यह केवल रैखिक और हल्का होना चाहिए।

संपादित करें:

unsigned __int64 GetTickCountEx() 
{ 
    static DWORD dwWraps = 0; 
    static DWORD dwLast = 0; 

    DWORD dwCurrent = 0; 

    timeMutex.lock(); 

    dwCurrent = GetTickCount(); 
    if(dwLast > dwCurrent) 
     dwWraps++; 

    dwLast = dwCurrent; 

    unsigned __int64 timeResult = ((unsigned __int64)0xFFFFFFFF * dwWraps) + dwCurrent; 

    timeMutex.unlock(); 

    return timeResult; 
} 
+0

क्या आप इसे अपटाइम> 49.7 दिनों के साथ सिस्टम पर चलाने की उम्मीद करते हैं? –

+0

हां। निश्चित रूप से अधिक। – Poni

+0

क्या आप विशेष रूप से विंडोज के बारे में पूछ रहे हैं? पॉज़िक्स प्लेटफार्मों में 'gettimeofday() 'है, जो माइक्रोसॉन्ड परिशुद्धता के साथ कई दशकों को कवर कर सकता है। –

उत्तर

15

समय के लिए, current Microsoft recommendationQueryPerformanceCounter & QueryPerformanceFrequency उपयोग करने के लिए है।

यह आपको मिलीसेकंड समय से बेहतर प्रदान करेगा। यदि सिस्टम उच्च-रिज़ॉल्यूशन टाइमर का समर्थन नहीं करता है, तो यह मिलीसेकंड (डिफ़ॉल्ट रूप से GetTickCount) के लिए डिफ़ॉल्ट होगा।

Here is a short Microsoft article with examples of why you should use it :)

+0

पहले लिंक पर, क्लॉज # 1 पर, यह कहता है: "डेवलपर्स को किसी भी प्रदर्शन दंड से बचने के लिए जितना संभव हो उतना कम से कम अपने गेम कॉल QueryPerformanceCounter को कॉल करने का प्रयास करना चाहिए"। तो, क्या मुझे निष्कर्ष निकालना चाहिए कि मैं बेहतर आरडीटीएससी का उपयोग करता हूं? यह एक बहुत ही मंच-निर्भर कॉल की तरह लगता है। – Poni

+0

ठीक है, थोड़ा और पढ़ें और आरडीटीएससी choise नहीं है। – Poni

+0

इसके अतिरिक्त, एमएसडीएन ने QueryPerformanceCounter को कई बार कॉल न करने की सिफारिश की है। तो, क्या मैं GetTickCount के साथ छोड़ दिया गया हूँ? – Poni

0

लिनक्स पर आप मिल माइक्रोसेकंड:

struct timeval tv; 
int res = gettimeofday(&tv, NULL); 
double tmp = (double) tv.tv_sec + 1e-6 * (double) tv.tv_usec; 

Windows पर, केवल millseconds उपलब्ध हैं:

SYSTEMTIME st; 
GetSystemTime(&st); 
tmp += 1e-3 * st.wMilliseconds; 

return tmp; 

यह R के datetime.c से आया है (और ब्रेवटी के लिए संपादित किया गया था)।

तो निश्चित रूप से Boost's Date_Time है जिसमें कुछ सिस्टमों पर नैनोसेकंद रिज़ॉल्यूशन हो सकता है (विवरण here और here)।

3

तुम सिर्फ GetTickCount() उमड़ती बारे में चिंतित हैं, तो आप बस इसे इस तरह लपेट कर सकते हैं:

DWORDLONG GetLongTickCount(void) 
{ 
    static DWORDLONG last_tick = 0; 
    DWORD tick = GetTickCount(); 

    if (tick < (last_tick & 0xffffffff)) 
     last_tick += 0x100000000; 

    last_tick = (last_tick & 0xffffffff00000000) | tick; 
    return last_tick; 
} 

आप एक से अधिक थ्रेड से कॉल करने के लिए चाहते हैं तो आप last_tick चर के लिए उपयोग लॉक करने के लिए की आवश्यकता होगी । जब तक आप प्रत्येक 49.7 दिनों में कम से कम एक बार GetLongTickCount() पर कॉल करते हैं, तो यह ओवरफ़्लो का पता लगाएगा।

0

POSIX clock_gettime() का समर्थन करता है जो struct timespec का उपयोग करता है जिसमें नैनोसेकंद संकल्प होता है। चाहे आपका सिस्टम वास्तव में समर्थन करता है कि एक सुदृढ़ एक संकल्प अधिक बहस योग्य है, लेकिन मेरा मानना ​​है कि उच्चतम रिज़ॉल्यूशन वाला मानक कॉल है। सभी सिस्टम इसका समर्थन नहीं करते हैं, और यह कभी-कभी अच्छी तरह छुपाया जाता है (लाइब्रेरी '-lposix4' सोलारिस, आईआईआरसी पर)।


अद्यतन (2016/09/20):

  • मैक ओएस एक्स 10.6.4 clock_gettime() का समर्थन नहीं किया है, और न ही न किया और मैक सहित मैक ओएस एक्स के किसी भी अन्य संस्करण ओएस एक्स 10.11.6 एल कैपिटन), मैकोज़ सिएरा 10.12 में फंक्शन clock_gettime() और इसके लिए मैन्युअल पेज लंबे समय तक हैं। वास्तविक संकल्प (CLOCK_MONOTONIC पर) अभी भी माइक्रोसेकंड है; छोटी इकाइयां सभी शून्य हैं। यह clock_getres() द्वारा पुष्टि की गई है जो रिपोर्ट करता है कि संकल्प 1000 नैनोसेकंड, उर्फ ​​1 μs है।

MacOS सिएरा पर clock_gettime() के लिए मैन्युअल पृष्ठ एक तरह से उच्च संकल्प समय प्राप्त करने के लिए के रूप में mach_absolute_time() का उल्लेख है। अधिक जानकारी के लिए, अन्य स्थानों के साथ, Technical Q&A QA1398: Mach Absolute Time Units और (एसओ पर) What is mach_absolute_time() based on on iPhone?

5

मुझे हाल ही में यह प्रश्न था और कुछ शोध किया। अच्छी खबर यह है कि सभी तीन प्रमुख ऑपरेटिंग सिस्टम कुछ प्रकार के उच्च रिज़ॉल्यूशन टाइमर प्रदान करते हैं। बुरी खबर यह है कि यह प्रत्येक सिस्टम पर एक अलग एपीआई कॉल है। POSIX ऑपरेटिंग सिस्टम के लिए आप clock_gettime() का उपयोग करना चाहते हैं। यदि आप मैक ओएस एक्स पर हैं, हालांकि, यह समर्थित नहीं है, तो आपको mach_get_time() का उपयोग करना होगा। विंडोज़ के लिए, QueryPerformanceCounter का उपयोग करें। वैकल्पिक रूप से, ओपनएमपी का समर्थन करने वाले कंपाइलर्स के साथ, आप omp_get_wtime() का उपयोग कर सकते हैं, लेकिन यह उस संकल्प को प्रदान नहीं कर सकता है जिसे आप ढूंढ रहे हैं।

मुझे उपयोगी होने के लिए fftw.org (www.fftw.org/cycle.h) से cycle.h भी मिला।

यहां कुछ कोड है जो प्रत्येक ओएस पर टाइमर को कॉल करते हैं, कुछ बदसूरत #ifdef स्टेटमेंट का उपयोग करते हुए। उपयोग बहुत आसान है: टाइमर टी; t.tic(); SomeOperation(); t.toc ("संदेश"); और यह सेकंड में बीत चुके समय को प्रिंट करेगा।

#ifndef TIMER_H 
#define TIMER_H 

#include <iostream> 
#include <string> 
#include <vector> 

# if (defined(__MACH__) && defined(__APPLE__)) 
# define _MAC 
# elif (defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(_WIN64)) 
# define _WINDOWS 
# ifndef WIN32_LEAN_AND_MEAN 
#  define WIN32_LEAN_AND_MEAN 
# endif 
#endif 

# if defined(_MAC) 
# include <mach/mach_time.h> 
# elif defined(_WINDOWS) 
# include <windows.h> 
# else 
# include <time.h> 
# endif 


#if defined(_MAC) 
    typedef uint64_t timer_t; 
    typedef double timer_c; 

#elif defined(_WINDOWS) 
    typedef LONGLONG  timer_t; 
    typedef LARGE_INTEGER timer_c; 

#else 
    typedef double timer_t; 
    typedef timespec timer_c; 
#endif 

    //============================================================================== 
    // Timer 
    // A quick class to do benchmarking. 
    // Example: Timer t; t.tic(); SomeSlowOp(); t.toc("Some Message"); 

    class Timer { 
    public: 
    Timer(); 

    inline void tic(); 
    inline void toc(); 
    inline void toc(const std::string &msg); 

    void print(const std::string &msg); 
    void print(); 
    void reset(); 
    double getTime(); 

    private: 
    timer_t start; 
    double duration; 
    timer_c ts; 
    double conv_factor; 
    double elapsed_time; 
    }; 



    Timer::Timer() { 

#if defined(_MAC) 
    mach_timebase_info_data_t info; 
    mach_timebase_info(&info); 

    conv_factor = (static_cast<double>(info.numer))/ 
        (static_cast<double>(info.denom)); 
    conv_factor = conv_factor*1.0e-9; 

#elif defined(_WINDOWS) 
    timer_c freq; 
    QueryPerformanceFrequency(&freq); 
    conv_factor = 1.0/(static_cast<double>freq.QuadPart); 

#else 
    conv_factor = 1.0; 
#endif 

    reset(); 
    } 

    inline void Timer::tic() { 

#if defined(_MAC) 
    start = mach_absolute_time(); 

#elif defined(_WINDOWS) 
    QueryPerformanceCounter(&ts); 
    start = ts.QuadPart; 

#else 
    clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts); 
    start = static_cast<double>(ts.tv_sec) + 1.0e-9 * 
      static_cast<double>(ts.tv_nsec); 

#endif 
    } 

    inline void Timer::toc() { 
#if defined(_MAC) 
    duration = static_cast<double>(mach_absolute_time() - start); 

#elif defined(_WINDOWS) 
    QueryPerformanceCounter(&qpc_t); 
    duration = static_cast<double>(qpc_t.QuadPart - start); 

#else 
    clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts); 
    duration = (static_cast<double>(ts.tv_sec) + 1.0e-9 * 
       static_cast<double>(ts.tv_nsec)) - start; 

#endif 

    elapsed_time = duration*conv_factor; 
    } 

    inline void Timer::toc(const std::string &msg) { toc(); print(msg); }; 

    void Timer::print(const std::string &msg) { 
    std::cout << msg << " "; print(); 
    } 

    void Timer::print() { 
    if(elapsed_time) { 
     std::cout << "elapsed time: " << elapsed_time << " seconds\n"; 
    } 
    } 

    void Timer::reset() { start = 0; duration = 0; elapsed_time = 0; } 
    double Timer::getTime() { return elapsed_time; } 


#if defined(_WINDOWS) 
# undef WIN32_LEAN_AND_MEAN 
#endif 

#endif // TIMER_H 
+0

अच्छा, बहुत उपयोगी परीक्षण के लिए! एक परियोजना में इसका उपयोग करने के लिए - मैं क्यूपीसी से बचने की कोशिश कर रहा हूं क्योंकि यह 100% विश्वसनीय नहीं है, जैसा कि कुछ ने यहां कहा है। – Poni

+0

मुझे mach_absolute_time के बारे में अधिक जानकारी मिलती है, जिसे mach/mach_time.h में घोषित किया गया है, यह तकनीकी http देखें : //developer.apple.com/library/mac/#q एक/qa1398/_index.html –

1

मेरा सुझाव था कि आप अगर आप विशेष रूप विंडोज को लक्षित कर रहे GetSystemTimeAsFileTime एपीआई का उपयोग करें। यह आमतौर पर GetSystemTime से तेज़ है और इसमें वही सटीकता है (जो कुछ 10-15 मिलीसेकंड है - संकल्प को न देखें); जब मैंने कुछ साल पहले विंडोज एक्सपी के तहत बेंचमार्क किया था तो यह कहीं 50-100 गुना तेजी से था।

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

QueryPerformanceCounter दूसरों के उल्लेख के अनुसार एक अच्छा विकल्प हो सकता है, लेकिन अंतर्निहित हार्डवेयर समर्थन के आधार पर ओवरहेड बड़ा हो सकता है। मेरे बेंचमार्क में मैंने ऊपर उल्लेख किया है QueryPerformanceCounter कॉल GetSystemTimeAsFileTime को कॉल से 25-200 गुना धीमा था। इसके अलावा, कुछ विश्वसनीयता समस्याएं हैं जैसे कि उदा। रिपोर्ट here

तो संक्षेप में: यदि आप 10-15 मिलीसेकंड की परिशुद्धता का सामना कर सकते हैं तो मैं आपको GetSystemTimeAsFileTime का उपयोग करने की सलाह दूंगा। अगर आपको इससे बेहतर कुछ चाहिए तो मैं क्वेरीरीफॉर्मेंस काउंटर के लिए जाऊंगा।

छोटे अस्वीकरण: मैंने XP SP3 की तुलना में बाद के विंडोज संस्करणों के तहत कोई बेंचमार्किंग नहीं की है। मैं आपको अपने आप पर कुछ बेंचमार्किंग करने की सलाह दूंगा।

+0

एक महान उत्तर के लिए धन्यवाद! पहला लिंक आपकी जानकारी के लिए एक और बहुत ही उपयोगी लिंक की ओर जाता है: विंडोज़ के लिए उच्च-रिज़ॉल्यूशन टाइम प्रदाता को कार्यान्वित करना http://msdn.microsoft.com/en-us/magazine/cc163996.aspx – Poni

0

यदि आप ओएस के देर से पर्याप्त संस्करण को लक्षित कर रहे हैं तो आप GetTickCount64() का उपयोग कर सकते हैं, जिसमें GetTickCount() से अधिक बिंदु के आसपास बहुत अधिक रैप है। आप GetTickCount() के शीर्ष पर GetTickCount64() का एक संस्करण भी बना सकते हैं।

+0

क्या उसने मुझे अभी तक मजबूर किया एक म्यूटेक्स के साथ कोड लपेटने के लिए, जो बिल्कुल सही नहीं लगता है। क्यूं कर? क्योंकि आखिरकार, मुझे लगता है, मैं दो म्यूटेक्स का उपयोग कर रहा हूं - एक रैपर और GetTickCount() में से एक। मेरा संपादन देखें। मुझे बताओ कि आप क्या सोचते हैं, धन्यवाद लेन !! – Poni

+0

मैं ऐसा नहीं करता। मेरे पास उपयुक्त समय पर उलझन के उच्च हिस्से को बढ़ाने के लिए टाइमर होगा, शायद लॉक के साथ इंटरलॉक किए गए वृद्धि का उपयोग करके, फिर इसे GetTickCountEx() पर कॉल में उपयोग करें। अभी आप 49.7 कम दिन के लिए अनावश्यक काम कर रहे हैं और इसका उपयोग करने वाले सभी थ्रेड सिंक्रनाइज़ कर रहे हैं (और यह एक आलोचक है और म्यूटेक्स नहीं है?) आप शायद लॉक से बच सकते हैं, या रीडर/लेखक लॉक का उपयोग कर सकते हैं और केवल लॉक कर सकते हैं जब आप उच्च भाग को अपडेट करने वाले हैं ... आप कोड का परीक्षण करने के लिए मेरे "टिक शिफ्ट" एपीआई इंटरसेप्शन टूल का उपयोग कर सकते हैं http://www.lenholgate.com/archives/000647.html –

+0

गुड पॉइंट लेन। मुझे लॉक से बचना होगा (और हाँ, यह एक महत्वपूर्ण खंड है)। टाइमर-टू-हाई हाई पार्ट एक अच्छा विचार है। – Poni

0

क्या आपने इस एमएसडीएन आलेख में कोड की समीक्षा की है?

http://msdn.microsoft.com/en-us/magazine/cc163996.aspx

मैं इस कोड दोनों VC2005 और सी ++ बिल्डर XE का उपयोग कर एक विंडोज 7 64 बिट मशीन पर संकलन है, लेकिन जब क्रियान्वित करने, यह मेरी मशीन को ताले; अभी तक क्यों पता लगाने के लिए पर्याप्त रूप से डीबग नहीं किया है। यह अत्यधिक जटिल लगता है। यूजी के टेम्पलेट्स के टेम्पलेट्स के टेम्पलेट्स ...

4

GetSystemTimeAsFileTime सबसे तेज़ संसाधन है। इसकी ग्रैन्युलरिटी को GetSystemTimeAdjustment पर कॉल करके प्राप्त की जा सकती है जो lpTimeIncrement भरती है। फ़ाइलटाइम के रूप में सिस्टम समय में 100ns इकाइयां हैं और टाइमइक्रिकमेंट द्वारा वृद्धि हुई है। टाइमइंक्चर भिन्न हो सकता है और यह मल्टीमीडिया टाइमर इंटरफ़ेस की सेटिंग पर निर्भर करता है।

timeGetDevCaps पर कॉल समय सेवाओं की क्षमताओं का खुलासा करेगा। यह न्यूनतम समर्थित इंटरप्ट अवधि के लिए एक मान wPeriodMin देता है। पर wPeriodMin के साथ एक कॉल के रूप में सिस्टम उच्चतम संभावित अंतराल आवृत्ति (आमतौर पर ~ 1ms) पर संचालित करने के लिए सिस्टम स्थापित करेगा। यह भी छोटे होने के लिए GetSystemTimeAsFileTime द्वारा लौटाए गए सिस्टम फ़ाइलटाइम की समय वृद्धि को मजबूर करेगा। इसकी ग्रैन्युलरिटी 1 एमएमएस (10000 100ns इकाइयों) की सीमा में होगी।

आपके उद्देश्य के लिए, मैं इस दृष्टिकोण के लिए जाने का सुझाव दूंगा।

QueryPerformanceCounter पसंद संदिग्ध है के बाद से इसकी आवृत्ति दो तरह से सही नहीं है: सबसे पहले यह एक हार्डवेयर ऑफसेट विशिष्ट द्वारा QueryPerformanceFrequency द्वारा दिए गए मूल्य से भटक। यह ऑफसेट आसानी से कई सौ पीपीएम हो सकता है, जिसका अर्थ है कि समय में रूपांतरण में प्रति सेकेंड कई सैकड़ों माइक्रोसॉन्ड की त्रुटि होगी। दूसरी बात यह थर्मल बहाव है। ऐसे उपकरणों की बहाव आसानी से कई पीपीएम हो सकती है। इस तरह दूसरा - गर्मी निर्भर - की त्रुटि कई us/s जोड़ दी गई है।

इसलिए जब तक ~ 1ms का संकल्प पर्याप्त होता है और मुख्य प्रश्न ओवरहेड होता है, GetSystemTimeAsFileTime अब तक का सबसे अच्छा समाधान है।

जब माइक्रोसेकंड मायने रखता है, तो आपको लंबा रास्ता तय करना होगा और अधिक जानकारी देखना होगा। उप-मिलीसेकंद समय सेवाओं का वर्णन Windows Timestamp Project

0

मैक ओएस एक्स पर, आप आसानी से टिक प्राप्त करने के लिए UInt32 टिककंट (शून्य) का उपयोग कर सकते हैं।

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