使用 clock_gettime(CLOCK_MONOTONIC) 测量经过的时间

Measuring Elapsed Time Using clock_gettime(CLOCK_MONOTONIC)

我必须在多个线程中消耗测量时间。我必须得到这样的输出:

Starting Time | Thread Number

00000000000   |   1

00000000100   |   2

00000000200   |   3

首先,我使用了 gettimeofday,但我看到有一些负数,然后我做了一些研究,了解到 gettimeofday 不能可靠地测量经过的时间。然后我决定使用 clock_gettime(CLOCK_MONOTONIC).

但是,有一个问题。当我用秒来测量时间时,我不能精确地测量时间。当我使用纳秒时,end.tv_nsec 变量的长度不能超过 9 位数字(因为它是一个长变量)。也就是说,当它要移动到第10位时,它仍然保持在9位,实际上数字变小了,导致经过的时间为负数。

这是我的代码:

long elapsedTime;
struct timespec end;
struct timespec start2;
//gettimeofday(&start2, NULL);
clock_gettime(CLOCK_MONOTONIC,&start2);

while(c <= totalCount)
{   
    if(strcmp(algorithm,"FCFS") == 0)
    {
        printf("In SErunner count=%d \n",count);
        if(count > 0)
        {
            printf("Count = %d \n",count);
        
            it = deQueue();
            c++;
            tid = it->tid;

            clock_gettime(CLOCK_MONOTONIC,&end);
            
            usleep( 1000*(it->value));
            elapsedTime = ( end.tv_sec - start2.tv_sec);
            
            printf("Process of thread %d finished with value %d\n",it->tid,it->value);
            fprintf(outputFile,"%ld %d %d\n",elapsedTime,it->value,it->tid+1);
        }
}

不幸的是,timespec 没有微秒变量。如果你能帮助我,我会很高兴。

要计算增量(经过的时间),您需要在两个 timeval 或两个 timespec 结构之间进行减法,具体取决于您正在使用的服务。

对于timeval,有一组操作在struct timeval .h>(例如/usr/include/x86_64-linux-gnu/sys/time.h):

# define timersub(a, b, result)                        \
  do {                                                 \
    (result)->tv_sec = (a)->tv_sec - (b)->tv_sec;      \
    (result)->tv_usec = (a)->tv_usec - (b)->tv_usec;   \
    if ((result)->tv_usec < 0) {                       \
      --(result)->tv_sec;                              \
      (result)->tv_usec += 1000000;                    \
    }                                                  \
  } while (0)

对于 timespec,如果您没有在您的头文件中安装它们,请复制类似于此 source code:

中定义的宏的内容
#define timespecsub(tsp, usp, vsp)                          \
    do {                                                    \
        (vsp)->tv_sec = (tsp)->tv_sec - (usp)->tv_sec;      \
        (vsp)->tv_nsec = (tsp)->tv_nsec - (usp)->tv_nsec;   \
        if ((vsp)->tv_nsec < 0) {                           \
            (vsp)->tv_sec--;                                \
            (vsp)->tv_nsec += 1000000000L;                  \
        }                                                   \
    } while (0)

编写一个辅助函数来计算两个时间规格之间的差异:

int64_t difftimespec_ns(const struct timespec after, const struct timespec before)
{
    return ((int64_t)after.tv_sec - (int64_t)before.tv_sec) * (int64_t)1000000000
         + ((int64_t)after.tv_nsec - (int64_t)before.tv_nsec);
}

如果你想要以微秒为单位,只需将它除以 1000,或者使用:

int64_t difftimespec_us(const struct timespec after, const struct timespec before)
{
    return ((int64_t)after.tv_sec - (int64_t)before.tv_sec) * (int64_t)1000000
         + ((int64_t)after.tv_nsec - (int64_t)before.tv_nsec) / 1000;
}

记得包含 ,这样您就可以使用转换 "%" PRIi64 来打印 int64_t 类型的整数:

    printf("%09" PRIi64 " | 5\n", difftimespec_ns(after, before));

您可以使用一些代码将时间转换为 double 值,例如:

double
clocktime_BM (clockid_t clid)
{
  struct timespec ts = { 0, 0 };
  if (clock_gettime (clid, &ts))
    return NAN;
  return (double) ts.tv_sec + 1.0e-9 * ts.tv_nsec;
}    

返回的 double 值包含以秒为单位的内容。在大多数机器上,double-s 是 IEEE 754 floating point numbers, and basic operations on them are fast (less than a µs each). Read the floating-point-gui.de for more about them. In 2020 x86-64 based laptops and servers have some HPET. Don't expect a microsecond precision on time measurements (since Linux runs many processes, and they might get scheduled at arbitrary times; read some good textbook about operating systems 用于解释)。

(以上代码来自Bismon, funded thru CHARIOT; something similar appears in RefPerSys)

在 Linux 上,请务必阅读 syscalls(2), clock_gettime(2), errno(3), time(7), vdso(7)

考虑研究 Linux kernel and/or of the GNU libc and/or of musl-libc. See LinuxFromScratch and OSDEV and kernelnewbies.

的源代码

注意 一些 32 位计算机上的 The year 2038 problem