C ++ ได้รับเวลามิลลิวินาทีบน Linux - clock () ดูเหมือนจะทำงานไม่ถูกต้อง


102

ใน Windows ให้clock()ส่งคืนเวลาเป็นมิลลิวินาที แต่ในกล่อง Linux นี้ที่ฉันกำลังทำงานอยู่มันจะปัดเศษเป็น 1000 ที่ใกล้ที่สุดดังนั้นความแม่นยำจึงอยู่ที่ระดับ "วินาที" เท่านั้นและไม่ถึงระดับมิลลิวินาที

ฉันพบวิธีแก้ปัญหาด้วย Qt โดยใช้QTimeคลาสสร้างอินสแตนซ์อ็อบเจ็กต์และเรียกstart()ใช้จากนั้นโทรelapsed()เพื่อรับจำนวนมิลลิวินาทีที่ผ่านไป

ฉันโชคดีมากเพราะฉันทำงานกับ Qt เพื่อเริ่มต้น แต่ฉันต้องการโซลูชันที่ไม่ต้องพึ่งพาไลบรารีของบุคคลที่สาม

ไม่มีวิธีมาตรฐานในการทำเช่นนี้หรือไม่?

อัปเดต

กรุณาอย่าแนะนำ Boost ..

ถ้า Boost และ Qt ทำได้แน่นอนว่ามันไม่ใช่เวทย์มนตร์ต้องมีมาตรฐานที่พวกเขาใช้อยู่!


2
เกี่ยวกับการแก้ไข - แต่การทำแบบพกพาก็มีความเจ็บปวดอยู่บ้าง
ไม่ระบุชื่อ

เกี่ยวข้อง: stackoverflow.com/questions/28396014/…
Cole Johnson

คำตอบ:


37

คุณสามารถใช้ gettimeofday ที่จุดเริ่มต้นและจุดสิ้นสุดของวิธีการของคุณแล้วทำให้โครงสร้างผลตอบแทนทั้งสองแตกต่างกัน คุณจะได้โครงสร้างดังต่อไปนี้:

struct timeval {
  time_t tv_sec;
  suseconds_t tv_usec;
}

แก้ไข: ตามที่สองความคิดเห็นด้านล่างแนะนำ clock_gettime (CLOCK_MONOTONIC) เป็นทางเลือกที่ดีกว่ามากหากคุณมีให้ใช้งานซึ่งน่าจะมีอยู่เกือบทุกที่ในทุกวันนี้

แก้ไข: มีคนอื่นแสดงความคิดเห็นว่าคุณสามารถใช้ C ++ สมัยใหม่กับ std :: chrono :: high_resolution_clock ได้ แต่ไม่รับประกันว่าจะเป็นแบบโมโนโทนิค ใช้ steady_clock แทน


38
แย่มากสำหรับการทำงานที่จริงจัง ปัญหาใหญ่ปีละสองครั้งเมื่อมีคนทำวันที่ - และแน่นอนว่าการซิงค์ NTP ใช้ clock_gettime (CLOCK_MONOTONIC,)
AndrewStone

9
@AndrewStone: เวลา UNIX ไม่เปลี่ยนแปลงสองครั้งต่อปี หรือแม้แต่ครั้งเดียวต่อปี. แต่ใช่CLOCK_MONOTONICเหมาะอย่างยิ่งสำหรับการหลีกเลี่ยงการปรับเวลาของระบบที่แปลเป็นภาษาท้องถิ่น
Lightness Races ใน Orbit

138
#include <sys/time.h>
#include <stdio.h>
#include <unistd.h>
int main()
{
    struct timeval start, end;

    long mtime, seconds, useconds;    

    gettimeofday(&start, NULL);
    usleep(2000);
    gettimeofday(&end, NULL);

    seconds  = end.tv_sec  - start.tv_sec;
    useconds = end.tv_usec - start.tv_usec;

    mtime = ((seconds) * 1000 + useconds/1000.0) + 0.5;

    printf("Elapsed time: %ld milliseconds\n", mtime);

    return 0;
}

4
ทำไมคุณถึงบวก +0.5 ในส่วนต่าง?
Mahmoud Al-Qudsi

19
@ คอมพิวเตอร์กูรูมันเป็นเทคนิคทั่วไปในการปัดเศษค่าบวก เมื่อค่าถูกตัดทอนเป็นค่าจำนวนเต็มค่าใด ๆ ที่อยู่ระหว่าง 0.0 ถึง 0.4999 ... ก่อนที่การบวกจะถูกตัดทอนเป็น 0 และระหว่าง 0.5 ถึง 0.9999 ... จะถูกตัดทอนเป็น 1
มาร์คค่าไถ่

