C ++ lấy thời gian mili giây trên Linux - clock () dường như không hoạt động bình thường


102

Trên Windows, clock()trả về thời gian bằng mili giây, nhưng trên hộp Linux này mà tôi đang làm việc, nó làm tròn nó đến 1000 gần nhất nên độ chính xác chỉ ở mức "thứ hai" chứ không phải mức mili giây.

Tôi đã tìm thấy giải pháp với Qt bằng cách sử dụng QTimelớp, khởi tạo một đối tượng và gọi đối tượng start()đó sau đó gọi elapsed()để nhận số mili giây đã trôi qua.

Tôi thật may mắn vì tôi đang làm việc với Qt để bắt đầu, nhưng tôi muốn một giải pháp không dựa vào thư viện của bên thứ ba,

Không có cách tiêu chuẩn để làm điều này?

CẬP NHẬT

Vui lòng không đề xuất Boost ..

Nếu Boost và Qt làm được, chắc chắn đó không phải là phép thuật, phải có tiêu chuẩn gì đó mà họ đang sử dụng!


2
Về chỉnh sửa - nhưng để làm điều đó theo cách di động là một số khó khăn.
Ẩn danh

Câu trả lời:


37

Bạn có thể sử dụng gettimeofday ở đầu và cuối phương thức của mình, sau đó phân biệt hai cấu trúc trả về. Bạn sẽ nhận được một cấu trúc như sau:

struct timeval {
  time_t tv_sec;
  suseconds_t tv_usec;
}

CHỈNH SỬA: Như hai nhận xét bên dưới gợi ý, clock_gettime (CLOCK_MONOTONIC) là lựa chọn tốt hơn nhiều nếu bạn có sẵn nó, hầu như ở khắp mọi nơi hiện nay.

CHỈNH SỬA: Ai đó đã nhận xét rằng bạn cũng có thể sử dụng C ++ hiện đại với std :: chrono :: high_resolution_clock, nhưng điều đó không được đảm bảo là đơn điệu. Thay vào đó, hãy sử dụng stable_clock.


38
khủng khiếp cho công việc nghiêm túc. Các vấn đề lớn hai lần một năm, khi ai đó thực hiện date -s và tất nhiên là đồng bộ hóa NTP. Sử dụng clock_gettime (CLOCK_MONOTONIC,)
AndrewStone

9
@AndrewStone: Thời gian UNIX không thay đổi hai lần mỗi năm. Hoặc thậm chí một lần mỗi năm. Nhưng, có, CLOCK_MONOTONICrất tốt để tránh điều chỉnh thời gian hệ thống được bản địa hóa.
Các cuộc đua ánh sáng trong quỹ đạo

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
Tại sao bạn thêm +0,5 vào sự khác biệt?
Mahmoud Al-Qudsi

19
@Computer Guru, đó là một kỹ thuật phổ biến để làm tròn các giá trị dương. Khi giá trị bị cắt đến một giá trị số nguyên, bất cứ điều gì giữa 0,0 và 0,4999 ... trước khi việc bổ sung bị cắt đến 0, và từ 0,5 đến 0,9999 ... được cắt ngắn để 1.
Mark Ransom

8
tv_usec không phải là mili giây, mà là microcsec giây.
NebulaFox

13
khủng khiếp cho công việc nghiêm túc. Vấn đề lớn hai lần một năm, khi ai đó -s ngày, và đồng bộ quá trình NTP
AndrewStone

14
@AndrewStone đã đúng, sử dụng clock_gettime (2) với CLOCK_REALTIME để so sánh thời gian trên cùng một máy tính. Từ gettimeofday (2) manpage: POSIX.1-2008 marks gettimeofday() as obsolete, recommending the use of clock_gettime(2) instead. @CTT, bạn có thể cập nhật ví dụ bằng cách thay đổi struct timevalđể struct timespec, và gettimeofday(&start, NULL)đến clock_gettime(CLOCK_MONOTONIC, &start)để mọi người không chạy vào rắc rối?
Bobby Powers

