【问题标题】:Measuring Elapsed Time Using clock_gettime(CLOCK_MONOTONIC)使用 clock_gettime(CLOCK_MONOTONIC) 测量经过的时间
【发布时间】:2021-03-01 18:22:41
【问题描述】:

我必须在多个线程期间经过测量时间。我必须得到这样的输出:

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 没有微秒变量。如果你能帮助我,我会很高兴的。

【问题讨论】:

  • 阅读clock_gettime(2)time(7)。你可以得到 - 理论上 - 纳秒,一微秒是 1000 纳秒
  • 可以,但是纳秒变量不能超过9位。虽然循环迭代 nd.tv_nsec 在一段时间后变小。像这样:2*10^9, 5*10^9, 8*10^9, 1*10^9, 4*10^9, 7*10^9...。它是这样的,因为在定义中在 struct timespec 中,tv_nsec 被定义为 long。

标签: c linux pthreads clock


【解决方案1】:

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

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

【讨论】:

  • 功能不工作。如果您计算 2s 10ns - 1s 30ns ==> 纳秒的减法是负数。因此,我的回答中的实用宏...
  • @RachidK.:是的,它们确实有效。如果您不同意,请在实践中验证它们。它们起作用的原因是一整秒是 1,000,000,000 纳秒。当纳秒差为负时,该操作相当于将秒减 1 并在(负)纳秒上增加 1,000,000,000。
  • 哦,是的!我错过了。我会回答:-)
【解决方案2】:

要计算 delta(经过的时间),您需要根据您使用的服务在两个 timeval 或两个 timespec 结构之间进行减法。

对于timeval,在中有一组操作来操作struct timeval(例如 /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)

【讨论】:

    【解决方案3】:

    您可以使用以下代码将时间转换为 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-gui.de 了解更多信息。在 2020 年,基于 x86-64 的笔记本电脑和服务器有一些 HPET。不要期望精确到微秒的时间测量(因为 Linux 运行许多 processes,它们可能会在任意时间安排;请阅读一些好的 textbook about operating systems 以获得解释)。

    (以上代码来自Bismon,通过CHARIOT资助;类似的内容出现在RefPerSys

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

    考虑研究 Linux kernel 和/或GNU libc 和/或musl-libc 的源代码。请参阅LinuxFromScratchOSDEVkernelnewbies

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-03-23
      • 2011-04-06
      • 1970-01-01
      • 1970-01-01
      • 2017-07-13
      • 1970-01-01
      • 1970-01-01
      • 2011-10-13
      相关资源
      最近更新 更多