8
tv_usec ไม่ใช่มิลลิวินาที แต่เป็นไมโครวินาที
NebulaFox

13
แย่มากสำหรับการทำงานที่จริงจัง ปัญหาใหญ่ปีละสองครั้งเมื่อมีคนทำวันที่ -s และแน่นอนว่า NTP sync
AndrewStone

14
@AndrewStone ถูกต้องใช้ clock_gettime (2) กับ CLOCK_REALTIME เพื่อเปรียบเทียบเวลาบนคอมพิวเตอร์เครื่องเดียวกัน จาก gettimeofday นี้ (2) manpage: POSIX.1-2008 marks gettimeofday() as obsolete, recommending the use of clock_gettime(2) instead. @CTT คุณสามารถอัปเดตตัวอย่างเช่นโดยการเปลี่ยนstruct timevalไปstruct timespecและgettimeofday(&start, NULL)ไปclock_gettime(CLOCK_MONOTONIC, &start)เพื่อให้คนที่ไม่ได้ทำงานเป็นปัญหา?
Bobby Powers

58

โปรดทราบว่าclockไม่ได้วัดเวลานาฬิกาแขวน นั่นหมายความว่าถ้าโปรแกรมของคุณใช้เวลา 5 วินาทีclockจะไม่สามารถวัดได้ 5 วินาทีอย่างจำเป็น แต่อาจมากกว่านั้น (โปรแกรมของคุณสามารถรันหลายเธรดและอาจใช้ CPU มากกว่าเรียลไทม์) หรือน้อยกว่า วัดเวลาโดยประมาณของCPU ที่ใช้ หากต้องการดูความแตกต่างให้พิจารณารหัสนี้

#include <iostream>
#include <ctime>
#include <unistd.h>

int main() {
    std::clock_t a = std::clock();
    sleep(5); // sleep 5s
    std::clock_t b = std::clock();

    std::cout << "difference: " << (b - a) << std::endl;
    return 0;
}

มันออกมาในระบบของฉัน

$ difference: 0

เพราะทั้งหมดที่เราทำคือการนอนหลับและไม่ได้ใช้ CPU เลย! อย่างไรก็ตามการใช้gettimeofdayเราได้รับสิ่งที่เราต้องการ (?)

#include <iostream>
#include <ctime>
#include <unistd.h>
#include <sys/time.h>

int main() {
    timeval a;
    timeval b;

    gettimeofday(&a, 0);
    sleep(5); // sleep 5s
    gettimeofday(&b, 0);

    std::cout << "difference: " << (b.tv_sec - a.tv_sec) << std::endl;
    return 0;
}

ผลลัพธ์ในระบบของฉัน

$ difference: 5

หากคุณต้องการความแม่นยำมากขึ้น แต่ต้องการเวลา CPUคุณสามารถพิจารณาใช้getrusageฟังก์ชันนี้ได้


⁺¹เกี่ยวกับกsleep()- ฉันคิดว่าจะถามคำถามอยู่แล้ว(ทำไมถึงได้ผลดีสำหรับทุกคนยกเว้นฉัน!)เมื่อพบคำตอบของคุณ
Hi-Angel

18

ฉันขอแนะนำเครื่องมือที่นำเสนอโดย Boost ไม่ว่าจะเป็น Boost Timer ที่กล่าวถึงหรือแฮ็คบางสิ่งบางอย่างออกจาก Boost.DateTime หรือมีไลบรารีที่เสนอใหม่ในแซนด์บ็อกซ์ - Boost.Chrono : อันสุดท้ายนี้จะมาแทนที่ Timer และจะมีคุณสมบัติ:

  • ยูทิลิตี้ด้านเวลาของ C ++ 0x Standard Library ได้แก่ :
    • เทมเพลตคลาส duration
    • เทมเพลตคลาส time_point
    • นาฬิกา:
      • system_clock
      • monotonic_clock
      • high_resolution_clock
  • เทมเพลตคลาสtimerพร้อม typedefs:
    • system_timer
    • monotonic_timer
    • high_resolution_timer
  • ประมวลผลนาฬิกาและตัวจับเวลา:
    • process_clockจับภาพเวลาจริงผู้ใช้ CPU และ CPU ของระบบ
    • process_timerจับภาพเวลาจริง CPU ของผู้ใช้และ CPU ของระบบที่ผ่านไป
    • run_timerสะดวกในการรายงาน | process_timer | ผล.
  • เลขคณิตเชิงเหตุผลในการคอมไพล์ตามเวลาของ C ++ 0x Standard Library

