केवल एएनएसआई सी का उपयोग करना, क्या मिलीसेकंड सटीक या अधिक के साथ समय को मापने का कोई तरीका है? मैं समय ब्राउज़ कर रहा था। लेकिन मुझे केवल दूसरा सटीक कार्य मिला।
केवल एएनएसआई सी का उपयोग करना, क्या मिलीसेकंड सटीक या अधिक के साथ समय को मापने का कोई तरीका है? मैं समय ब्राउज़ कर रहा था। लेकिन मुझे केवल दूसरा सटीक कार्य मिला।
जवाबों:
कोई एएनएसआई सी फ़ंक्शन नहीं है जो 1 सेकंड के समय के रिज़ॉल्यूशन लेकिन पोसिक्स फ़ंक्शन से बेहतर प्रदान करता है gettimeofday
माइक्रोसेकंड रिज़ॉल्यूशन प्रदान करता है। घड़ी फ़ंक्शन केवल उस समय की मात्रा को मापता है जो एक प्रक्रिया ने निष्पादन में खर्च किया है और कई प्रणालियों पर सटीक नहीं है।
आप इस फ़ंक्शन का उपयोग इस तरह कर सकते हैं:
struct timeval tval_before, tval_after, tval_result;
gettimeofday(&tval_before, NULL);
// Some code you want to time, for example:
sleep(1);
gettimeofday(&tval_after, NULL);
timersub(&tval_after, &tval_before, &tval_result);
printf("Time elapsed: %ld.%06ld\n", (long int)tval_result.tv_sec, (long int)tval_result.tv_usec);
यह Time elapsed: 1.000870
मेरी मशीन पर लौटता है ।
timeval::tv_usec
यह हमेशा एक सेकंड के नीचे होता है, यह लूपिंग होता है। 1 सेकंड से अधिक समय के अंतर को लेने के लिए, आपको चाहिए:long usec_diff = (e.tv_sec - s.tv_sec)*1000000 + (e.tv_usec - s.tv_usec);
timersub
समारोह के अंदर बिगड़ा हुआ है। हम tval_result
मानों (tv_sec और tv_usec) का उपयोग कर सकते हैं -जैसा है।
#include <time.h>
clock_t uptime = clock() / (CLOCKS_PER_SEC / 1000);
CLOCKS_PER_SEC / 1000
संभवतः CLOCKS_PER_SEC
अक्षम हो सकता है जो अंतिम परिणाम को प्रभावित कर सकता है (हालांकि मेरे अनुभव में हमेशा 1000 का गुणक रहा है)। अक्षमता (1000 * clock()) / CLOCKS_PER_SEC
को कम करने के लिए अतिसंवेदनशील है, लेकिन दूसरी तरफ अतिप्रवाह के लिए अतिसंवेदनशील है। बस कुछ मुद्दों पर विचार करने के लिए।
मैं हमेशा घड़ी_गेटाइम () फ़ंक्शन का उपयोग करता हूं, CLOCK_MONOTONIC घड़ी से समय लौटाता हूं। लौटाया गया समय, सेकंड और नैनोसेकंड में समय की मात्रा है, क्योंकि अतीत में कुछ अनिर्दिष्ट बिंदु, जैसे कि युग के सिस्टम स्टार्टअप।
#include <stdio.h>
#include <stdint.h>
#include <time.h>
int64_t timespecDiff(struct timespec *timeA_p, struct timespec *timeB_p)
{
return ((timeA_p->tv_sec * 1000000000) + timeA_p->tv_nsec) -
((timeB_p->tv_sec * 1000000000) + timeB_p->tv_nsec);
}
int main(int argc, char **argv)
{
struct timespec start, end;
clock_gettime(CLOCK_MONOTONIC, &start);
// Some code I am interested in measuring
clock_gettime(CLOCK_MONOTONIC, &end);
uint64_t timeElapsed = timespecDiff(&end, &start);
}
clock_gettime(CLOCK_MONOTONIC, ...)
और यहां तक कि फीचर टेस्ट मैक्रो भी है _POSIX_MONOTONIC_CLOCK
।
पोर्टेबल समाधान लागू करना
जैसा कि यहां पहले ही उल्लेख किया गया था कि समय मापन समस्या के लिए पर्याप्त सटीकता के साथ कोई उचित एएनएसआई समाधान नहीं है, मैं उन तरीकों के बारे में लिखना चाहता हूं कि कैसे एक पोर्टेबल और, यदि संभव हो तो, एक उच्च-रिज़ॉल्यूशन समय मापन समाधान।
मोनोटोनिक घड़ी बनाम समय टिकटों
आम तौर पर बोलने के समय मापने के दो तरीके हैं:
पहले वाला एक मोनोटोनिक क्लॉक काउंटर (कभी-कभी इसे टिक काउंटर कहा जाता है) का उपयोग करता है, जो एक पूर्वनिर्धारित आवृत्ति के साथ टिकों की गिनती करता है, इसलिए यदि आपके पास एक टिक मूल्य है और आवृत्ति ज्ञात है, तो आप आसानी से टिक को बीता हुआ समय में बदल सकते हैं। यह वास्तव में गारंटी नहीं है कि एक मोनोटोनिक घड़ी किसी भी तरह से वर्तमान सिस्टम समय को दर्शाती है, यह सिस्टम स्टार्टअप के बाद से टिकों की गिनती भी कर सकती है। लेकिन यह गारंटी देता है कि सिस्टम राज्य की परवाह किए बिना एक घड़ी हमेशा बढ़ती हुई शैली में चलती है। आमतौर पर आवृत्ति एक हार्डवेयर उच्च-रिज़ॉल्यूशन स्रोत से जुड़ी होती है, इसीलिए यह एक उच्च सटीकता प्रदान करता है (हार्डवेयर पर निर्भर करता है, लेकिन अधिकांश आधुनिक हार्डवेयर में उच्च-रिज़ॉल्यूशन क्लॉक स्रोतों के साथ कोई समस्या नहीं है)।
दूसरा तरीका मौजूदा सिस्टम क्लॉक वैल्यू के आधार पर (डेट) टाइम वैल्यू प्रदान करता है। इसका एक उच्च रिज़ॉल्यूशन भी हो सकता है, लेकिन इसकी एक बड़ी खामी है: इस तरह का समय मान विभिन्न सिस्टम टाइम समायोजन, यानी समय क्षेत्र परिवर्तन, डेलाइट सेविंग टाइम (DST) परिवर्तन, NTP सर्वर अपडेट, सिस्टम हाइबरनेशन और इतने से प्रभावित हो सकता है पर। कुछ परिस्थितियों में आप एक नकारात्मक समय मान प्राप्त कर सकते हैं जो एक अपरिभाषित व्यवहार का कारण बन सकता है। वास्तव में इस तरह का समय स्रोत पहले वाले की तुलना में कम विश्वसनीय है।
तो समय अंतराल मापने में पहला नियम संभव हो तो एक मोनोटोनिक घड़ी का उपयोग करना है। यह आमतौर पर एक उच्च परिशुद्धता है, और यह डिजाइन द्वारा विश्वसनीय है।
पतन की रणनीति
पोर्टेबल समाधान को लागू करते समय यह एक गिरावट की रणनीति पर विचार करने के लिए लायक है: यदि उपलब्ध है और सिस्टम में कोई मोनोटोनिक घड़ी नहीं है, तो समय स्टैम्प दृष्टिकोण के लिए उपलब्ध होने पर एक मोनोटोनिक घड़ी का उपयोग करें।
खिड़कियाँ
विंडोज पर समय मापन के बारे में MSDN पर उच्च-रिज़ॉल्यूशन समय टिकटों को प्राप्त करने के लिए एक महान लेख है, जिसमें उन सभी विवरणों का वर्णन है जो आपको सॉफ़्टवेयर और हार्डवेयर समर्थन के बारे में जानने की आवश्यकता हो सकती है। विंडोज पर एक उच्च परिशुद्धता समय टिकट प्राप्त करने के लिए आपको चाहिए:
क्वेरी टाइमर आवृत्ति (प्रति सेकंड टिक्स) QueryPerformanceFrequency के साथ :
LARGE_INTEGER tcounter;
LARGE_INTEGER freq;
if (QueryPerformanceFrequency (&tcounter) != 0)
freq = tcounter.QuadPart;
टाइमर की आवृत्ति सिस्टम बूट पर तय की गई है, इसलिए आपको इसे केवल एक बार प्राप्त करने की आवश्यकता है।
क्वेरी के साथ मौजूदा टिक वैल्यू को क्वेरीपेरफॉर्मेंस एनकाउंटर के लिए क्वेरी करें :
LARGE_INTEGER tcounter;
LARGE_INTEGER tick_value;
if (QueryPerformanceCounter (&tcounter) != 0)
tick_value = tcounter.QuadPart;
स्केल को बीता हुआ समय, अर्थात माइक्रोसेकंड तक:
LARGE_INTEGER usecs = (tick_value - prev_tick_value) / (freq / 1000000);
Microsoft के अनुसार आपको ज्यादातर मामलों में Windows XP और बाद के संस्करणों में इस दृष्टिकोण से कोई समस्या नहीं होनी चाहिए। लेकिन आप विंडोज पर दो फॉलबैक सॉल्यूशंस का भी इस्तेमाल कर सकते हैं:
GetTickCount
, लेकिन यह Windows Vista और इसके बाद के संस्करण से उपलब्ध है।OS X (macOS)
OS X (macOS) की अपनी स्वयं की मच निरपेक्ष समय इकाइयाँ हैं जो एक मोनोटोनिक घड़ी का प्रतिनिधित्व करती हैं। शुरू करने का सबसे अच्छा तरीका ऐप्पल का लेख तकनीकी क्यू एंड ए क्यूए 1398: मच एब्सोल्यूट टाइम इकाइयाँ हैं (जो कोड उदाहरणों के साथ) बताता है कि मोनोटोनिक टिक पाने के लिए मच-विशिष्ट एपीआई का उपयोग कैसे करें। इसके बारे में एक स्थानीय सवाल यह भी है कि मैक ओएस एक्स में घड़ी_गेटटाइम विकल्प कहा जाता है जो अंत में आपको थोड़ा भ्रमित कर सकता है कि संभावित मूल्य अतिप्रवाह के साथ क्या करना है क्योंकि काउंटर आवृत्ति का उपयोग अंश और हर के रूप में किया जाता है। तो, एक छोटा सा उदाहरण कि कैसे बीते हुए समय को प्राप्त करें:
घड़ी आवृत्ति अंश और हर प्राप्त करें:
#include <mach/mach_time.h>
#include <stdint.h>
static uint64_t freq_num = 0;
static uint64_t freq_denom = 0;
void init_clock_frequency ()
{
mach_timebase_info_data_t tb;
if (mach_timebase_info (&tb) == KERN_SUCCESS && tb.denom != 0) {
freq_num = (uint64_t) tb.numer;
freq_denom = (uint64_t) tb.denom;
}
}
आपको केवल एक बार ऐसा करने की आवश्यकता है।
वर्तमान टिक वैल्यू के साथ क्वेरी करें mach_absolute_time
:
uint64_t tick_value = mach_absolute_time ();
स्केल को बीता हुआ समय, अर्थात् माइक्रोसेकंड के लिए, पहले से ही अंश और हर का उपयोग करके:
uint64_t value_diff = tick_value - prev_tick_value;
/* To prevent overflow */
value_diff /= 1000;
value_diff *= freq_num;
value_diff /= freq_denom;
अतिप्रवाह को रोकने के लिए मुख्य विचार यह है कि अंश और हर का उपयोग करने से पहले टिक्सेस को वांछित सटीकता तक स्केल किया जाए। जैसा कि प्रारंभिक टाइमर संकल्प नैनोसेकंड में है, हम इसे 1000
माइक्रोसेकंड प्राप्त करने के लिए विभाजित करते हैं । आप क्रोमियम के time_mac.c में उपयोग किए गए समान दृष्टिकोण को पा सकते हैं । अगर आपको वास्तव में नैनोसेकंड सटीकता की आवश्यकता है, तो पढ़ने पर विचार करें कि मैं कैसे बिना ओवरफ्लो किए mach_absolute_time का उपयोग कर सकता हूं? ।
लिनक्स और यूनिक्स
clock_gettime
कॉल किसी भी POSIX के अनुकूल प्रणाली पर अपने सबसे अच्छा तरीका है। यह अलग-अलग घड़ी स्रोतों से समय की क्वेरी कर सकता है, और जिसकी हमें आवश्यकता है CLOCK_MONOTONIC
। सभी प्रणालियाँ जिनके पास clock_gettime
समर्थन नहीं है CLOCK_MONOTONIC
, इसलिए सबसे पहले आपको इसकी उपलब्धता की जाँच करनी होगी:
_POSIX_MONOTONIC_CLOCK
मूल्य को परिभाषित किया जाता है >= 0
तो इसका मतलब है कि CLOCK_MONOTONIC
यह उपलब्ध है;यदि _POSIX_MONOTONIC_CLOCK
इसे परिभाषित किया गया है, 0
तो इसका मतलब है कि आपको अतिरिक्त जांच करनी चाहिए कि क्या यह रनटाइम पर काम करता है, मैं उपयोग करने का सुझाव देता हूं sysconf
:
#include <unistd.h>
#ifdef _SC_MONOTONIC_CLOCK
if (sysconf (_SC_MONOTONIC_CLOCK) > 0) {
/* A monotonic clock presents */
}
#endif
उपयोग clock_gettime
सीधे आगे है:
समय मान प्राप्त करें:
#include <time.h>
#include <sys/time.h>
#include <stdint.h>
uint64_t get_posix_clock_time ()
{
struct timespec ts;
if (clock_gettime (CLOCK_MONOTONIC, &ts) == 0)
return (uint64_t) (ts.tv_sec * 1000000 + ts.tv_nsec / 1000);
else
return 0;
}
मैं यहाँ microseconds के लिए समय कम कर दिया है।
पिछले समय के मूल्य के अंतर की गणना उसी तरह करें:
uint64_t prev_time_value, time_value;
uint64_t time_diff;
/* Initial time */
prev_time_value = get_posix_clock_time ();
/* Do some work here */
/* Final time */
time_value = get_posix_clock_time ();
/* Time difference */
time_diff = time_value - prev_time_value;
gettimeofday
कॉल का उपयोग करने के लिए सबसे अच्छी गिरावट रणनीति है : यह एक मोनोटोनिक नहीं है, लेकिन यह काफी अच्छा प्रस्ताव प्रदान करता है। विचार के साथ ही है clock_gettime
, लेकिन आपको एक समय मूल्य प्राप्त करना चाहिए:
#include <time.h>
#include <sys/time.h>
#include <stdint.h>
uint64_t get_gtod_clock_time ()
{
struct timeval tv;
if (gettimeofday (&tv, NULL) == 0)
return (uint64_t) (tv.tv_sec * 1000000 + tv.tv_usec);
else
return 0;
}
फिर से, समय मान को माइक्रोसेकंड तक घटाया जाता है।
SGI IRIX
IRIX में clock_gettime
कॉल है, लेकिन इसका अभाव है CLOCK_MONOTONIC
। इसके बजाय यह अपने आप ही monotonic घड़ी स्रोत के रूप में परिभाषित किया गया है CLOCK_SGI_CYCLE
जो आप के बजाय का उपयोग करना चाहिए CLOCK_MONOTONIC
के साथ clock_gettime
।
सोलारिस और एचपी-यूएक्स
सोलारिस का अपना उच्च-रिज़ॉल्यूशन टाइमर इंटरफ़ेस है, gethrtime
जो नैनोसेकंड में वर्तमान टाइमर मान लौटाता है। हालांकि सोलारिस के नए संस्करण हो सकते हैं clock_gettime
, आप gethrtime
पुराने सोलारिस संस्करणों का समर्थन करने की आवश्यकता होने पर चिपक सकते हैं ।
उपयोग सरल है:
#include <sys/time.h>
void time_measure_example ()
{
hrtime_t prev_time_value, time_value;
hrtime_t time_diff;
/* Initial time */
prev_time_value = gethrtime ();
/* Do some work here */
/* Final time */
time_value = gethrtime ();
/* Time difference */
time_diff = time_value - prev_time_value;
}
एचपी-यूएक्स की कमी है clock_gettime
, लेकिन यह समर्थन करता हैgethrtime
जिसे आपको सोलारिस पर उसी तरह से उपयोग करना चाहिए।
BeOS
BeOS का अपना उच्च-रिज़ॉल्यूशन टाइमर इंटरफ़ेस भी है system_time
जो कंप्यूटर को बूट किए जाने के बाद माइक्रोसेकंड की संख्या को वापस ला देता है।
उदाहरण उपयोग:
#include <kernel/OS.h>
void time_measure_example ()
{
bigtime_t prev_time_value, time_value;
bigtime_t time_diff;
/* Initial time */
prev_time_value = system_time ();
/* Do some work here */
/* Final time */
time_value = system_time ();
/* Time difference */
time_diff = time_value - prev_time_value;
}
ओएस / 2
OS / 2 के पास उच्च-परिशुद्धता समय टिकटों को प्राप्त करने के लिए अपना स्वयं का एपीआई है:
DosTmrQueryFreq
(जीसीसी संकलक के लिए ) एक टाइमर आवृत्ति (प्रति यूनिट टिक्स) क्वेरी :
#define INCL_DOSPROFILE
#define INCL_DOSERRORS
#include <os2.h>
#include <stdint.h>
ULONG freq;
DosTmrQueryFreq (&freq);
क्वेरी के साथ वर्तमान टिक मूल्य DosTmrQueryTime
:
QWORD tcounter;
unit64_t time_low;
unit64_t time_high;
unit64_t timestamp;
if (DosTmrQueryTime (&tcounter) == NO_ERROR) {
time_low = (unit64_t) tcounter.ulLo;
time_high = (unit64_t) tcounter.ulHi;
timestamp = (time_high << 32) | time_low;
}
स्केल को बीता हुआ समय, अर्थात माइक्रोसेकंड तक:
uint64_t usecs = (prev_timestamp - timestamp) / (freq / 1000000);
उदाहरण कार्यान्वयन
आप प्लासी लाइब्रेरी पर एक नज़र डाल सकते हैं जो उपरोक्त वर्णित सभी रणनीतियों को लागू करती है (विवरणों के लिए ptimeprofiler * .c देखें)।
timespec_get
: stackoverflow.com/a/36095407/895245
timespec_get
मोनोटोनिक नहीं है।
timespec_get
C11 से
कार्यान्वयन के संकल्प के लिए, नैनोसेकंड तक रिटर्न देता है।
POSIX से एक ANSI रिपॉफ की तरह दिखता है ' clock_gettime
।
उदाहरण: printf
उबंटू 15.10 पर प्रत्येक 100ms किया जाता है:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
static long get_nanos(void) {
struct timespec ts;
timespec_get(&ts, TIME_UTC);
return (long)ts.tv_sec * 1000000000L + ts.tv_nsec;
}
int main(void) {
long nanos;
long last_nanos;
long start;
nanos = get_nanos();
last_nanos = nanos;
start = nanos;
while (1) {
nanos = get_nanos();
if (nanos - last_nanos > 100000000L) {
printf("current nanos: %ld\n", nanos - start);
last_nanos = nanos;
}
}
return EXIT_SUCCESS;
}
C11 N1570 मानक प्रारूप 7.27.2.5 "timespec_get समारोह कहते हैं,":
यदि आधार TIME_UTC है, तो tv_sec सदस्य एक निर्धारित परिभाषित युग के बाद से सेकंड की संख्या पर सेट हो जाता है, पूरे मान पर काट दिया जाता है और tv_nsec सदस्य सिस्टम घड़ी के रिज़ॉल्यूशन के लिए नैनोसेकंड के अभिन्न नंबर पर सेट होता है। (321)
321) हालांकि एक संरचनात्मक टाइमस्पेक ऑब्जेक्ट नैनोसेकंड रिज़ॉल्यूशन के साथ समय का वर्णन करता है, उपलब्ध रिज़ॉल्यूशन सिस्टम निर्भर है और 1 सेकंड से अधिक भी हो सकता है।
C ++ 11 भी मिला std::chrono::high_resolution_clock
: C ++ क्रॉस-प्लेटफ़ॉर्म हाई-रिज़ॉल्यूशन टाइमर
glibc 2.21 कार्यान्वयन
के sysdeps/posix/timespec_get.c
रूप में पाया जा सकता है :
int
timespec_get (struct timespec *ts, int base)
{
switch (base)
{
case TIME_UTC:
if (__clock_gettime (CLOCK_REALTIME, ts) < 0)
return 0;
break;
default:
return 0;
}
return base;
}
इतना स्पष्ट रूप से:
केवल TIME_UTC
वर्तमान में समर्थित है
यह आगे की ओर है __clock_gettime (CLOCK_REALTIME, ts)
, जो एक POSIX API है: http://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_getres.html
लिनक्स x86-64 में एक clock_gettime
सिस्टम कॉल है।
ध्यान दें कि यह एक विफल-प्रूफ माइक्रो-बेंचमार्किंग विधि नहीं है क्योंकि:
man clock_gettime
यदि आपका प्रोग्राम चलते समय कुछ सिस्टम टाइम सेटिंग में बदलाव करता है, तो इस माप में असंतोष हो सकता है। यह पाठ्यक्रम की एक दुर्लभ घटना होनी चाहिए, और आप इसे अनदेखा करने में सक्षम हो सकते हैं।
यह दीवार के समय को मापता है, इसलिए यदि अनुसूचक आपके कार्य के बारे में भूलने का फैसला करता है, तो यह अधिक समय तक चलता रहेगा।
उन कारणों से getrusage()
यह एक बेहतर बेहतर POSIX बेंचमार्किंग टूल हो सकता है, इसके बावजूद कि यह माइक्रोसेकंड अधिकतम परिशुद्धता कम है।
पर अधिक जानकारी: लिनक्स में समय को मापें - समय बनाम घड़ी बनाम गेट्रेज बनाम घड़ी_गेटाइम बनाम गेटटाइमऑफडे बनाम टाइमपेक_गेट?
सबसे अच्छी परिशुद्धता जो आप संभवतः प्राप्त कर सकते हैं, x86- केवल "rdtsc" निर्देश के उपयोग के माध्यम से है, जो घड़ी-स्तरीय रिज़ॉल्यूशन प्रदान कर सकता है (निश्चित रूप से rdtsc कॉल की लागत को ध्यान में रखना चाहिए, जिसे आसानी से मापा जा सकता है अनुप्रयोग स्टार्टअप)।
यहां मुख्य पकड़ प्रति सेकंड घड़ियों की संख्या को माप रही है, जो बहुत कठिन नहीं होनी चाहिए।
स्वीकृत उत्तर काफी अच्छा है। लेकिन मेरा समाधान अधिक सरल है। मैं अभी लिनक्स में परीक्षण करता हूं, gcc का उपयोग करता हूं (Ubuntu 7.2.0-8ubuntu3.2) 7.2.0।
वरना उपयोग gettimeofday
, tv_sec
दूसरे का हिस्सा है, और tv_usec
है माइक्रोसेकंड , नहीं मिली सेकंड ।
long currentTimeMillis() {
struct timeval time;
gettimeofday(&time, NULL);
return time.tv_sec * 1000 + time.tv_usec / 1000;
}
int main() {
printf("%ld\n", currentTimeMillis());
// wait 1 second
sleep(1);
printf("%ld\n", currentTimeMillis());
return 0;
}
यह प्रिंट करें:
1522139691342
1522139692342
, बिल्कुल दूसरा।