จะวัดเวลาเป็นมิลลิวินาทีโดยใช้ ANSI C ได้อย่างไร?


127

การใช้ ANSI C เพียงอย่างเดียวมีวิธีใดในการวัดเวลาด้วยความแม่นยำระดับมิลลิวินาทีขึ้นไปหรือไม่? ฉันกำลังเรียกดูเวลา h แต่ฉันพบฟังก์ชันความแม่นยำที่สองเท่านั้น


4
สังเกตความแตกต่างระหว่างความแม่นยำและความแม่นยำ คุณสามารถหาเวลาด้วยความแม่นยำระดับมิลลิวินาทีได้โดยใช้เวลาเป็นวินาทีแล้วคูณด้วย 1,000 แต่ก็ไม่มีประโยชน์ ฟังก์ชันความแม่นยำของ ms ไม่จำเป็นต้องมีความแม่นยำของ ms - แม้ว่าโดยทั่วไปแล้วจะมีความแม่นยำมากกว่า 1 วินาทีก็ตาม
Steve Jessop

2
คำตอบง่ายๆคือไม่ ANSI C ไม่รองรับความแม่นยำระดับมิลลิวินาทีหรือดีกว่า คำตอบที่ซับซ้อนขึ้นอยู่กับสิ่งที่คุณกำลังพยายามทำ - ตรงไปตรงมาพื้นที่ทั้งหมดเป็นฝันร้ายแม้ว่าคุณจะอนุญาตให้ใช้ฟังก์ชัน Posix ที่มีอยู่ทั่วไปก็ตาม คุณใช้คำว่า "วัด" ดังนั้นฉันคิดว่าคุณสนใจช่วงเวลามากกว่า "นาฬิกาแขวน" แต่คุณกำลังพยายามวัดช่วงเวลาที่แน่นอนหรือการใช้ CPU ตามกระบวนการของคุณหรือไม่?
Dipstick

2
แค่อยากจะบอกกับ SOF เพิ่งช่วยเบคอนของฉันอีกครั้ง ;-)
corlettk

คำตอบ:


92

ไม่มีฟังก์ชัน ANSI C ที่ให้ความละเอียดได้ดีกว่า 1 วินาที แต่ฟังก์ชัน POSIX 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ที่เครื่องของฉัน


30
ข้อแม้เล็กน้อย: gettimeofday () ไม่ใช่เสียงเดียวซึ่งหมายความว่าสามารถกระโดดไปรอบ ๆ (และถอยหลังได้ด้วยซ้ำ) ตัวอย่างเช่นหากเครื่องของคุณพยายามที่จะทำการซิงโครไนซ์กับเซิร์ฟเวอร์เวลาเครือข่ายหรือแหล่งเวลาอื่น ๆ
Dipstick

3
เพื่อความแม่นยำ: ใน ISO C99 (ซึ่งฉันคิดว่าเข้ากันได้ในส่วนนี้กับ ANSI C) ไม่มีแม้แต่การรับประกันความละเอียดทุกครั้ง (ISO C99, 7.23.1p4)
Roland Illig

6
เป็นที่น่าสังเกตว่าtimeval::tv_usecมักจะไม่เกินหนึ่งวินาทีมันวนซ้ำ กล่าวคือเพื่อใช้เวลาที่แตกต่างกันมากกว่า 1 วินาทีคุณควร:long usec_diff = (e.tv_sec - s.tv_sec)*1000000 + (e.tv_usec - s.tv_usec);
Alexander Malakhov

4
@Dipstick: แต่โปรดทราบว่าเช่น NTP จะไม่เลื่อนนาฬิกาของคุณไปข้างหลังจนกว่าคุณจะบอกให้ทำอย่างชัดเจน
thejh

1
@AlexanderMalakhov ตรรกะการลบเวลาจะรวมอยู่ภายในtimersubฟังก์ชัน เราสามารถใช้tval_resultค่า (tv_sec และ tv_usec) ตามที่เป็นอยู่
x4444

48
#include <time.h>
clock_t uptime = clock() / (CLOCKS_PER_SEC / 1000);

