Gettimeofday () microsecond संकल्प की गारंटी है?


97

मैं एक गेम पोर्ट कर रहा हूं, जो मूल रूप से लिनक्स के लिए Win32 एपीआई के लिए लिखा गया था (अच्छी तरह से, लिनक्स के लिए Win32 पोर्ट के ओएस एक्स पोर्ट को पोर्ट करना)।

मैंने QueryPerformanceCounterप्रक्रिया शुरू होने के बाद से यूस्कॉन्ड देकर लागू किया है:

BOOL QueryPerformanceCounter(LARGE_INTEGER* performanceCount)
{
    gettimeofday(&currentTimeVal, NULL);
    performanceCount->QuadPart = (currentTimeVal.tv_sec - startTimeVal.tv_sec);
    performanceCount->QuadPart *= (1000 * 1000);
    performanceCount->QuadPart += (currentTimeVal.tv_usec - startTimeVal.tv_usec);

    return true;
}

यह, QueryPerformanceFrequency()आवृत्ति के रूप में एक निरंतर 1000000 देने के साथ युग्मित , मेरी मशीन पर अच्छी तरह से काम करता है , मुझे 64-बिट चर देता है जिसमें uSecondsप्रोग्राम के स्टार्ट-अप के बाद से शामिल है ।

तो क्या यह पोर्टेबल है? अगर कर्नेल को एक निश्चित तरीके से संकलित किया गया था या ऐसा कुछ भी किया गया था, तो मैं इसे अलग तरह से काम करना नहीं चाहता। हालाँकि, मैं लिनक्स के अलावा किसी अन्य चीज़ के लिए गैर-पोर्टेबल होने के साथ ठीक हूँ।

जवाबों:


57

शायद। लेकिन आपको बड़ी समस्याएं हैं। gettimeofday()यदि आपके सिस्टम पर ऐसी प्रक्रियाएँ होती हैं जो टाइमर को बदल देती हैं (यानी, ntpd)। "सामान्य" लाइनक्स पर, मेरा मानना ​​है कि संकल्प gettimeofday()10us है। यह आपके सिस्टम पर चल रही प्रक्रियाओं के आधार पर, आगे और पीछे और समय कूद सकता है। यह आपके प्रश्न संख्या के उत्तर को प्रभावी ढंग से बनाता है।

आपको clock_gettime(CLOCK_MONOTONIC)समय अंतराल के लिए देखना चाहिए । यह मल्टी-कोर सिस्टम और बाहरी घड़ी सेटिंग्स जैसी चीजों के कारण कई कम मुद्दों से ग्रस्त है।

इसके अलावा, clock_getres()फंक्शन में देखें।


1
clock_gettime केवल नवीनतम लिनक्स पर मौजूद है। अन्य प्रणाली में केवल
gettimeofday

3
@ vitaly.v.ch यह POSIX है इसलिए यह केवल Linux और 'newist' नहीं है? Red Hat Enterprise Linux की तरह 'एंटरप्राइज' डिस्ट्रोस भी 2.6.18 पर आधारित है, जिसमें क्लॉक_गेटटाइम है इसलिए नहीं, बहुत नया नहीं है .. (RHEL में मैनपेज की तारीख 2004-मार्च -12 है, इसलिए यह थोड़ी देर के लिए आस-पास है) जब तक आप नहीं होते वास्तव में बात करते हुए OLD गुठली WTF के बारे में आप क्या मतलब है?
स्पड 86

2001 में POSIX में घड़ी_गेटाइम को शामिल किया गया था। जहाँ तक मुझे पता है कि वर्तमान में घड़ी_गेटाइम () लिनक्स 2.6 और qxx में लागू है। लेकिन linux 2.4 वर्तमान में कई उत्पादन प्रणालियों में उपयोग किया जाता है।
vitaly.v.ch

इसे 2001 में पेश किया गया था, लेकिन POSIX 2008 तक अनिवार्य नहीं था।
R .. GitHub STOP HELPING ICE

