Systemzeit mit getrusage Funktion in C messen
-
Verwenden Sie die Funktion
getrusage
, um die Systemzeit eines Single-Threaded-Programms zu messen -
Verwenden Sie die Funktion
getrusage
, um die Systemzeit eines Multithread-Programms zu messen
Dieser Artikel zeigt verschiedene Methoden zur Messung der Systemzeit mit der Funktion getrusage
in C.
Verwenden Sie die Funktion getrusage
, um die Systemzeit eines Single-Threaded-Programms zu messen
Im Allgemeinen gibt es in jedem laufenden Programm zwei Zeitkomponenten. Die Systemzeit stellt den Zeitraum dar, den das Programm im Kernelmodus und in der Benutzerzeit ausführt, und gibt die im Benutzermodus verstrichene Ausführungszeit an. Die Summe beider Werte wird als Prozesszeit bezeichnet. Dies ist ein nützliches Maß für die Optimierung der Programmleistung.
Die Funktion getrusage
ruft mehrere Datenpunkte über den Prozess ab, und einer davon ist die Systemzeit, die als Objekt struc timeval
dargestellt wird. getrusage
verwendet einen ganzzahligen Wert und eine Adresse des Objekts struct rusage
als Argumente. Die Ganzzahl gibt an, welche Threads / Prozesse gemessen werden sollen, und kann die folgenden vordefinierten Makrowerte RUSAGE_SELF
, RUSAGE_CHILDREN
oder RUSAGE_THREAD
haben.
Andererseits sollte die Struktur rusage
im Voraus deklariert werden, und der erfolgreiche Funktionsaufruf speichert die entsprechenden Werte darin. Da die Struktur timeval
zwei Datenelemente enthält - Sekunden und Mikrosekunden zur Darstellung der Zeit - haben wir die Funktionen diffUserTime
und diffSystemTime
implementiert, um die verstrichene Zeit in Sekunden zu berechnen.
#include <stdio.h>
#include <stdlib.h>
#include <sys/resource.h>
#include <unistd.h>
enum { NUM_ITERS = 1000000 };
void loopFunc1(size_t num) {
int tmp = 0;
for (int i = 0; i < num; ++i) {
tmp += 1;
}
}
void *loopFunc2(size_t num) {
for (int i = 0; i < num; ++i) {
getpid();
}
return NULL;
}
float diffUserTime(struct rusage *start, struct rusage *end) {
return (end->ru_utime.tv_sec - start->ru_utime.tv_sec) +
1e-6 * (end->ru_utime.tv_usec - start->ru_utime.tv_usec);
}
float diffSystemTime(struct rusage *start, struct rusage *end) {
return (end->ru_stime.tv_sec - start->ru_stime.tv_sec) +
1e-6 * (end->ru_stime.tv_usec - start->ru_stime.tv_usec);
}
int main() {
struct rusage start, end;
getrusage(RUSAGE_SELF, &start);
loopFunc1(NUM_ITERS);
getrusage(RUSAGE_SELF, &end);
printf("loopFunc1 stats:\n");
printf(" CPU time: %.06f sec user, %.06f sec system\n",
diffUserTime(&start, &end), diffSystemTime(&start, &end));
getrusage(RUSAGE_SELF, &start);
loopFunc1(NUM_ITERS);
getrusage(RUSAGE_SELF, &end);
printf("loopFunc2 stats:\n");
printf(" CPU time: %.06f sec user, %.06f sec system\n",
diffUserTime(&start, &end), diffSystemTime(&start, &end));
exit(EXIT_SUCCESS);
}
Ausgabe:
loopFunc1 stats:
CPU time: 0.002193 sec user, 0.000000 sec system
loopFunc2 stats:
CPU time: 0.002087 sec user, 0.000190 sec system
Verwenden Sie die Funktion getrusage
, um die Systemzeit eines Multithread-Programms zu messen
Die Funktion getrusage
kann auch die Systemzeit abrufen, die von allen Threads im aufrufenden Prozess verwendet wird. Das Argument RUSAGE_SELF
gibt diese Funktion an und kann in einem Programm mit einem Thread gegenseitig verwendet werden, wie im vorherigen Beispiel gezeigt.
Im folgenden Beispielcode erstellen wir 16 Threads, die alle dieselbe Funktion loopFunc2
ausführen und beenden. Unabhängig davon entspricht die vom Aufruf getrusage
abgerufene Zeit der verstrichenen Zeit, die in allen Threads summiert wurde, einschließlich derjenigen, die sie erstellt haben. Wenn der Benutzer nur die vom aufrufenden Thread verbrauchte Systemzeit messen möchte, kann als erstes Argument RUSAGE_THREAD
übergeben werden. Beachten Sie jedoch, dass der Wert RUSAGE_THREAD
Linux-spezifisch ist und _GNU_SOURCE
vor den Header-Dateien definiert werden muss, um ihn einzuschließen.
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <sys/resource.h>
#include <threads.h>
#include <unistd.h>
enum { NUM_ITERS = 1000000, NUM_THREADS = 16 };
void *loopFunc2(size_t num) {
for (int i = 0; i < num; ++i) {
getpid();
}
return NULL;
}
float diffUserTime(struct rusage *start, struct rusage *end) {
return (end->ru_utime.tv_sec - start->ru_utime.tv_sec) +
1e-6 * (end->ru_utime.tv_usec - start->ru_utime.tv_usec);
}
float diffSystemTime(struct rusage *start, struct rusage *end) {
return (end->ru_stime.tv_sec - start->ru_stime.tv_sec) +
1e-6 * (end->ru_stime.tv_usec - start->ru_stime.tv_usec);
}
int main() {
struct rusage start, end;
thrd_t threads[NUM_THREADS];
int rc;
getrusage(RUSAGE_SELF, &start);
for (int i = 0; i < NUM_THREADS; i++) {
rc = thrd_create(&threads[i], (thrd_start_t)loopFunc2, (void *)NUM_ITERS);
if (rc == thrd_error) {
perror("[ERROR] thrd_create() call failed\n");
}
}
loopFunc2(NUM_ITERS);
getrusage(RUSAGE_SELF, &end);
printf("loopFunc2 stats:\n");
printf(" CPU time: %.06f sec user, %.06f sec system\n",
diffUserTime(&start, &end), diffSystemTime(&start, &end));
exit(EXIT_SUCCESS);
}
Ausgabe:
loopFunc2 stats:
CPU time: 0.599556 sec user, 0.233000 sec system
Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.
LinkedIn Facebook