CLOCKS_PER_SEC ถูกตั้งค่าเป็น 1000000 ในหลายระบบ พิมพ์มูลค่าให้แน่ใจก่อนใช้งานในลักษณะนี้
ysap

16
เนื่องจากนาฬิกาต่อวินาทีจึงไม่สำคัญว่าจะเป็นค่าใดค่าที่ได้จาก clock () / CLOCKS_PER_SEC จะเป็นหน่วยวินาที (อย่างน้อยก็ควรเป็น) หารด้วย 1,000 จะกลายเป็นมิลลิวินาที
David Young

14
ตามคู่มืออ้างอิง C ค่า clock_t สามารถพันรอบเริ่มต้นที่ประมาณ 36 นาที หากคุณกำลังวัดการคำนวณที่ยาวนานคุณจำเป็นต้องตระหนักถึงสิ่งนี้
CyberSkull

4
นอกจากนี้โปรดระวังว่าการหารจำนวนเต็มCLOCKS_PER_SEC / 1000อาจไม่แน่นอนซึ่งอาจส่งผลต่อผลลัพธ์สุดท้าย (แม้ว่าจากประสบการณ์ของฉันCLOCKS_PER_SECจะเป็นผลคูณของ 1,000 เสมอ) การทำ(1000 * clock()) / CLOCKS_PER_SECมีความอ่อนไหวน้อยกว่าต่อความไม่แน่นอนของการแบ่ง แต่ในทางกลับกันมีความอ่อนไหวต่อการล้นมากกว่า เพียงบางประเด็นที่ต้องพิจารณา
Cornstalks

4
นี่ไม่วัดเวลา cpu ไม่ใช่ wall time เหรอ?
krs013

28

ฉันใช้ฟังก์ชัน clock_gettime () ตลอดเวลาโดยย้อนเวลาจากนาฬิกา 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);
}

5
clock_gettime () ไม่ใช่ ANSI C.
PowerApp101

1
นอกจากนี้ CLOCK_MONOTONIC ยังไม่มีการนำไปใช้ในหลายระบบ (รวมถึงแพลตฟอร์ม Linux จำนวนมาก)
Dipstick

2
@ PowerApp101 ไม่มีวิธี ANSI C ที่ดี / มีประสิทธิภาพในการทำเช่นนี้ คำตอบอื่น ๆ อีกมากมายขึ้นอยู่กับ POSIX มากกว่า ANCI C ที่กล่าวมาฉันเชื่อว่าวันนี้ @Dipstick วันนี้ฉันเชื่อว่าแพลตฟอร์มที่ทันสมัยที่สุด [ต้องการอ้างอิง] รองรับclock_gettime(CLOCK_MONOTONIC, ...)และยังมีมาโครทดสอบฟีเจอร์_POSIX_MONOTONIC_CLOCKด้วย
omninonsense

22

การใช้โซลูชันแบบพกพา

ดังที่ได้กล่าวไปแล้วในที่นี้ว่าไม่มีโซลูชัน ANSI ที่เหมาะสมที่มีความแม่นยำเพียงพอสำหรับปัญหาการวัดเวลาฉันต้องการเขียนเกี่ยวกับวิธีการรับอุปกรณ์พกพาและวิธีการวัดเวลาที่มีความละเอียดสูงหากเป็นไปได้

นาฬิกาเสียงเดียวเทียบกับการประทับเวลา

โดยทั่วไปการวัดเวลามีสองวิธี:

  • นาฬิกาโมโนโทนิก
  • ประทับเวลาปัจจุบัน (วันที่)

ตัวแรกใช้ตัวนับนาฬิกาแบบโมโนโทนิค (บางครั้งเรียกว่าตัวนับเห็บ) ซึ่งจะนับเห็บด้วยความถี่ที่กำหนดไว้ล่วงหน้าดังนั้นหากคุณมีค่าเห็บและทราบความถี่คุณสามารถแปลงเห็บเป็นเวลาที่ผ่านไปได้อย่างง่ายดาย จริง ๆ แล้วไม่รับประกันว่านาฬิกาโมโนโทนิกจะสะท้อนเวลาของระบบปัจจุบันไม่ว่าในทางใดก็ตามมันอาจนับเห็บตั้งแต่เริ่มต้นระบบ แต่รับประกันได้ว่านาฬิกาจะทำงานในรูปแบบที่เพิ่มมากขึ้นโดยไม่คำนึงถึงสถานะของระบบ โดยปกติความถี่จะถูกผูกไว้กับแหล่งที่มาของฮาร์ดแวร์ที่มีความละเอียดสูงนั่นเป็นเหตุผลว่าทำไมจึงให้ความแม่นยำสูง (ขึ้นอยู่กับฮาร์ดแวร์ แต่ฮาร์ดแวร์สมัยใหม่ส่วนใหญ่ไม่มีปัญหากับแหล่งสัญญาณนาฬิกาที่มีความละเอียดสูง)

