Как я могу легко тестировать код C?

Есть ли простая библиотека для сравнения времени выполнения части кода на 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
}

Также было бы здорово, если бы библиотека позволяла вам делать много прогонов, усредняя их и вычисляя разницу во времени!

5 ответов

Решение

По сути, все, что вам нужно, это таймер высокого разрешения. Прошедшее время - это, конечно, только разница во времени, и ускорение рассчитывается путем деления времени для каждой задачи. Я включил код для таймера высокого разрешения, который должен работать по крайней мере на 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

Используйте функцию clock() определяется в time.h:

startTime = (float)clock()/CLOCKS_PER_SEC;

/* Do work */

endTime = (float)clock()/CLOCKS_PER_SEC;

timeElapsed = endTime - startTime;

Легко протестируйте код 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);
}

Простой тест многопоточного кода C

Если вы хотите протестировать многопоточную программу, вам сначала нужно внимательнее взглянуть на часы :

Описание

Функция clock() возвращает приблизительное время процессора, используемое программой.

Возвращаемое значение

Возвращаемое значение - это процессорное время, используемое до 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!

Пример

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

Скомпилировать с помощью:

      gcc -O3 multithread_benchmark.c -fopenmp && time ./a.out

Выход:

      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)

В POSIX попробуйте getrusage. Соответствующим аргументом является RUSAGE_SELF, а соответствующими полями являются ru_utime.tv_sec и ru_utime.tv_usec.

Могут существовать утилиты, которые помогают с этим, но я подозреваю, что большинство из них будет использовать какую-то выборку или инъекцию. Но чтобы получить определенные разделы кода по времени, вам, вероятно, придется добавить вызовы к таймеру, как показано в вашем примере. Если вы используете Windows, то высокопроизводительный таймер работает. Я ответил на аналогичный вопрос и показал пример кода, который сделает это. Есть похожие методы для Linux.

Другие вопросы по тегам