কীভাবে কোয়েরি পারফরম্যান্স কাউন্টার ব্যবহার করবেন?


97

আমি সম্প্রতি সিদ্ধান্ত নিয়েছি যে আমার টাইমার শ্রেণীর জন্য মিলিসেকেন্ডগুলি থেকে মাইক্রোসেকেন্ডে পরিবর্তন করা দরকার এবং কিছু গবেষণার পরে আমি সিদ্ধান্ত নিয়েছি যে কোয়েরি পারফরম্যান্স কাউন্টার সম্ভবত আমার নিরাপদ বাজি। ( Boost::Posixএটি উইন 32 এপিআইতে কাজ না করে সে সম্পর্কে সতর্কতা আমাকে কিছুটা দূরে সরিয়ে দেয়)। তবে, কীভাবে এটি বাস্তবায়ন করা যায় তা আমি নিশ্চিত নই।

আমি যা করছি তা হ'ল আমি যে কোনও GetTicks()এস্ক্ক ফাংশনটি কল করছি এবং এটি টাইমার startingTicksভেরিয়েবলকে নির্ধারণ করছি । তারপরে সময়টি নির্ধারণ করার জন্য আমি কেবলমাত্র ফাংশনের রিটার্ন মানটি বিয়োগ startingTicksকরেছিলাম এবং আমি টাইমারটি পুনরায় সেট করার পরে আমি কেবল ফাংশনটি আবার কল করি এবং এটিতে স্টার্টিংটিকস নির্ধারণ করি। দুর্ভাগ্যক্রমে, আমি যে কোডটি দেখেছি তা কেবল কল করার মতো সহজ নয় QueryPerformanceCounter(), এবং আমি নিশ্চিত হতে পারি না যে আমি তার যুক্তি হিসাবে কী পাস করব।


4
আমি রামনস্টারের কোড স্নিপেটগুলি এনে এখানে একটি লাইব্রেরিতে তৈরি করেছি: অনুগামীদের জন্য gist.github.com/1153062
রজারডপ্যাক

4
আমরা সম্প্রতি ক্যুরি পারফরম্যান্স কাউন্টারটির জন্য ডকুমেন্টেশন আপডেট করেছি এবং অতিরিক্ত তথ্য যথাযথ ব্যবহার এবং FAQ এ উত্তর যুক্ত করেছি। আপনি আপডেটড
এড ব্রিগস

শুধু __rdtsc উল্লেখ করতে চাই , এটি কোয়েরি পারফরম্যান্স কাউন্টার ব্যবহার করে।
কলিন lamarre

উত্তর:


161
#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;

এটি সত্যিই সুবিধার্থে যেহেতু এটি দ্বিগুণ করে returns


4
হুবহু, LARGE_INTEGER কী?
বেনামে

4
এটি একটি উইন্ডোজ টাইপ, মূলত একটি বহনযোগ্য bit৪ বিট পূর্ণসংখ্যা। এটির সংজ্ঞাটি লক্ষ্য করে যে সিস্টেমটি bit৪ বিট পূর্ণসংখ্যার সমর্থন করে কিনা তার উপর নির্ভর করে। যদি সিস্টেমটি 64 বিট ইনটকে সমর্থন না করে তবে এটি 2 32 বিট ইনট, একটি হাইপার্ট এবং লো পার্ট হিসাবে সংজ্ঞায়িত করা হয়েছে। যদি সিস্টেমটি 64 বিট ইনটকে সমর্থন করে তবে এটি 2 32 বিট ইনট এবং কোয়াড পার্ট নামে পরিচিত একটি 64 বিট ইন্টের মধ্যে একটি ইউনিয়ন।
রামেনস্টার