วิธีที่สองให้ค่าเวลา (วันที่) ตามค่านาฬิกาของระบบปัจจุบัน นอกจากนี้ยังอาจมีความละเอียดสูง แต่ก็มีข้อเสียเปรียบที่สำคัญอย่างหนึ่งค่าเวลาประเภทนี้อาจได้รับผลกระทบจากการปรับเปลี่ยนเวลาของระบบที่แตกต่างกันเช่นการเปลี่ยนโซนเวลาการเปลี่ยนแปลงเวลาออมแสง (DST) การอัปเดตเซิร์ฟเวอร์ NTP การไฮเบอร์เนตของระบบและอื่น ๆ บน. ในบางสถานการณ์คุณอาจได้รับค่าเวลาที่ผ่านไปเป็นลบซึ่งอาจนำไปสู่พฤติกรรมที่ไม่ได้กำหนดได้ อันที่จริงแหล่งเวลาประเภทนี้มีความน่าเชื่อถือน้อยกว่าแหล่งแรก

ดังนั้นกฎข้อแรกในการวัดช่วงเวลาคือการใช้นาฬิกาแบบโมโนโทนิคถ้าเป็นไปได้ โดยปกติจะมีความแม่นยำสูงและมีความน่าเชื่อถือจากการออกแบบ

กลยุทธ์ทางเลือก

เมื่อใช้โซลูชันแบบพกพาคุณควรพิจารณากลยุทธ์ทางเลือก: ใช้นาฬิกาโมโนโทนิกหากมีและใช้วิธีการประทับเวลาแทนหากไม่มีนาฬิกาโมโนโทนิกในระบบ

ของ windows

มีบทความดีๆที่ชื่อว่าAcquiring high-resolution time stampบน MSDN เกี่ยวกับการวัดเวลาบน Windows ซึ่งอธิบายรายละเอียดทั้งหมดที่คุณอาจต้องรู้เกี่ยวกับการสนับสนุนซอฟต์แวร์และฮาร์ดแวร์ ในการรับการประทับเวลาที่มีความแม่นยำสูงบน Windows คุณควร:

  • ค้นหาความถี่ตัวจับเวลา (ขีดต่อวินาที) ด้วยQueryPerformanceFrequency :

    LARGE_INTEGER tcounter;
    LARGE_INTEGER freq;    
    
    if (QueryPerformanceFrequency (&tcounter) != 0)
        freq = tcounter.QuadPart;

    ความถี่ของตัวจับเวลาได้รับการแก้ไขในการบูตระบบดังนั้นคุณต้องรับเพียงครั้งเดียว

  • สอบถามค่าเห็บปัจจุบันด้วยQueryPerformanceCounter :

    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 และเวอร์ชันที่ใหม่กว่าในกรณีส่วนใหญ่ แต่คุณยังสามารถใช้โซลูชันทางเลือกสองวิธีบน Windows:

  • GetTickCountระบุจำนวนมิลลิวินาทีที่ผ่านไปนับตั้งแต่ระบบเริ่มทำงาน จะห่อทุกๆ 49.7 วันดังนั้นโปรดใช้ความระมัดระวังในการวัดช่วงเวลาที่นานขึ้น
  • GetTickCount64เป็นเวอร์ชัน 64 บิตGetTickCountแต่สามารถใช้ได้ตั้งแต่ Windows Vista ขึ้นไป

OS X (macOS)