นี่คือที่มาของรายการคุณสมบัติ


ในตอนนี้คุณสามารถใช้ Boost Timer จากนั้นย้ายไปยัง Chrono ได้อย่างสง่างามเมื่อได้รับการตรวจสอบ / ยอมรับ
ไม่ระบุชื่อ

13

ฉันได้เขียนTimerระดับขึ้นอยู่กับคำตอบของ CTT สามารถใช้ได้ด้วยวิธีต่อไปนี้:

Timer timer = Timer();
timer.start();
/* perform task */
double duration = timer.stop();
timer.printTime(duration);

นี่คือการใช้งาน:

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
using namespace std;

class Timer {
private:

    timeval startTime;

public:

    void start(){
        gettimeofday(&startTime, NULL);
    }

    double stop(){
        timeval endTime;
        long seconds, useconds;
        double duration;

        gettimeofday(&endTime, NULL);

        seconds  = endTime.tv_sec  - startTime.tv_sec;
        useconds = endTime.tv_usec - startTime.tv_usec;

        duration = seconds + useconds/1000000.0;

        return duration;
    }

    static void printTime(double duration){
        printf("%5.6f seconds\n", duration);
    }
};

2
สิ่งนี้ยอดเยี่ยม แต่ "วินาที" นั้นทำให้เข้าใจผิดเพราะค่าเวลาไม่ถือนาโนวินาทีมันถือเป็นไมโครวินาทีดังนั้นฉันขอแนะนำให้คนอื่นเรียกสิ่งนี้ว่า "useconds"
pho0

ขอบคุณ. ทำการแก้ไข
Chris Redford

9

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


4

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

(โปรดจำไว้ว่าคุณต้องเชื่อมโยงกับ -lrt บน Linux)


4

ด้วย C ++ 11 และstd::chrono::high_resolution_clockคุณสามารถทำได้:

#include <iostream>
#include <chrono>
#include <thread>
typedef std::chrono::high_resolution_clock Clock;

int main()
{
    std::chrono::milliseconds three_milliseconds{3};

    auto t1 = Clock::now();
    std::this_thread::sleep_for(three_milliseconds);
    auto t2 = Clock::now();

    std::cout << "Delta t2-t1: " 
              << std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1).count()
              << " milliseconds" << std::endl;
}

เอาท์พุต:

Delta t2-t1: 3 milliseconds

ลิงก์ไปยังการสาธิต: http://cpp.sh/2zdtu


2

clock () ไม่ส่งคืนมิลลิวินาทีหรือวินาทีบน linux โดยปกติแล้ว clock () จะส่งคืนไมโครวินาทีในระบบ linux วิธีที่เหมาะสมในการตีความค่าที่ส่งคืนตามสัญญาณนาฬิกา () คือหารด้วย CLOCKS_PER_SEC เพื่อหาว่าเวลาผ่านไปเท่าใด


ไม่ได้อยู่ในกล่องที่ฉันกำลังทำอยู่! บวกฉันกำลังหารด้วย CLOCKS_PER_SEC แต่มันไม่มีจุดหมายเพราะความละเอียดเป็นเพียงลงไปที่สอง
Hasen

เพื่อความเป็นธรรมหน่วยคือไมโครวินาที (CLOCKS_PER_SEC คือ 1000000 ในระบบ POSIX ทั้งหมด) เพียงแค่มีความละเอียดเป็นวินาที :- ป.
Evan Teran

1

สิ่งนี้ควรใช้งานได้ ... ทดสอบบนเครื่อง Mac ...

#include <stdio.h>
#include <sys/time.h>

int main() {
        struct timeval tv;
        struct timezone tz;
        struct tm *tm;
        gettimeofday(&tv,&tz);
        tm=localtime(&tv.tv_sec);
        printf("StartTime: %d:%02d:%02d %d \n", tm->tm_hour, tm->tm_min, tm->tm_sec, tv.tv_usec);
}

ใช่ ... เรียกใช้สองครั้งและลบ ...


1

ในมาตรฐาน POSIX clockมีค่าส่งคืนที่กำหนดไว้ในรูปของสัญลักษณ์ CLOCKS_PER_SEC และการนำไปใช้งานนั้นมีอิสระที่จะกำหนดสิ่งนี้ในรูปแบบที่สะดวก ใน Linux ฉันโชคดีกับtimes()ฟังก์ชันนี้