2
Lock_gettime के लिए लिनक्स अकसर किये गए सवाल से (डेविड स्कॉलनेगल का जवाब देखें) "CLOCK_MONOTONIC ... को NTP द्वारा adjtimex () के माध्यम से समायोजित किया जाता है। भविष्य में (मैं अभी भी पैच प्राप्त करने की कोशिश कर रहा हूं) इसमें CLOCK_MONOTONIC_RAW होगा जो कि नहीं होगा। बिल्कुल संशोधित हो, और हार्डवेयर काउंटरों के साथ एक रैखिक संबंध होगा। " मुझे नहीं लगता कि _RAW घड़ी ने कभी इसे कर्नेल में बनाया (जब तक कि इसका नाम बदलकर _HR नहीं किया गया था, लेकिन मेरा शोध बताता है कि प्रयासों को भी छोड़ दिया गया है)।
टोनी डेलरो

41

उच्च रिज़ॉल्यूशन, इंटेल प्रोसेसर के लिए कम ओवरहेड समय

यदि आप इंटेल हार्डवेयर पर हैं, तो यहां सीपीयू वास्तविक समय अनुदेश काउंटर को कैसे पढ़ा जाए। यह आपको बताएगा कि प्रोसेसर के बूट होने के बाद से कितने सीपीयू साइकल चलाए गए हैं। यह संभवतः सबसे अच्छा-दाने वाला काउंटर है जिसे आप प्रदर्शन माप के लिए प्राप्त कर सकते हैं।

ध्यान दें कि यह सीपीयू चक्रों की संख्या है। लिनक्स पर आप सीपीयू की गति / proc / cpuinfo से प्राप्त कर सकते हैं और सेकंड की संख्या प्राप्त करने के लिए विभाजित कर सकते हैं। इसे डबल में बदलना काफी आसान है।

जब मैं इसे अपने बॉक्स पर चलाता हूं, तो मुझे मिल जाता है

11867927879484732
11867927879692217
it took this long to call printf: 207485

यहां इंटेल डेवलपर का मार्गदर्शक है जो टन को विस्तार देता है।

#include <stdio.h>
#include <stdint.h>

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;
}

main()
{
    unsigned long long x;
    unsigned long long y;
    x = rdtsc();
    printf("%lld\n",x);
    y = rdtsc();
    printf("%lld\n",y);
    printf("it took this long to call printf: %lld\n",y-x);
}

11
ध्यान दें कि टीएससी हमेशा कोर के बीच सिंक्रनाइज़ नहीं किया जा सकता है, जब प्रोसेसर कम बिजली मोड में प्रवेश करता है, तो इसकी आवृत्ति को रोक या बदल सकता है (और आपके पास ऐसा करने का कोई तरीका नहीं है), और सामान्य तौर पर हमेशा विश्वसनीय नहीं होता है। कर्नेल यह पता लगाने में सक्षम है कि यह विश्वसनीय है, एचपीईटी और एसीपीआई पीएम टाइमर जैसे अन्य विकल्पों का पता लगाएं, और स्वचालित रूप से सर्वश्रेष्ठ का चयन करें। यह हमेशा समय के लिए कर्नेल का उपयोग करने के लिए एक अच्छा विचार है जब तक कि आप वास्तव में सुनिश्चित न हों कि टीएससी स्थिर और एकरस है।
सीज़रबी

