यह नया उत्तर 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
इससे पता चलता है कि इन घड़ियों में से प्रत्येक की एक अलग टिक अवधि होती है, क्योंकि प्रति प्रवाह की टिक प्रत्येक घड़ी के लिए अलग-अलग होती है। हालांकि, जब समय की एक ज्ञात इकाई में परिवर्तित हो जाता है (उदाहरण के लिए पिकोसेकंड), मुझे प्रत्येक घड़ी के लिए लगभग समान परिणाम मिलता है (आपका माइलेज भिन्न हो सकता है)।
ध्यान दें कि मेरा कोड "जादू रूपांतरण स्थिरांक" से पूरी तरह मुक्त कैसे है। वास्तव में, पूरे उदाहरण में केवल दो मैजिक नंबर हैं:
- परिभाषित करने के लिए मेरी मशीन की घड़ी की गति
x::clock
।
- परीक्षण करने के लिए पुनरावृत्तियों की संख्या। यदि इस संख्या को बदलने से आपके परिणाम बहुत भिन्न हो जाते हैं, तो आपको संभवतः पुनरावृत्तियों की संख्या को अधिक करना चाहिए, या परीक्षण के दौरान प्रतिस्पर्धात्मक प्रक्रियाओं के अपने कंप्यूटर को खाली करना चाहिए।