如何轻松地对C代码进行基准测试?

Mik*_*ike 50 c benchmarking

是否有一个简单的库来衡量执行部分C代码所需的时间?我想要的是:

int main(){
    benchmarkBegin(0);
    //Do work
    double elapsedMS = benchmarkEnd(0);

    benchmarkBegin(1)
    //Do some more work
    double elapsedMS2 = benchmarkEnd(1);

    double speedup = benchmarkSpeedup(elapsedMS, elapsedMS2); //Calculates relative speedup
}
Run Code Online (Sandbox Code Playgroud)

如果图书馆允许你进行多次运行,平均它们并计算时间差异,这也会很棒!

Joe*_*Joe 38

基本上,你想要的只是一个高分辨率计时器.经过的时间当然只是时间的差异,并且通过除以每个任务的时间来计算加速.我已经包含了一个高分辨率计时器的代码,至少应该在windows和unix上运行.

#ifdef WIN32

#include <windows.h>
double get_time()
{
    LARGE_INTEGER t, f;
    QueryPerformanceCounter(&t);
    QueryPerformanceFrequency(&f);
    return (double)t.QuadPart/(double)f.QuadPart;
}

#else

#include <sys/time.h>
#include <sys/resource.h>

double get_time()
{
    struct timeval t;
    struct timezone tzp;
    gettimeofday(&t, &tzp);
    return t.tv_sec + t.tv_usec*1e-6;
}

#endif
Run Code Online (Sandbox Code Playgroud)

  • 是的,这就是为什么我用狡猾的词"可能"和"经常"来限定我的评论;)顺便说一下,如果需要挂钟时间*,那么`clock_gettime(CLOCK_MONOTONIC,...)`是一个更好的选择,因为与`gettimeofday`不同,它不会受到定时间隔期间系统时钟变化的影响. (9认同)
  • Wallclock时间(由`gettimeofday`返回)可能没那么有用 - `clock_gettime(CLOCK_PROCESS_CPUTIME_ID,...)`通常是那里想要的. (6认同)
  • @caf:一个程序使用非常少的CPU时间但是花费大量时间进行阻塞I/O或等待异步I/O仍然会被用户认为很慢.CPU时间和挂钟时间都很重要. (4认同)

小智 37

使用以下clock()定义的函数time.h:

startTime = (float)clock()/CLOCKS_PER_SEC;

/* Do work */

endTime = (float)clock()/CLOCKS_PER_SEC;

timeElapsed = endTime - startTime;
Run Code Online (Sandbox Code Playgroud)

  • 这应该是公认的答案,而不是 Windows 特定的答案! (4认同)

Ant*_*REL 6

轻松对 C 代码进行基准测试

#include <time.h>

int main(void) {
  clock_t start_time = clock();

  // code or function to benchmark

  double elapsed_time = (double)(clock() - start_time) / CLOCKS_PER_SEC;
  printf("Done in %f seconds\n", elapsed_time);
}
Run Code Online (Sandbox Code Playgroud)

多线程 C 代码的简单基准测试

如果您想对多线程程序进行基准测试,您首先需要仔细查看时钟

描述

Clock() 函数返回程序使用的处理器时间的近似值。

返回值

返回的值是迄今为止使用的CPU时间clock_t;要获取使用的秒数,请除以 CLOCKS_PER_SEC。如果所使用的处理器时间不可用或其值无法表示,则该函数返回值 (clock_t)(-1)

因此,将elapsed_time 除以线程数以获得函数的执行时间非常重要:

#include <time.h>
#include <omp.h>

#define THREADS_NB omp_get_max_threads()

#pragma omp parallel for private(i) num_threads(THREADS_NB)
clock_t start_time = clock();

// code or function to benchmark

double elapsed_time = (double)(clock() - start_time) / CLOCKS_PER_SEC;
printf("Done in %f seconds\n", elapsed_time / THREADS_NB); // divide by THREADS_NB!
Run Code Online (Sandbox Code Playgroud)

例子

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
#include <omp.h>

#define N 20000
#define THREADS_NB omp_get_max_threads()

void init_arrays(double *a, double *b) {
  memset(a, 0, sizeof(a));
  memset(b, 0, sizeof(b));
  for (int i = 0; i < N; i++) {
    a[i] += 1.0;
    b[i] += 1.0;
  }
}

double func2(double i, double j) {
  double res = 0.0;

  while (i / j > 0.0) {
    res += i / j;
    i -= 0.1;
    j -= 0.000003;
  }
  return res;
}

double single_thread(double *a, double *b) {
  double res = 0;
  int i, j;
  for (i = 0; i < N; i++) {
    for (j = 0; j < N; j++) {
      if (i == j) continue;
      res += func2(a[i], b[j]);
    }
  }
  return res;
}

double multi_threads(double *a, double *b) {
  double res = 0;
  int i, j;
  #pragma omp parallel for private(j) num_threads(THREADS_NB) reduction(+:res)
  for (i = 0; i < N; i++) {
    for (j = 0; j < N; j++) {
      if (i == j) continue;
      res += func2(a[i], b[j]);
    }
  }
  return res;
}

int main(void) {
  double *a, *b;
  a = (double *)calloc(N, sizeof(double));
  b = (double *)calloc(N, sizeof(double));
  init_arrays(a, b);

  clock_t start_time = clock();
  double res = single_thread(a, b);
  double elapsed_time = (double)(clock() - start_time) / CLOCKS_PER_SEC;
  printf("Default:  Done with %f in %f sd\n", res, elapsed_time);

  start_time = clock();
  res = multi_threads(a, b);
  elapsed_time = (double)(clock() - start_time) / CLOCKS_PER_SEC;
  printf("With OMP: Done with %f in %f sd\n", res, elapsed_time / THREADS_NB);
}
Run Code Online (Sandbox Code Playgroud)

编译:

gcc -O3 multithread_benchmark.c -fopenmp && time ./a.out
Run Code Online (Sandbox Code Playgroud)

输出:

Default:  Done with 2199909813.614555 in 4.909633 sd
With OMP: Done with 2199909799.377532 in 1.708831 sd

real    0m6.703s (from time function)
Run Code Online (Sandbox Code Playgroud)

  • 您不是假设所有线程都可以始终充分利用所有核心吗?因此,如果存在任何同步开销,您就低估了实时量。如果您想要实时,请请求实时(使用“clock_gettime”),并在空闲系统上进行测试。然后,您可以“比较”该实时时间内使用的 CPU 时间的总 CPU 秒数。或者最大限度地减少启动开销,并使基准测试重复足以主导整个运行时间,然后“perf stat”您的整个程序,并将为您完成所有这些工作,包括显示“任务时钟”和使用的 3.800 个 CPU 等。 (2认同)