12
टीएससी कोर और उससे ऊपर के इंटेल प्लेटफॉर्म को कई सीपीयू और वेतन वृद्धि के साथ एक निरंतर आवृत्ति पर सिंक्रनाइज़ किया जाता है जो बिजली प्रबंधन राज्यों से स्वतंत्र होता है। इंटेल सॉफ्टवेयर डेवलपर मैनुअल, वॉल्यूम देखें। 3 धारा 18.10। हालाँकि जिस दर पर काउंटर वेतन वृद्धि होती है वह सीपीयू की आवृत्ति के समान नहीं होती है। TSC "प्लेटफ़ॉर्म की अधिकतम सुलझी हुई आवृत्ति, जो स्केलेबल बस आवृत्ति और अधिकतम हल किए गए बस अनुपात" के बराबर है, इंटेल सॉफ्टवेयर डेवलपर मैनुअल, वॉल्यूम में वृद्धि करता है। 3 धारा 18.18.5। आप उन मूल्यों को सीपीयू के मॉडल-विशिष्ट रजिस्टरों (एमएसआर) से प्राप्त करते हैं।
7:15 बजे sstock

7
आप सीपीयू के मॉडल-विशिष्ट रजिस्टरों (MSRs) के अनुसार स्केलेबल बस आवृत्ति और अधिकतम हल बस अनुपात प्राप्त कर सकते हैं: स्केलेबल बस आवृत्ति == MSR_FSB_FREQ [2: 0] आईडी 0xCD, अधिकतम हल बस अनुपात == MSR_PLATFORM_ID [12: 12 8] आईडी 0x17। रजिस्टर मानों की व्याख्या करने के लिए Intel SDM Vol.3 परिशिष्ट B.1 से परामर्श करें। आप रजिस्टर करने के लिए लिनक्स पर msr-tools का उपयोग कर सकते हैं। kernel.org/pub/linux/utils/cpu/msr-tools
sstock

1
क्या CPUIDपहले RDTSCनिर्देश के बाद और कोड को बेंचमार्क किए जाने से पहले आपके कोड का फिर से उपयोग नहीं होना चाहिए ? अन्यथा, बेंचमार्क कोड को पहले / के साथ-साथ-साथ निष्पादित किया जाना बंद करने के लिए क्या करना है RDTSC, और परिणामस्वरूप RDTSCडेल्टा में प्रस्तुत किया गया है?
टोनी डेलारॉय

18

@Bernard:

मुझे स्वीकार करना होगा, आपका अधिकांश उदाहरण सीधे मेरे सिर पर चला गया। यह संकलन करता है, और काम करने लगता है, हालांकि। क्या यह एसएमपी सिस्टम या स्पीडस्टेप के लिए सुरक्षित है?

यह एक अच्छा सवाल है ... मुझे लगता है कि कोड ठीक है। एक व्यावहारिक दृष्टिकोण से, हम हर दिन अपनी कंपनी में इसका उपयोग करते हैं, और हम 2-8 कोर से सब कुछ बॉक्स के एक बहुत विस्तृत सरणी पर चलाते हैं। बेशक, YMMV, आदि, लेकिन यह एक विश्वसनीय और कम-ओवरहेड प्रतीत होता है (क्योंकि यह समय के सिस्टम-स्पेस में एक संदर्भ स्विच नहीं करता है)।

आम तौर पर यह कैसे काम करता है:

  • कोड के ब्लॉक को कोडांतरक घोषित करें (और अस्थिर है, इसलिए अनुकूलक इसे अकेला छोड़ देगा)।
  • CPUID निर्देश निष्पादित करें। कुछ सीपीयू जानकारी प्राप्त करने के अलावा (जो हम कुछ भी नहीं करते हैं) यह सीपीयू के निष्पादन बफर को सिंक्रनाइज़ करता है ताकि टाइमिंग आउट-ऑफ-ऑर्डर निष्पादन से प्रभावित न हो।
  • rdtsc निष्पादित करें (टाइमस्टैम्प पढ़ें) निष्पादन। यह प्रोसेसर के रीसेट होने के बाद से निष्पादित मशीन चक्र की संख्या को प्राप्त करता है। यह 64-बिट मान है, इसलिए वर्तमान सीपीयू की गति के साथ यह प्रत्येक 194 साल या उसके आसपास लपेटेगा। दिलचस्प है, मूल पेंटियम संदर्भ में, वे यह नोट करते हैं कि यह प्रत्येक 5800 साल या उसके आसपास लपेटता है।
  • अंतिम दो पंक्तियाँ रजिस्टरों से वैरिएबल हाय और लो में मानों को संग्रहीत करती हैं, और 64-बिट रिटर्न वैल्यू में डालती हैं।