OS X (macOS) มีหน่วยเวลาสัมบูรณ์ของ Mach ซึ่งเป็นตัวแทนของนาฬิกาแบบโมโนโทนิค วิธีที่ดีที่สุดในการเริ่มต้นคือบทความของ Apple Q&A ทางเทคนิค QA1398: Mach Absolute Time Unitsซึ่งอธิบาย (พร้อมตัวอย่างโค้ด) วิธีการใช้ Mach-specific API เพื่อรับเครื่องหมายโมโนโทนิก นอกจากนี้ยังมีคำถามในท้องถิ่นที่เรียกว่าclock_gettime ทางเลือกใน Mac OS Xซึ่งในตอนท้ายอาจทำให้คุณสับสนเล็กน้อยว่าจะทำอย่างไรกับค่าที่เป็นไปได้มากเกินไปเนื่องจากความถี่ของตัวนับถูกใช้ในรูปแบบของตัวเศษและตัวส่วน ตัวอย่างสั้น ๆ เกี่ยวกับการใช้เวลาที่ผ่านไป:

  • รับตัวนับความถี่นาฬิกาและตัวส่วน:

    #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 โดยไม่ให้ล้น .

Linux และ UNIX

การ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;
    }

    ฉันได้ลดเวลาลงเหลือไมโครวินาทีแล้ว

  • คำนวณความแตกต่างกับค่าเวลาก่อนหน้าที่ได้รับในลักษณะเดียวกัน:

    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แต่ขาด แต่มันมีแหล่งที่มาของนาฬิกาเนื่องของตัวเองกำหนดเป็นCLOCK_SGI_CYCLEที่ที่คุณควรจะใช้แทนด้วยCLOCK_MONOTONICclock_gettime

Solaris และ HP-UX

Solaris มีอินเทอร์เฟซตัวจับเวลาความละเอียดสูงของตัวเองgethrtimeซึ่งส่งคืนค่าตัวจับเวลาปัจจุบันเป็นนาโนวินาที แม้ว่า Solaris เวอร์ชันที่ใหม่กว่าอาจมีclock_gettimeแต่คุณสามารถเลือกได้gethrtimeว่าต้องการรองรับ Solaris เวอร์ชันเก่าหรือไม่

การใช้งานทำได้ง่าย:

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

HP-UX ไม่มีclock_gettimeแต่รองรับgethrtimeสิ่งที่คุณควรใช้ในลักษณะเดียวกับ Solaris

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

OS / 2

OS / 2มี API ของตัวเองเพื่อดึงการประทับเวลาที่มีความแม่นยำสูง:

  • ค้นหาความถี่ตัวจับเวลา (ขีดต่อหน่วย) ด้วยDosTmrQueryFreq(สำหรับคอมไพเลอร์ GCC):

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

ตัวอย่างการใช้งาน

คุณสามารถดูที่ไลบรารีplibsysซึ่งใช้กลยุทธ์ที่อธิบายไว้ข้างต้นทั้งหมด (ดูรายละเอียดใน ptimeprofiler * .c)


"ไม่มีโซลูชัน ANSI ที่เหมาะสมและมีความแม่นยำเพียงพอสำหรับปัญหาการวัดเวลา": มี C11 timespec_get: stackoverflow.com/a/36095407/895245
Ciro Santilli 郝海东冠状病六四事件法轮功

1
นี่ยังเป็นวิธีที่ไม่ถูกต้องในการวัดเวลาในการเรียกใช้โค้ด timespec_getไม่ใช่เสียงเดียว
Alexander Saprykin

11

timespec_get จาก C11

ส่งกลับค่าเป็นนาโนวินาทีปัดตามความละเอียดของการนำไปใช้งาน

หน้าตาเหมือนกันหา ANSI จาก clock_gettimePOSIX'

ตัวอย่าง: a printfจะทำทุกๆ 100ms บน Ubuntu 15.10:

#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 ++ Cross-Platform High-Resolution Timer

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

    Linux x86-64 มีการclock_gettimeเรียกใช้ระบบ

    โปรดทราบว่านี่ไม่ใช่วิธีการเปรียบเทียบขนาดเล็กที่ป้องกันความล้มเหลวเนื่องจาก:

    • man clock_gettimeกล่าวว่ามาตรการนี้อาจหยุดทำงานหากคุณเปลี่ยนการตั้งค่าเวลาของระบบบางอย่างในขณะที่โปรแกรมของคุณทำงาน แน่นอนว่านี่น่าจะเป็นเหตุการณ์ที่เกิดขึ้นได้ยากและคุณอาจละเลยมันไปได้

    • สิ่งนี้จะวัดเวลาที่ผนังดังนั้นหากตัวกำหนดตารางเวลาตัดสินใจที่จะลืมงานของคุณดูเหมือนว่าจะทำงานได้นานขึ้น

    ด้วยเหตุผลเหล่านี้getrusage()อาจเป็นเครื่องมือเปรียบเทียบ POSIX ที่ดีกว่าแม้ว่าจะมีความแม่นยำสูงสุดระดับไมโครวินาทีที่ต่ำกว่าก็ตาม

    ข้อมูลเพิ่มเติมที่: Measure time in Linux - time vs clock vs getrusage vs clock_gettime vs gettimeofday vs timespec_get?


นี่คือคำตอบที่ถูกต้อง ณ ปี 2560 แม้แต่ MSVC ก็มีฟังก์ชันนี้ ในแง่ของการเปรียบเทียบให้ค้นหาสิ่งที่อ่านการลงทะเบียนชิป (โปรเซสเซอร์ x86 รุ่นใหม่กว่าพร้อมส่วนขยาย PT และเวอร์ชันใหม่กว่าของ Linux kernel / perf)

4

ความแม่นยำที่ดีที่สุดที่คุณจะได้รับคือการใช้คำสั่ง "rdtsc" x86 เท่านั้นซึ่งสามารถให้ความละเอียดระดับนาฬิกาได้ (แน่นอนว่าต้องคำนึงถึงต้นทุนของการเรียก rdtsc ซึ่งสามารถวัดได้อย่างง่ายดายบน การเริ่มต้นแอปพลิเคชัน)

การจับหลักที่นี่คือการวัดจำนวนนาฬิกาต่อวินาทีซึ่งไม่ควรยากเกินไป


3
คุณอาจต้องกังวลเกี่ยวกับความสัมพันธ์ของโปรเซสเซอร์เนื่องจากในบางเครื่องคุณอาจส่งการเรียก RDTSC ไปยังโปรเซสเซอร์มากกว่าหนึ่งตัวและตัวนับ RDTSC ของพวกเขาอาจไม่ซิงโครไนซ์
Will Dean

1
และยิ่งไปกว่านั้นโปรเซสเซอร์บางตัวไม่มี TSC ที่เพิ่มขึ้นอย่างจำเจ - คิดว่าโหมดประหยัดพลังงานที่ลดความถี่ของ CPU ใช้สำหรับ RDTSC อะไร แต่มากการกำหนดเวลาที่มีการแปลสั้นเป็นมากความคิดที่ดี
snemarch

Btw, core drift ที่กล่าวถึงโดย @WillDean และการใช้ rdtsc เพื่อกำหนดเวลาเป็นสาเหตุที่ทำให้เกมจำนวนมากล้มเหลวในการทำงานบนซีพียู AMD64 แบบมัลติคอร์ (ต้น?) - ฉันต้อง จำกัด ความสัมพันธ์แบบ single-core บน x2 4400+ ของฉันสำหรับ ชื่อเรื่องจำนวนมาก
snemarch

2

คำตอบที่ยอมรับนั้นดีพอ แต่วิธีแก้ปัญหาของฉันนั้นง่ายกว่าฉันแค่ทดสอบใน Linux ใช้ gcc (Ubuntu 7.2.0-8ubuntu3.2) 7.2.0

ใช้ alse gettimeofdayที่tv_secเป็นส่วนหนึ่งของที่สองและtv_usecเป็นmicrosecondsไม่มิลลิวินาที

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วินาทีนั้นเอง


-4

ใต้หน้าต่าง:

SYSTEMTIME t;
GetLocalTime(&t);
swprintf_s(buff, L"[%02d:%02d:%02d:%d]\t", t.wHour, t.wMinute, t.wSecond, t.wMilliseconds);

1
นี่คือ ansi C ตามคำขอหรือไม่?
Gyom
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.