Hoe kan ik de C-code gemakkelijk benchmarken?

Is er een eenvoudige bibliotheek om de tijd te benchmarken die nodig is om een ​​deel van de C-code uit te voeren? Wat ik wil is zoiets als:

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
}

Het zou ook geweldig zijn als je in de bibliotheek veel runs kunt doen, ze kunt middelen en de variantie in timing kunt berekenen!


Antwoord 1, autoriteit 100%

Gebruik de functie clock()gedefinieerd in time.h:

startTime = (float)clock()/CLOCKS_PER_SEC;
/* Do work */
endTime = (float)clock()/CLOCKS_PER_SEC;
timeElapsed = endTime - startTime;

Antwoord 2, autoriteit 85%

In principe is alles wat je wilt een timer met een hoge resolutie. De verstreken tijd is natuurlijk slechts een verschil in tijd en de versnelling wordt berekend door de tijden voor elke taak te delen. Ik heb de code toegevoegd voor een timer met hoge resolutie die zou moeten werken op ten minste Windows en 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

Antwoord 3, autoriteit 5%

Benchmark C-code eenvoudig

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

Eenvoudige benchmark van multi-threaded C-code

Als je een multithreaded programma wilt benchmarken, moet je eerst klok:

Beschrijving

De functie clock() retourneert een benadering van de processortijd
gebruikt door het programma.

Retourwaarde

De geretourneerde waarde is de CPU-tijddie tot nu toe is gebruikt als clock_t; naar
krijg het aantal gebruikte seconden, deel door CLOCKS_PER_SEC. Als de
gebruikte processortijd is niet beschikbaar of de waarde ervan kan niet worden
weergegeven, retourneert de functie de waarde (clock_t)(-1)

Daarom is het erg belangrijk om je elapsed_time te delen door het aantal threadsom de uitvoeringstijd van je functie te krijgen:

#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!

Voorbeeld

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

Compileren met:

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

Uitvoer:

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)

Antwoord 4, autoriteit 2%

Probeer in POSIX getrusage. Het relevante argument is RUSAGE_SELF en de relevante velden zijn ru_utime.tv_sec en ru_utime.tv_usec.


Antwoord 5

Er kunnen bestaande hulpprogramma’s zijn die hierbij helpen, maar ik vermoed dat de meesten een soort van bemonstering of mogelijk injectie zullen gebruiken. Maar om specifieke delen van de code getimed te krijgen, moet u waarschijnlijk oproepen toevoegen aan een timer zoals u in uw voorbeeld laat zien. Als u Windows gebruikt, werkt de high-performance timer. Ik beantwoordde een vergelijkbare vraagen liet voorbeeldcode zien die dat zal doen. Er zijn vergelijkbare methoden voor Linux.

Other episodes