विशिष्ट नोट:

  • आउट-ऑफ-ऑर्डर निष्पादन गलत परिणाम दे सकता है, इसलिए हम "cpuid" निर्देश को निष्पादित करते हैं जो आपको cpu के बारे में कुछ जानकारी देने के अलावा किसी भी आउट-ऑफ-ऑर्डर निर्देश निष्पादन को भी सिंक्रनाइज़ करता है।

  • अधिकांश OS शुरू होने पर सीपीयू पर काउंटरों को सिंक्रनाइज़ करते हैं, इसलिए नैनो-सेकंड के एक जोड़े के भीतर उत्तर अच्छा है।

  • हाइबरनेटिंग टिप्पणी शायद सच है, लेकिन व्यवहार में आप शायद हाइबरनेशन सीमाओं के समय के बारे में परवाह नहीं करते हैं।

  • स्पीडस्टेप के बारे में: नए इंटेल सीपीयू गति में बदलाव के लिए क्षतिपूर्ति करते हैं और एक समायोजित गणना लौटाते हैं। मैंने हमारे नेटवर्क के कुछ बक्सों पर एक त्वरित स्कैन किया और केवल एक ही बक्सा पाया, जिसमें यह नहीं था: एक पेंटियम 3 जो कुछ पुराने डेटाबेस सर्वर को चला रहा था। (ये लिनक्स बॉक्स हैं, इसलिए मैंने इनकी जाँच की: grep constant_tsc / proc / cpuinfo)

  • मुझे एएमडी सीपीयू के बारे में निश्चित नहीं है, हम मुख्य रूप से एक इंटेल शॉप हैं, हालांकि मुझे पता है कि हमारे कुछ निम्न-स्तरीय सिस्टम गुरुओं ने एएमडी मूल्यांकन किया था।

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


1
... कर्नेल लोग कुछ समय के लिए rdtsc का उपयोग बंद करने के लिए लोगों को प्राप्त करने की कोशिश कर रहे हैं ... और आमतौर पर इसे कर्नेल में उपयोग करने से बचें क्योंकि यह सिर्फ अविश्वसनीय है।
स्पड 86

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


11

शराब वास्तव में क्वेटपेरफॉर्मेंस एनकाउंटर () को लागू करने के लिए गेटटाइमऑफ () का उपयोग कर रही है और इसे लिनक्स और मैक पर कई विंडोज गेम्स काम करने के लिए जाना जाता है।

शुरू होता है http://source.winehq.org/source/dlls/kernel32/cpu.c#L312

http://source.winehq.org/source/dlls/ntdll/time.c#L448 की ओर जाता है


9

तो यह स्पष्ट रूप से microseconds कहते हैं, लेकिन कहते हैं कि सिस्टम घड़ी का संकल्प अनिर्दिष्ट है। मुझे लगता है कि इस संदर्भ में संकल्प का मतलब है कि यह कितनी छोटी राशि होगी?

डेटा संरचना को माप की एक इकाई के रूप में माइक्रोसेकंड होने के रूप में परिभाषित किया गया है, लेकिन इसका मतलब यह नहीं है कि घड़ी या ऑपरेटिंग सिस्टम वास्तव में उस सूक्ष्मता को मापने में सक्षम है।

जैसे अन्य लोगों ने सुझाव दिया है, gettimeofday()बुरा है क्योंकि समय निर्धारित करने से घड़ी तिरछा हो सकता है और आपकी गणना बंद हो सकती है। clock_gettime(CLOCK_MONOTONIC)वह है जो आप चाहते हैं, और clock_getres()आपको आपकी घड़ी की शुद्धता बताएंगे।


तो क्या आपके कोड में होता है जब gettimeofday () दिन के उजाले की बचत के साथ आगे या पीछे कूदता है?
mpez0