58

Xin lưu ý rằng clockkhông phải đo thời gian đồng hồ treo tường. Điều đó có nghĩa là nếu chương trình của bạn mất 5 giây, clocksẽ không nhất thiết phải đo 5 giây mà có thể nhiều hơn (chương trình của bạn có thể chạy nhiều luồng và do đó có thể tiêu tốn nhiều CPU hơn thời gian thực) hoặc ít hơn. Nó đo lường khoảng thời gian CPU được sử dụng. Để thấy sự khác biệt, hãy xem xét mã này

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

Nó xuất ra trên hệ thống của tôi

$ difference: 0

Bởi vì tất cả những gì chúng tôi đã làm là ngủ và không sử dụng bất kỳ thời gian nào của CPU! Tuy nhiên, sử dụng gettimeofdaychúng ta sẽ có được những gì chúng ta muốn (?)

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

Kết quả đầu ra trên hệ thống của tôi

$ difference: 5

Nếu bạn cần độ chính xác cao hơn nhưng muốn tính thời gian của CPU , thì bạn có thể cân nhắc sử dụng getrusagehàm.


⁺¹ về việc đề cập a sleep()- Tôi đã định đặt một câu hỏi (tại sao nó hoạt động tốt cho tất cả mọi người, ngoại trừ tôi ?!) , khi tìm thấy câu trả lời của bạn.
Hi-Angel

18

Tôi cũng giới thiệu các công cụ được cung cấp bởi Boost. Boost Timer được đề cập hoặc hack một cái gì đó từ Boost.DateTime hoặc có thư viện đề xuất mới trong hộp cát - Boost.Chrono : Cái cuối cùng này sẽ thay thế cho Timer và sẽ có:

  • Các tiện ích thời gian của Thư viện chuẩn 0x C ++, bao gồm:
    • Mẫu lớp học duration
    • Mẫu lớp học time_point
    • Đồng hồ:
      • system_clock
      • monotonic_clock
      • high_resolution_clock
  • Mẫu lớp timer, với typedefs:
    • system_timer
    • monotonic_timer
    • high_resolution_timer
  • Đồng hồ và bộ hẹn giờ xử lý:
    • process_clock, ghi lại thời gian thực, CPU người dùng và CPU hệ thống.
    • process_timer, ghi lại thời gian thực, CPU người dùng và CPU hệ thống đã trôi qua.
    • run_timer, báo cáo thuận tiện về | process_timer | các kết quả.
  • Số học hợp lý theo thời gian biên dịch của Thư viện Chuẩn C ++ 0x.

Đây là nguồn của danh sách tính năng


Hiện tại, bạn có thể sử dụng Bộ hẹn giờ tăng cường và sau đó chuyển sang Chrono một cách duyên dáng khi nó được xem xét / chấp nhận.
Ẩn danh

13

Tôi đã viết một Timerlớp học dựa trên câu trả lời của CTT . Nó có thể được sử dụng theo cách sau:

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

Đây là cách triển khai của nó:

#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
Điều này thật tuyệt nhưng "nseconds" gây hiểu nhầm vì thời gian không giữ nano giây, nó giữ micro giây, vì vậy tôi khuyên mọi người nên gọi đây là "useconds".
pho0

Cảm ơn. Đã sửa sai.
Chris Redford

9

Nếu bạn không cần mã có thể di động đến các đơn vị cũ, bạn có thể sử dụng clock_gettime (), nó sẽ cung cấp cho bạn thời gian tính bằng nano giây (nếu bộ xử lý của bạn hỗ trợ độ phân giải đó). Đó là POSIX, nhưng từ năm 2001.


4

clock () thường có độ phân giải khá tệ. Nếu bạn muốn đo thời gian ở mức mili giây, một giải pháp thay thế là sử dụng clock_gettime (), như được giải thích trong câu hỏi này.

(Hãy nhớ rằng bạn cần liên kết với -lrt trên Linux).


