QueryPerformanceCounter का उपयोग कैसे करें?


97

मैंने हाल ही में फैसला किया है कि मुझे अपने टाइमर वर्ग के लिए मिलीसेकंड का उपयोग करने से लेकर माइक्रोसेकंड तक बदलने की आवश्यकता है, और कुछ शोध के बाद मैंने फैसला किया है कि क्वेरपेरफॉर्मेंसकाउंटर शायद मेरा सबसे सुरक्षित दांव है। (इस पर चेतावनी Boost::Posixकि यह Win32 एपीआई पर काम नहीं करता है मुझे थोड़ा दूर कर सकता है)। हालांकि, मुझे वास्तव में यकीन नहीं है कि इसे कैसे लागू किया जाए।

मैं जो कुछ भी कर रहा हूं उसे GetTicks()एस्क्यू फ़ंक्शन कह रहा हूं और इसे टाइमर के startingTicksचर में निर्दिष्ट कर रहा हूं । फिर समय की मात्रा का पता लगाने के लिए, मैं अभी से फ़ंक्शन के रिटर्न मान को घटाता हूं startingTicks, और जब मैं टाइमर रीसेट करता हूं तो मैं फ़ंक्शन को फिर से कॉल करता हूं और इसे शुरू करने के लिए असाइन करता हूं। दुर्भाग्य से, कोड से मैंने देखा है कि यह केवल कॉलिंग के रूप में सरल नहीं है QueryPerformanceCounter(), और मुझे यकीन नहीं है कि मुझे इसके तर्क के रूप में पारित करना चाहिए।


2
मैंने रामोनस्टर के कोड स्निपेट लिए हैं और उन्हें यहां एक लाइब्रेरी में बनाया है: अनुयायियों के लिए gist.github.com/1153062
रोजरपैक

3
हमने हाल ही में QueryPerformanceCounter के लिए दस्तावेज़ीकरण को अपडेट किया है, और अतिरिक्त जानकारी को उचित उपयोग, और FAQ के जवाब में जोड़ा है। आप यहाँ पर अपडेट किए गए दस्तावेज़ देख सकते हैं msdn.microsoft.com/en-us/library/windows/desktop/…
एड ब्रिग्स

बस __rdtsc का उल्लेख करना पसंद है , यह QueryPerformanceCounter का उपयोग करता है।
कॉलिन लामरे

जवाबों:


159
#include <windows.h>

double PCFreq = 0.0;
__int64 CounterStart = 0;

void StartCounter()
{
    LARGE_INTEGER li;
    if(!QueryPerformanceFrequency(&li))
    cout << "QueryPerformanceFrequency failed!\n";

    PCFreq = double(li.QuadPart)/1000.0;

    QueryPerformanceCounter(&li);
    CounterStart = li.QuadPart;
}
double GetCounter()
{
    LARGE_INTEGER li;
    QueryPerformanceCounter(&li);
    return double(li.QuadPart-CounterStart)/PCFreq;
}

int main()
{
    StartCounter();
    Sleep(1000);
    cout << GetCounter() <<"\n";
    return 0;
}

इस कार्यक्रम को 1000 के करीब एक संख्या का उत्पादन करना चाहिए (विंडोज़ नींद उतना सटीक नहीं है, लेकिन यह 999 की तरह होना चाहिए)।

StartCounter()समारोह टिक प्रदर्शन काउंटर में है की संख्या रिकॉर्ड CounterStartचर। यह GetCounter()फ़ंक्शन मिलीसेकंड की संख्या को लौटाता है क्योंकि StartCounter()अंतिम रूप से इसे डबल कहा जाता था, इसलिए यदि GetCounter()0.001 रिटर्न देता है तो इसे लगभग 1 माइक्रोसेकंड StartCounter()कहा गया है।

यदि आप इसके बजाय टाइमर का उपयोग सेकंड करना चाहते हैं तो बदल दें

PCFreq = double(li.QuadPart)/1000.0;

सेवा

PCFreq = double(li.QuadPart);

या यदि आप माइक्रोसेकंड चाहते हैं तो उपयोग करें

PCFreq = double(li.QuadPart)/1000000.0;

लेकिन वास्तव में यह सुविधा के बारे में है क्योंकि यह एक डबल देता है।


5
वास्तव में, LARGE_INTEGER क्या है?
बेनामी

