C++ C++;细粒度时间

C++ C++;细粒度时间,c++,c,timer,C++,C,Timer,下面的代码给出0作为函数的运行时。有人能指出错误吗 struct timeval start,end; long seconds,useconds; gettimeofday(&start, NULL); int optimalpfs=optimal(n,ref,count); gettimeofday(&end, NULL); seconds = end.tv_sec - start.tv_sec; useconds = end.tv_usec - start.tv_use

下面的代码给出0作为函数的运行时。有人能指出错误吗

struct timeval start,end;
long seconds,useconds;
gettimeofday(&start, NULL);
int optimalpfs=optimal(n,ref,count);
gettimeofday(&end, NULL);
seconds  = end.tv_sec  - start.tv_sec;
useconds = end.tv_usec - start.tv_usec;
long opt_runtime = ((seconds) * 1000 + useconds/1000.0) + 0.5;
cout<<"\nOptimal Runtime is "<<opt_runtime<<"\n";

请告诉我错误。

这里的浮点和整数混合得很奇怪:

long opt_runtime = ((seconds) * 1000 + useconds/1000.0) + 0.5;
尝试使用:

long opt_runtime = (long)(seconds * 1000 + (float)useconds/1000);

这样,您将在毫秒内得到结果

optimal(…)的执行时间小于
gettimeofday(…)
的粒度。这可能发生在窗户上。在Windows上,典型的粒度高达20毫秒。我已经回答了一个相关的gettimeofday(…)问题。 对于Linux,我问了一下,并得到了一个很好的结果


有关如何获得准确计时的更多信息,请参见SO答案。

我通常会进行如下计算:

long long ss = start.tv_sec * 1000000LL + start.tv_usec;
long long es = end.tv_sec * 1000000LL + end.tv_usec;
那就改变一下

long long microsec_diff = es - ss;
现在根据需要进行转换:

double seconds = microsec_diff / 1000000.;

通常,我不关心最后一步,以微秒为单位进行所有计时。

POSIX 1003.1b-1993为
clock\u gettime()
(和
clock\u getres()
)指定了接口,并提供了使用MON选项时,可以有一种具有
clockid\u t
clock\u单调的时钟类型。
(这样您的计时器就不会受到系统时间调整的影响)。如果您的系统上有可用的功能,那么这些功能将返回一个可能分辨率低至一纳秒的结构,尽管后一个功能将确切地告诉您时钟的分辨率

 struct timespec {
         time_t  tv_sec;         /* seconds */
         long    tv_nsec;        /* and nanoseconds */
 };
您可能仍然需要在循环中多次运行测试函数,以便时钟记录超出其分辨率的任何时间,并且您可能希望运行循环足够的时间,以比时钟分辨率至少多运行一个数量级的时间

请注意,虽然Linux用户显然误读了POSIX.1b规范和/或不理解单调递增时钟的定义,并且他们的
时钟单调
受到系统时间调整的影响,因此您必须使用他们发明的非标准
时钟单调
原始时钟来获得一个真实的时钟单调的时钟

或者,可以使用相关的POSIX.1
timer\u settime()
调用来设置一个正在运行的计时器、一个捕获计时器传递的信号的信号处理程序,以及
timer\u getOverload()
找出信号排队和最终发送之间经过的时间,然后将循环设置为运行直到计时器熄灭,计算所设置时间间隔内的迭代次数,加上超限

当然,在抢占式多任务系统中,这些时钟和计时器即使在进程未运行时也会运行,因此它们对基准测试不是很有用

略为罕见的是可选的POSIX.1-1999
clockid\u t
CLOCK\u-PROCESS\u-CPUTIME\u-ID
,它表示调用进程的CPU时间时钟,给出表示调用进程执行时间量的值。(更罕见的是
CLOCK\u THREAD\u CPUTIME\u ID
clockid\u t
的TCT选项,由
\u POSIX\u THREAD\u CPUTIME
宏指示,该宏表示CPU时钟,给出表示调用线程的执行时间量的值。)

不幸的是,POSIX没有提到这些所谓的CPUTIME时钟是只计算用户时间,还是同时计算进程或线程累积的用户和系统(以及中断)时间,因此,如果分析中的代码进行任何系统调用,那么在内核模式下花费的时间量可能表示,也可能不表示

更糟糕的是,在多处理器系统上,如果进程在执行过程中碰巧从一个CPU迁移到另一个CPU,则CPUTIME时钟的值可能完全是假的。实现这些CPUTIME时钟的计时器也可能在不同的CPU核上以不同的速度运行,在不同的时间运行,从而使它们的含义更加复杂。它们可能不表示与实际挂钟时间相关的任何内容,而只是表示CPU周期的数量(只要始终使用相对时间,并且用户知道执行时间可能因外部因素而不同,则这对于基准测试可能仍然有用)。更糟糕的是,据报道,在Linux CPU上,基于时间戳计数器的CPUTIME时钟甚至可能报告进程休眠的时间

如果您的系统运行良好
getrusage()
系统调用,然后它将有望为您的进程在运行时分别消耗的每个实际用户和系统时间提供一个
struct timeval
。然而,由于这最多只能使您返回到微秒时钟,所以您需要重复运行测试代码足够多的时间,以获得更准确的结果e定时,调用
getrusage()
循环前一次,循环后一次,并计算给定时间之间的差异。对于简单算法,这可能意味着要运行数百万次或更多次。还要注意,在许多系统上,用户时间和系统时间之间的划分是任意进行的,如果在重复循环中单独检查,则然而,如果你的算法没有进行任何系统调用,那么对你的代码执行来说,求和时间增量仍然是一个公平的总时间

顺便说一句,在比较时间值时要小心,这样您就不会像@Nim建议的那样,或者像下面这样(来自NetBSD的
)在字段中溢出或以负值结束:

#定义timersub(tvp、uvp、vvp)\
做{\
(vvp)->电视秒=(tvp)->电视秒-(uvp)->电视秒\
(vvp)->tv_usec=(tvp)->tv_usec-(uvp)->tv_usec\
如果((vvp)->tv_usec<0){\
(vvp)->tv_sec--\
(vvp)->tv_usec+=100000
 struct timespec {
         time_t  tv_sec;         /* seconds */
         long    tv_nsec;        /* and nanoseconds */
 };
    #define timersub(tvp, uvp, vvp)                             \
        do {                                                    \
            (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec;      \
            (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec;   \
            if ((vvp)->tv_usec < 0) {                           \
                (vvp)->tv_sec--;                                \
                (vvp)->tv_usec += 1000000;                      \
            }                                                   \
        } while (0)