POSIX 1003.1b-1993 为clock_gettime()(和clock_getres())指定接口,并通过MON 选项提供了一种clockid_t 值为CLOCK_MONOTONIC 的时钟类型(这样您的计时器不受系统时间调整的影响)。如果在您的系统上可用,那么这些函数会返回一个潜在分辨率低至 1 纳秒的结构,尽管后一个函数会准确地告诉您时钟的分辨率。
struct timespec {
time_t tv_sec; /* seconds */
long tv_nsec; /* and nanoseconds */
};
您可能仍需要在循环中多次运行测试函数,以使时钟记录超出其分辨率的任何时间,并且您可能希望循环运行足够多的时间以至少持续一个数量级以上时间比时钟的分辨率。
请注意,尽管显然 Linux 人员误读了 POSIX.1b 规范和/或不理解单调递增时钟的定义,并且他们的 CLOCK_MONOTONIC 时钟受系统时间调整的影响,所以你有使用他们发明的非标准CLOCK_MONOTONIC_RAW 时钟来获得一个真实单调时钟。
或者,可以使用相关的 POSIX.1 timer_settime() 调用来设置一个正在运行的定时器,一个信号处理程序来捕获定时器传递的信号,并使用 timer_getoverrun() 来找出队列之间经过了多少时间信号及其最终传递,然后将循环设置为运行,直到计时器关闭,计算设置的时间间隔内的迭代次数,加上溢出。
当然,在抢占式多任务系统上,这些时钟和计时器即使在您的进程未运行时也会运行,因此它们对于基准测试并不是很有用。
稍微少见的是可选的 POSIX.1-1999 clockid_t 值 CLOCK_PROCESS_CPUTIME_ID,由来自 <time.h> 的 _POSIX_CPUTIME 的存在表示,它表示调用进程的 CPU 时间时钟,给出表示调用进程的执行时间量的值。 (更罕见的是CLOCK_THREAD_CPUTIME_ID 的clockid_t 的TCT 选项,由_POSIX_THREAD_CPUTIME 宏表示,它表示CPU 时钟,给出的值表示调用线程的执行时间。)
不幸的是,POSIX 没有提到这些所谓的 CPUTIME 时钟是否只计算用户时间,或者用户和系统(和中断)时间,由进程或线程累积,所以如果你在分析中的代码进行任何系统调用,那么在内核模式下花费的时间可能会被表示,也可能不会被表示。
更糟糕的是,在多处理器系统上,如果您的进程在执行期间碰巧从一个 CPU 迁移到另一个 CPU,那么 CPUTIME 时钟的值可能完全是虚假的。实现这些 CPUTIME 时钟的计时器也可能在不同的 CPU 内核上以不同的速度运行,并且在不同的时间运行,这使它们的含义进一步复杂化。 IE。它们可能与实际挂钟时间无关,而仅表示 CPU 周期数(只要始终使用相对时间并且用户知道执行时间可能会有所不同,这对于基准测试仍然有用取决于外部因素)。更糟糕的是,据报道,在 Linux CPU TimeStampCounter 上,基于 CPUTIME 时钟甚至可以报告进程已休眠的时间。
如果您的系统有一个运行良好的getrusage() 系统调用,那么它有望为您的进程消耗的每个实际用户和系统时间分别提供一个struct timeval当它运行时。但是,由于这最多会使您回到微秒时钟,因此您需要重复运行测试代码足够多次以获得更准确的时间,在循环之前调用getrusage(),然后再调用一次,并计算差异在给定的时间之间。对于简单的算法,这可能意味着运行它们数百万次,甚至更多。另请注意,在许多系统上,用户时间和系统时间之间的划分有些随意,如果在重复循环中单独检查,其中一个甚至可能出现倒退。但是,如果您的算法没有进行系统调用,那么对时间增量求和仍然应该是您的代码执行的合理总时间。
顺便说一句,在比较时间值时要小心,不要像@Nim 建议的那样,或者像这样(来自 NetBSD 的 <sys/time.h>):
#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)
(您甚至可能更偏执于tv_usec 在范围内)
关于基准测试的另一个重要注意事项:确保实际调用了您的函数,最好检查编译器的汇编输出。在驱动程序循环之外的单独源模块中编译您的函数通常会说服优化器保留调用。另一个技巧是让它返回一个你在循环内分配给定义为volatile的变量的值。