clock_gettime() 对比 gettimeofday() 用于测量 OpenMP 执行时间

Sha*_*man 5 c parallel-processing time openmp gettimeofday

我正在编写一些 C 代码,它实现了一个三重嵌套 for 循环来计算矩阵乘法,同时使用 OpenMP 对其进行并行化。我试图准确地测量从 for 循环开始到结束所花费的时间。到目前为止,我一直在使用 gettimeofday(),但我注意到有时感觉它没有准确记录执行 for 循环所花费的时间。似乎是在说它比实际花费的时间更长。

这是原始代码:

struct timeval start end;
double elapsed;

gettimeofday(&start, NULL);
#pragma omp parallel for num_threads(threads) private(i, j, k)
for(...)
{
 ...
 for(...)
 {
  ...
  for(...)
  {
   ...
  }
 }
}

gettimeofday(&end, NULL);
elapsed = (end.tv_sec+1E-6*end.tv_usec) - (start.tv_sec+1E-6*start.tv_usec)
Run Code Online (Sandbox Code Playgroud)

这是使用clock_gettime()的相同代码:

 struct timespec start1, finish1;
 double elapsed1;

clock_gettime(CLOCK_MONOTONIC, &start1);

  #pragma omp parallel for num_threads(threads) private(i, j, k)
    for(...)
    {
     ...
     for(...)
     {
      ...
      for(...)
      {
       ...
      }
     }
    }

clock_gettime(CLOCK_MONOTONIC, &finish1);
elapsed1 = (finish1.tv_sec - start1.tv_sec);
elapsed1 += (finish1.tv_nsec - start1.tv_nsec)/1000000000.0;
Run Code Online (Sandbox Code Playgroud)

循环需要 3-4 秒才能完成,我尝试同时使用两种时间测量,使用 gettimeofday() 的结果几乎总是比 clock_gettime() 的结果长,有时比我的结果长一秒多正在使用clock_gettime():

struct timespec start1, finish1;
double elapsed1;

struct timeval start end;
double elapsed;

clock_gettime(CLOCK_MONOTONIC, &start1);
gettimeofday(&start, NULL);

  #pragma omp parallel for num_threads(threads) private(i, j, k)
    for(...)
    {
     ...
     for(...)
     {
      ...
      for(...)
      {
       ...
      }
     }
    }

gettimeofday(&end, NULL);
clock_gettime(CLOCK_MONOTONIC, &finish1);

elapsed = (end.tv_sec+1E-6*end.tv_usec) - (start.tv_sec+1E-6*start.tv_usec)

elapsed1 = (finish1.tv_sec - start1.tv_sec);
elapsed1 += (finish1.tv_nsec - start1.tv_nsec)/1000000000.0;
Run Code Online (Sandbox Code Playgroud)

是否有一个原因?使用这两个函数时可能会导致什么不同?我试图更好地了解这两个函数的性质。

chu*_*ica 5

elapsed = (end.tv_sec+1E-6*end.tv_usec) - (start.tv_sec+1E-6*start.tv_usec) 当减去两个都很大的值时,很容易丢失精度。

  1. 使用elapsed = (end.tv_sec - start.tv_sec) - (start.tv_usec- end.tv_usec)/1E6. 这就像 OP 的第二个和第三个代码,但不是第一个。

  2. 公平地说,以一致的顺序获得时间以消除偏见。

    clock_gettime(CLOCK_MONOTONIC, &start1);
    gettimeofday(&start, NULL);
    
    ...
    
    // gettimeofday(&end, NULL);
    // clock_gettime(CLOCK_MONOTONIC, &finish1);
    clock_gettime(CLOCK_MONOTONIC, &finish1);
    gettimeofday(&end, NULL);
    
    Run Code Online (Sandbox Code Playgroud)
  3. 次要:第三个虽然非常微妙的改进有助于减少一点点不一致(0.5 微秒),是在刻度变化时开始测试。但请注意@Dietrich Epp对替代改进的评论

    gettimeofday(&t, NULL);
    do { 
      gettimeofday(&start, NULL);
    } while (start == t);
    
    Run Code Online (Sandbox Code Playgroud)

或者,使用宽整数数学来避免精度问题

long long elapsed_ns = (1LL*finish1.tv_sec - start1.tv_sec)*1000000000LL + 
    finish1.tv_nsec - start1.tv_nsec;
Run Code Online (Sandbox Code Playgroud)

  • 这如何解决 >1 s 差异的问题? (2认同)