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

时间:2016-09-26 19:03:26

标签: c time parallel-processing openmp gettimeofday

我正在研究一些实现三重嵌套for循环的C代码,以便在使用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)

以下是使用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;

循环需要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;

这有什么理由吗?使用这两个功能时可能会有什么不同?我试图更好地理解这两个功能的本质。

2 个答案:

答案 0 :(得分:3)

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);
    
  3. 轻微:第三,虽然非常微妙的改进,有助于减少位(0.5 usec)的不一致,是开始测试蜱变化。但请注意@Dietrich Epp comment以获得替代改进。

    gettimeofday(&t, NULL);
    do { 
      gettimeofday(&start, NULL);
    } while (start == t);
    
  4. 或者,使用宽整数数学来避免精度问题

    long long elapsed_ns = (1LL*finish1.tv_sec - start1.tv_sec)*1000000000LL + 
        finish1.tv_nsec - start1.tv_nsec;
    

答案 1 :(得分:1)

感谢大家的帮助。原来问题与时间函数没有关系,而是由于在计算结束时间和开始时间之间的差异时没有正确地放置括号。我知道,这是一种虎头蛇和愚蠢的解决方案,但它解决了我的问题。当我使用gettimeofday()时,我这样做是为了计算结果:

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

当我应该这样做时:

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

我正在使用的代码是由其他人编写的,用于使用gettimeofday()函数,他们有#define's:

#define TIME_GET(time) (time).tv_sec+1E-6*(time).tv_usec
#define TIME_GET_RESULT(start,end) TIME_GET(end)-TIME_GET(start)

通过添加括号修改第一个#define修复了我的问题:

#define TIME_GET(time) ((time).tv_sec+1E-6*(time).tv_usec)

当我开始使用clock_gettime()时,我正确地放置了括号,并且没有注意到代码作者对gettimeofday()的#define不是。