C ++在Linux上获得毫秒时间— clock()似乎无法正常工作


102

在Windows上,clock()返回时间(以毫秒为单位),但是在我正在使用的Linux机器上,它将时间四舍五入到最接近的1000,因此精度仅达到“秒”级别而不是毫秒级别。

我使用QTime该类找到了Qt的解决方案,实例化了一个对象并start()对其进行调用elapsed(),然后调用以获取经过的毫秒数。

我很幸运,因为我从一开始就与Qt合作,但是我想要一个不依赖第三方库的解决方案,

有没有标准的方法可以做到这一点?

更新

请不要推荐Boost ..

如果Boost和Qt可以做到,那肯定不是魔术,他们必须使用某种标准!


2
关于编辑-但以可移植的方式进行编辑会有些痛苦。
匿名

Answers:


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
糟糕的认真工作。每年两次,每次有人约会时都会出现重大问题-s,当然还有NTP同步。使用clock_gettime(CLOCK_MONOTONIC,)
AndrewStone 2011年

9
@AndrewStone:UNIX时间每年不会更改两次。甚至每年一次。但是,是的,这样CLOCK_MONOTONIC可以避免本地化的系统时间调整。
Lightness Races in 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 09年

19
@Computer Guru,这是舍入正值的常用技术。当该值被截断为整数值,在0.0和0.4999之间什么...之前加入被截断为0,和0.5和0.9999之间...被截断为1
马克兰瑟姆

8
tv_usec不是毫秒,而是微秒。
NebulaFox

13
糟糕的认真工作。每年两次重大问题,某人约会-s,当然还有NTP同步
AndrewStone 2011年

14
@AndrewStone是正确的,使用clock_gettime(2)和CLOCK_REALTIME来比较同一台计算机上的时间。从有gettimeofday(2)手册页:POSIX.1-2008 marks gettimeofday() as obsolete, recommending the use of clock_gettime(2) instead. @CTT,你可以通过改变更新的例子struct timevalstruct 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函数。


mention¹提到一个sleep()-我已经被问到一个问题(为什么它对我以外的所有人都有效?!),当找到您的答案时。
Hi-Angel

18

我也推荐Boost提供的工具。要么提到提到的Boost Timer,要么从Boost.DateTime中破解某些东西,或者在沙箱中提出了一个新的库-Boost.Chrono:这最后一个将替代Timer,并具有以下特点:

  • C ++ 0x标准库的时间实用程序,包括:
    • 类模板 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标准库的编译时有理算法。

这是功能列表的来源


目前,您可以使用Boost Timer,然后在审阅/接受Chrono时正常迁移到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
这很酷,但是“ nseconds”具有误导性,因为timeval不包含纳秒,而是包含微秒,因此我建议人们将其称为“ useconds”。
pho0 2011年

谢谢。更正。
克里斯·雷德福德

9

如果不需要将代码移植到旧的unice中,则可以使用clock_gettime(),它可以为您提供以毫微秒为单位的时间(如果您的处理器支持该分辨率)。是POSIX,但从2001年开始。


4

clock()的分辨率通常很差。如果要以毫秒为单位测量时间,则可以选择使用clock_gettime(),如本问题所述。

(请记住,您需要在Linux上与-lrt链接)。


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

在Linux上,clock()不会返回毫秒或秒。通常,在Linux系统上,clock()返回微秒。解释clock()返回的值的正确方法是将其除以CLOCKS_PER_SEC,以计算经过了多少时间。


不在我正在研究的盒子里!再加上,我感到由CLOCKS_PER_SEC分割,但由于分辨率只有精确到秒这是毫无意义
哈森

公平地说,单位微秒(在所有POSIX系统上,CLOCKS_PER_SEC是1000000)。只是它具有秒分辨率。:-P
埃文·特兰

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-此项目中的clock()不可用-通常返回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。

不要使用警报或警报功能,当您的过程难以完成时,精度会降低。



0

作为更新,似乎在Windows clock()上测量挂钟时间(精度为CLOCKS_PER_SEC)

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

而在Linux上,它可测量当前进程所使用的内核之间的cpu时间

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

和(它的出现,以及由原始的海报说明)实际上较少比CLOCKS_PER_SEC的精度,但也许这依赖于Linux的特定版本。


0

我喜欢不使用gettimeofday()的Hola Soy方法。发生在我正在运行的服务器上,管理员更改了时区。时钟已更新为显示相同(正确)的本地值。这导致函数time()和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()由于多任务而导致操作系统切入和切出执行上下文。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.