4

Với C ++ 11 và std::chrono::high_resolution_clockbạn có thể làm điều này:

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

Đầu ra:

Delta t2-t1: 3 milliseconds

Liên kết đến bản demo: http://cpp.sh/2zdtu


2

clock () không trả về mili giây hoặc giây trên linux. Thông thường clock () trả về micro giây trên hệ thống linux. Cách thích hợp để diễn giải giá trị được trả về bởi clock () là chia nó cho CLOCKS_PER_SEC để tìm ra thời gian đã trôi qua.


không có trong hộp tôi đang làm việc! ngoài ra, tôi đang chia cho CLOCKS_PER_SEC, nhưng điều đó là vô nghĩa vì độ phân giải chỉ giảm xuống thứ hai
hasen 25/02/09

công bằng mà nói, đơn vị micro giây (CLOCKS_PER_SEC là 1000000 trên tất cả các hệ thống POSIX). Chỉ cần nó có độ phân giải giây. :-P.
Evan Teran

1

Điều này sẽ hoạt động ... được thử nghiệm trên 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);
}

Ừ ... chạy nó hai lần và trừ đi ...


1

Trong tiêu chuẩn POSIX clockcó giá trị trả về của nó được xác định theo ký hiệu CLOCKS_PER_SEC và việc triển khai được miễn phí để xác định giá trị này theo bất kỳ cách nào thuận tiện. Với Linux, tôi đã gặp may mắn với times()chức năng này.


1

gettimeofday - vấn đề là giá trị sẽ có thể thấp hơn nếu bạn thay đổi xung nhịp phần cứng (với NTP chẳng hạn) sau một thời gian nó trả về số âm.

Tôi thích tạo lớp học của riêng mình và cập nhật mỗi 10 mili giây, vì vậy cách này linh hoạt hơn và tôi thậm chí có thể cải thiện nó để có người đăng ký.

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;

để làm mới nó, tôi sử dụng 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); 
.....

Nhìn vào setitimer và ITIMER_VIRTUAL và ITIMER_REAL.

Không sử dụng các chức năng báo thức hoặc báo động, bạn sẽ có độ chính xác thấp khi quy trình của bạn gặp khó khăn.


0

Tôi thích thư viện Boost Timer vì sự đơn giản của nó, nhưng nếu bạn không muốn sử dụng thư viện thứ ba, thì việc sử dụng clock () có vẻ hợp lý.


0

Như một bản cập nhật, có vẻ như trên windows clock () đo thời gian trên đồng hồ treo tường (với độ chính xác CLOCKS_PER_SEC)

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

trong khi trên Linux, nó đo thời gian cpu trên các lõi được quy trình hiện tại sử dụng

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

và (nó xuất hiện, và như đã nói bởi các poster ban đầu) thực sự với ít chính xác hơn CLOCKS_PER_SEC, mặc dù có lẽ điều này phụ thuộc vào phiên bản cụ thể của Linux.


0

Tôi thích phương pháp Hola Soy không sử dụng gettimeofday (). Điều đó xảy ra với tôi trên một máy chủ đang chạy, quản trị viên đã thay đổi múi giờ. Đồng hồ đã được cập nhật để hiển thị cùng một giá trị cục bộ (đúng). Điều này khiến hàm time () và gettimeofday () chuyển sang 2 giờ và tất cả các dấu thời gian trong một số dịch vụ bị kẹt.


0

Tôi đã viết một C++lớp bằng cách sử dụng timeb.

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

Chức năng thành viên:

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

Ví dụ sử dụng:

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

Đầu ra trên máy tính của tôi là '19'. Độ chính xác của msTimerlớp là theo thứ tự mili giây. Trong ví dụ sử dụng ở trên, tổng thời gian thực thi mà for-loop chiếm dụng được theo dõi. Thời gian này bao gồm việc chuyển đổi hệ điều hành trong và ngoài bối cảnh thực thi main()do đa nhiệm.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.