Gibt es eine einfache Bibliothek, um die Zeit zu messen, die zum Ausführen eines Teils des C-Codes benötigt wird? Was ich will, ist so etwas wie:
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
}
Es wäre auch großartig, wenn Sie mit der Bibliothek viele Läufe durchführen, sie mitteln und die Varianz im Timing berechnen könnten!
Verwenden Sie die Funktion clock()
definiert in time.h
:
startTime = (float)clock()/CLOCKS_PER_SEC;
/* Do work */
endTime = (float)clock()/CLOCKS_PER_SEC;
timeElapsed = endTime - startTime;
Im Grunde ist alles, was Sie wollen, ein hochauflösender Timer. Die verstrichene Zeit ist natürlich nur eine Zeitdifferenz und die Beschleunigung wird berechnet, indem die Zeiten für jede Aufgabe geteilt werden. Ich habe den Code für einen hochauflösenden Timer eingefügt, der zumindest unter Windows und Unix funktionieren sollte.
#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
Einfaches Benchmarking von C-Code
#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);
}
Einfacher Benchmark von Multithread-C-Code
Wenn Sie Multithreading-Programme benchmarken möchten, müssen Sie sich das zunächst einmal genauer ansehen Uhr:
Beschreibung
Die Funktion clock() gibt eine Annäherung an die vom Programm verwendete Prozessorzeit zurück.
Rückgabewert
Der zurückgegebene Wert ist die CPU-Zeit bisher als clock_t verwendet; Um die Anzahl der verwendeten Sekunden zu erhalten, dividieren Sie durch CLOCKS_PER_SEC. Ist die verwendete Prozessorzeit nicht verfügbar oder deren Wert nicht darstellbar, liefert die Funktion den Wert (clock_t)(-1)
Daher ist es sehr wichtig, Teilen Sie Ihre elapsed_time durch die Anzahl der Threads um die Ausführungszeit Ihrer Funktion zu erhalten:
#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!
Beispiel
#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);
}
Kompilieren mit:
gcc -O3 multithread_benchmark.c -fopenmp && time ./a.out
Ausgabe:
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)
Versuchen Sie es in POSIX getrusage. Das relevante Argument ist RUSAGE_SELF und die relevanten Felder sind ru_utime.tv_sec und ru_utime.tv_usec.
Möglicherweise gibt es vorhandene Dienstprogramme, die dabei helfen, aber ich vermute, die meisten werden eine Art Probenahme oder möglicherweise Injektion verwenden. Aber um bestimmte Abschnitte des Codes zeitgesteuert zu bekommen, müssen Sie wahrscheinlich Aufrufe zu einem Timer hinzufügen, wie Sie es in Ihrem Beispiel zeigen. Wenn Sie Windows verwenden, funktioniert der Hochleistungstimer. Ich habe eine ähnliche Frage beantwortet und Beispielcode gezeigt, der dies tun wird. Für Linux gibt es ähnliche Methoden.
Gute Frage, das hat mir sehr geholfen.
– Nick Knowlson
22. Juli 2012 um 0:51 Uhr
Alternativen zum programminternen Timing: stackoverflow.com/questions/7456146/…
– Ciro Santilli OurBigBook.com
29. Juni 2015 um 14:01 Uhr
Große geschlossene Linux-Frage: stackoverflow.com/questions/375913/…
– Ciro Santilli OurBigBook.com
29. Juni 2015 um 14:03 Uhr
Wenn Sie ähnliche Arbeiten zweimal im selben Programm ausführen, kann der Compiler möglicherweise zwischen ihnen optimieren. Das Erstellen mehrerer ausführbarer Dateien, bei denen jeder Mikrobench eine einzelne Implementierungsstrategie markiert, ist sicherer (aber umständlicher). Da die gesamte Laufzeit eines Programms der Benchmark ist, ist es einfach, die Ergebnisse von Leistungszählern zu vergleichen
perf stat
und bedeutet, dass Sie externe Timing-Sachen wie verwenden könnentime ./a.out
Anstatt Timing-Code in Ihr C aufzunehmen. Mit Timing-Code im Programm können Sie jedoch Timing-Initialisierungscode vermeiden. Und mehrere Ergebnisse aus einem sind einfacher.– Peter Cordes
12. Juni 2016 um 10:35 Uhr