9
এই উত্তরটি খারাপভাবে ত্রুটিযুক্ত। কোয়েরি পারফরম্যান্স কাউন্টার একটি নির্দিষ্ট নির্দিষ্ট চক্রের কাউন্টার রেজিস্টার পড়ে এবং যদি মৃত্যুদণ্ডের থ্রেডটি অন্য একটি কোরে পুনরায় নির্ধারণ করা হয়, তবে কোয়েরি পারফরম্যান্স কাউন্টার থেকে দুটি পরিমাপ কেবল ব্যস্ত সময়কেই অন্তর্ভুক্ত করে না, তবে প্রায়শই একটি স্থির, বৃহত এবং কঠোরভাবে দুটি কোর রেজিস্টারের মধ্যে বদ্বীপ চিহ্নিত করা যায়। সুতরাং - আপনার প্রক্রিয়াটি কোনও নির্দিষ্ট মূলের সাথে আবদ্ধ থাকলে এটি কেবল নির্ভরযোগ্যভাবে কাজ করে।
টনি ডেলরয়

15
@ টনিডি: এমএসডিএন ডকুমেন্টেশন বলেছেন: 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).এই কোডটি খারাপভাবে ত্রুটিযুক্ত নয়, তবে কিছু বিআইওএস বা এইচএল রয়েছে।
লুকাস

4
@ টনিডি: আমি এটিকে আরও কিছুটা সন্ধান করেছি। আমি ফাংশনটিতে নিম্নলিখিত কলটি যুক্ত করেছি StartCounter: old_mask = SetThreadAffinityMask(GetCurrentThread,1);এবং তারপরে এটি আবার সেট করুন SetThreadAffinityMask ( GetCurrentThread , old_mask ) ;। আমি আশা করি যে কৌশলটি করবে। এটি আমার থ্রেডকে 1 ম সিপিইউ কোর ব্যতীত অন্য কোনও ক্ষেত্রে পুনরায় নির্ধারণ করা থেকে বিরত রাখতে হবে। (যা সম্ভবত একটি পরীক্ষামূলক পরিবেশে কেবল একটি সমাধান পাওয়া যাবে)
লুকাস

20

আমি এই সংজ্ঞাগুলি ব্যবহার করি:

/** 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

ধরে নিই যে আপনি উইন্ডোজে রয়েছেন (যদি তাই আপনার প্রশ্নটি যেমন ট্যাগ করা উচিত!) তবে এই এমএসডিএন পৃষ্ঠায় আপনি একটি সাধারণ, দরকারী HRTimerসি ++ ক্লাসের উত্স খুঁজে পেতে পারেন যা আপনার প্রয়োজনের খুব কাছাকাছি কিছু করার জন্য প্রয়োজনীয় সিস্টেম কলকে আবৃত করে (এটিতে কোনও GetTicks()পদ্ধতি যুক্ত করা সহজ হবে, বিশেষত, আপনার যা প্রয়োজন ঠিক তা করা)।

উইন্ডোজবিহীন প্ল্যাটফর্মে, কোয়েরি পারফরম্যান্স কাউন্টার ফাংশন নেই, সুতরাং সমাধানটি সরাসরি পোর্টেবল হবে না। তবে আপনি যদি উপরে বর্ণিত শ্রেণীর মতো এটি ক্ল্যাপ করে রাখেন তবে HRTimerবর্তমান প্ল্যাটফর্মটি প্রকৃতপক্ষে যা অফার করতে পারে তা ব্যবহার করার জন্য শ্রেণীর বাস্তবায়ন পরিবর্তন করা সহজ হবে (সম্ভবত বুস্ট বা যা কিছু হোক না কেন!)।


1

সময় পাওয়ার বিষয়ে আমি এনডিআইএসের ড্রাইভার উদাহরণ দিয়ে এই প্রশ্নটি বাড়িয়ে দেব। যেহেতু কেউ জানেন, কে কিউরিসিস্টেমটাইম (এনডিসগেটকন্ট্রেন্ট সিস্টেমটাইমের অধীনে নকল করা) মিলিসেকেন্ডের উপরে কম রেজোলিউশন রয়েছে এবং নেটওয়ার্ক প্যাকেট বা অন্যান্য আইআরপি এর মতো কিছু প্রক্রিয়া রয়েছে যার জন্য আরও ভাল টাইমস্ট্যাম্পের প্রয়োজন হতে পারে;

উদাহরণ ঠিক যেমন সহজ:

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

যেখানে বিভাজক হ'ল 10 ^ 3 বা 10 ^ 6 প্রয়োজনীয় রেজোলিউশনের উপর নির্ভর করে।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.