3
clock_gettime केवल नवीनतम लिनक्स पर मौजूद है। अन्य प्रणाली में केवल
gettimeofday

8

गेटटाइमऑफडे () का वास्तविक रिज़ॉल्यूशन हार्डवेयर आर्किटेक्चर पर निर्भर करता है। इंटेल प्रोसेसर के साथ-साथ स्पार्क मशीनें उच्च रिज़ॉल्यूशन टाइमर की पेशकश करती हैं जो माइक्रोसेकंड को मापते हैं। अन्य हार्डवेयर आर्किटेक्चर सिस्टम के टाइमर पर वापस आते हैं, जो आमतौर पर 100 हर्ट्ज पर सेट होता है। ऐसे मामलों में, समय संकल्प कम सटीक होगा।

मुझे यह उत्तर हाई रिजॉल्यूशन टाइम मेजरमेंट एंड टाइमर, भाग I से प्राप्त हुआ


6

इस उत्तर में घड़ी के समायोजित होने की समस्याओं का उल्लेख है। आपकी दोनों समस्याएं टिक इकाइयों की गारंटी देती हैं और समय के साथ समायोजित होने वाली समस्याओं को <chrono>लाइब्रेरी के साथ C ++ 11 में हल किया जाता है ।

घड़ी std::chrono::steady_clockकी गारंटी है कि इसे समायोजित नहीं किया जाएगा, और इसके अलावा यह वास्तविक समय के सापेक्ष निरंतर दर पर आगे बढ़ेगा, इसलिए स्पीडस्टेप जैसी तकनीकों को इसे प्रभावित नहीं करना चाहिए।

आप किसी एक स्पेशलाइज़ेशन में कनवर्ट करके टाइपसेफ़ यूनिट प्राप्त कर सकते हैं std::chrono::duration, जैसे कि std::chrono::microseconds। इस प्रकार के साथ टिक मूल्य द्वारा उपयोग की जाने वाली इकाइयों के बारे में कोई अस्पष्टता नहीं है। हालाँकि, ध्यान रखें कि घड़ी में यह रिज़ॉल्यूशन ज़रूरी नहीं है। आप वास्तव में एक घड़ी कि सटीक होने के बिना एक अवधि को एटोसोकेन्ड में बदल सकते हैं।


4

मेरे अनुभव से, और मैंने इंटरनेट पर जो भी पढ़ा है, उसका उत्तर "नहीं" है, इसकी गारंटी नहीं है। यह सीपीयू की गति, ऑपरेटिंग सिस्टम, लिनक्स का स्वाद आदि पर निर्भर करता है।


3

आरडीपीटीसी पढ़ना एसएमपी सिस्टम में विश्वसनीय नहीं है, क्योंकि प्रत्येक सीपीयू अपने स्वयं के काउंटर को बनाए रखता है और प्रत्येक काउंटर को दूसरे सीपीयू के संबंध में सिंक्रनाइज़ करने की गारंटी नहीं है।

मैं कोशिश कर रहा सुझाव दे सकते हैं clock_gettime(CLOCK_REALTIME)। पॉज़िक्स मैनुअल बताता है कि इसे सभी आज्ञाकारी प्रणालियों पर लागू किया जाना चाहिए। यह एक नैनोसेकंड गिनती प्रदान कर सकता है, लेकिन आप शायद clock_getres(CLOCK_REALTIME)अपने सिस्टम पर जांचना चाहेंगे कि वास्तविक संकल्प क्या है।


clock_getres(CLOCK_REALTIME)असली संकल्प नहीं देंगे। यह हमेशा "1 एनएस" (एक नैनोसेकंड) वापस लौटता है जब हर्टिमर्स उपलब्ध होते हैं, तो include/linux/hrtimer.hफ़ाइल को define HIGH_RES_NSEC 1अधिक ( stackoverflow.com/a/23044075/196561 पर देखें )
ऑग्सक्स
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.