1

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

ฉันชอบที่จะสร้างชั้นเรียนของตัวเองและอัปเดตทุกๆ 10 มิลลิวินาทีดังนั้นวิธีนี้จึงมีความยืดหยุ่นมากกว่าและฉันยังสามารถปรับปรุงให้มีสมาชิกได้อีกด้วย

class MyAlarm {
static int64_t tiempo;
static bool running;
public:
static int64_t getTime() {return tiempo;};
static void callback( int sig){
    if(running){
        tiempo+=10L;
    }
}
static void run(){ running = true;}
};

int64_t MyAlarm::tiempo = 0L;
bool MyAlarm::running = false;

เพื่อรีเฟรชฉันใช้ setitimer:

int main(){
struct sigaction sa; 
struct itimerval timer; 

MyAlarm::run();
memset (&sa, 0, sizeof (sa)); 
sa.sa_handler = &MyAlarm::callback; 

sigaction (SIGALRM, &sa, NULL); 


timer.it_value.tv_sec = 0; 
timer.it_value.tv_usec = 10000; 



timer.it_interval.tv_sec = 0; 
timer.it_interval.tv_usec = 10000; 


setitimer (ITIMER_REAL, &timer, NULL); 
.....

ดูที่ setitimer และ ITIMER_VIRTUAL และ ITIMER_REAL

อย่าใช้ฟังก์ชั่นปลุกหรือ ualarm คุณจะมีความแม่นยำต่ำเมื่อกระบวนการของคุณทำงานหนัก



0

จากการอัปเดตปรากฏว่าบนนาฬิกา windows () วัดเวลานาฬิกาแขวน (ด้วยความแม่นยำ CLOCKS_PER_SEC)

 http://msdn.microsoft.com/en-us/library/4e2ess30(VS.71).aspx

ในขณะที่บน Linux จะวัดเวลาของซีพียูในคอร์ที่ใช้โดยกระบวนการปัจจุบัน

http://www.manpagez.com/man/3/clock

และ (ปรากฏและตามที่ระบุไว้ในผู้โพสต์ต้นฉบับ) ซึ่งมีความแม่นยำน้อยกว่า CLOCKS_PER_SEC แม้ว่าอาจจะขึ้นอยู่กับเวอร์ชันเฉพาะของ Linux


0

ฉันชอบวิธี Hola Soy ที่ไม่ใช้ gettimeofday () มันเกิดขึ้นกับฉันบนเซิร์ฟเวอร์ที่ทำงานอยู่ผู้ดูแลระบบได้เปลี่ยนเขตเวลา นาฬิกาได้รับการอัปเดตเพื่อแสดงค่าท้องถิ่น (ที่ถูกต้อง) เดียวกัน สิ่งนี้ทำให้เวลาของฟังก์ชัน () และ gettimeofday () เลื่อนไป 2 ชั่วโมงและการประทับเวลาทั้งหมดในบริการบางอย่างติดขัด


0

ฉันเขียนC++ชั้นเรียนโดยใช้timeb.

#include <sys/timeb.h>
class msTimer 
{
public:
    msTimer();
    void restart();
    float elapsedMs();
private:
    timeb t_start;
};

ฟังก์ชั่นสมาชิก:

msTimer::msTimer() 
{ 
    restart(); 
}

void msTimer::restart() 
{ 
    ftime(&t_start); 
}

float msTimer::elapsedMs() 
{
    timeb t_now;
    ftime(&t_now);
    return (float)(t_now.time - t_start.time) * 1000.0f +
           (float)(t_now.millitm - t_start.millitm);
}

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

#include <cstdlib>
#include <iostream>

using namespace std;

int main(int argc, char** argv) 
{
    msTimer t;
    for (int i = 0; i < 5000000; i++)
        ;
    std::cout << t.elapsedMs() << endl;
    return 0;
}

เอาต์พุตบนคอมพิวเตอร์ของฉันคือ '19' ความแม่นยำของmsTimerคลาสอยู่ในลำดับมิลลิวินาที ในตัวอย่างการใช้งานข้างต้นเวลาทั้งหมดของการดำเนินการที่ใช้โดยfor-loop จะถูกติดตาม คราวนี้รวมถึงระบบปฏิบัติการที่สลับเข้าและออกบริบทการดำเนินการmain()เนื่องจากการทำงานหลายอย่างพร้อมกัน

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