5
यह एक विंडोज़ प्रकार है, मूल रूप से एक पोर्टेबल 64 बिट पूर्णांक है। यह परिभाषा इस बात पर निर्भर करती है कि लक्ष्य प्रणाली 64 बिट पूर्णांक का समर्थन करती है या नहीं। यदि सिस्टम 64 बिट इनट्स का समर्थन नहीं करता है, तो इसे 2 32 बिट इनट्स, एक हाईपार्ट और एक लोपार्ट के रूप में परिभाषित किया गया है। यदि सिस्टम 64 बिट इनट्स का समर्थन करता है तो यह 2 32 बिट इनट्स और 64 बिट इंट के बीच एक संघ है जिसे क्वाडपार्ट कहा जाता है।
रामोनस्टर

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

15
@TonyD: MSDN प्रलेखन कहता है: On a multiprocessor computer, it should not matter which processor is called. However, you can get different results on different processors due to bugs in the basic input/output system (BIOS) or the hardware abstraction layer (HAL).यह कोड बुरी तरह से दोषपूर्ण नहीं है, लेकिन कुछ BIOS या HAL है।
लुकास

3
@TonyD: मैंने अभी इस पर थोड़ा और गौर किया है। मैंने StartCounterफ़ंक्शन में निम्नलिखित कॉल जोड़ा : old_mask = SetThreadAffinityMask(GetCurrentThread,1);और फिर इसे अंत में सेट किया SetThreadAffinityMask ( GetCurrentThread , old_mask ) ;। मुझे उम्मीद है कि वह चाल चलेगा। यह मेरे धागे को कुछ भी लेकिन 1 सीपीयू कोर से पुनर्निर्धारित होने से रोकना चाहिए। (जो स्पष्ट रूप से एक परीक्षण वातावरण के लिए केवल एक समाधान है)
लुकास

19

मैं इन परिभाषित का उपयोग करें:

/** Use to init the clock */
#define TIMER_INIT \
    LARGE_INTEGER frequency; \
    LARGE_INTEGER t1,t2; \
    double elapsedTime; \
    QueryPerformanceFrequency(&frequency);


/** Use to start the performance timer */
#define TIMER_START QueryPerformanceCounter(&t1);

/** Use to stop the performance timer and output the result to the standard stream. Less verbose than \c TIMER_STOP_VERBOSE */
#define TIMER_STOP \
    QueryPerformanceCounter(&t2); \
    elapsedTime=(float)(t2.QuadPart-t1.QuadPart)/frequency.QuadPart; \
    std::wcout<<elapsedTime<<L" sec"<<endl;

उपयोग (कोष्ठक को रोकने के लिए)

TIMER_INIT

{
   TIMER_START
   Sleep(1000);
   TIMER_STOP
}

{
   TIMER_START
   Sleep(1234);
   TIMER_STOP
}

उपयोग उदाहरण से आउटपुट:

1.00003 sec
1.23407 sec

2

यह मानते हुए कि आप Windows पर हैं (यदि आपको अपना प्रश्न इस प्रकार टैग करना चाहिए!), तो इस MSDN पृष्ठ पर आप एक सरल, उपयोगी HRTimerC ++ क्लास के लिए स्रोत पा सकते हैं जो आवश्यक सिस्टम कॉल को लपेटता है, जो आपके लिए आवश्यक है। (यह करने के लिए एक GetTicks()विधि जोड़ना आसान होगा , विशेष रूप से, ठीक वही करने के लिए जो आपको चाहिए)।

गैर-विंडोज प्लेटफार्मों पर, कोई क्वेरीपेरफॉर्मेंसकाउंटर फ़ंक्शन नहीं है, इसलिए समाधान सीधे पोर्टेबल नहीं होगा। हालांकि, यदि आप इसे ऊपर बताए गए वर्ग में लपेटते हैं, तो HRTimerवर्तमान प्लेटफ़ॉर्म को वास्तव में ऑफ़र करने में सक्षम होने का उपयोग करने के लिए कक्षा के कार्यान्वयन को बदलना आसान होगा (हो सकता है कि बूस्ट के माध्यम से या जो भी हो!)।


1

मैं इस सवाल का विस्तार एनडीआईएस ड्राइवर के साथ समय मिलने पर करूंगा। जैसा कि एक जानता है, KeQuerySystemTime (NdisGetCurrentSystemTime के तहत नकल) मिलीसेकंड के ऊपर कम रिज़ॉल्यूशन है, और नेटवर्क पैकेट या अन्य आईआरपी जैसी कुछ प्रक्रियाएं हैं जिन्हें बेहतर टाइमस्टैम्प की आवश्यकता हो सकती है;

उदाहरण केवल सरल है:

LONG_INTEGER data, frequency;
LONGLONG diff;
data = KeQueryPerformanceCounter((LARGE_INTEGER *)&frequency)
diff = data.QuadPart / (Frequency.QuadPart/$divisor)

जहां भाजक आवश्यक संकल्प के आधार पर 10 ^ 3, या 10 ^ 6 है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.