Mesurer l'heure du système avec la fonction getrusage en C
-
Utilisez la fonction
getrusage
pour mesurer le temps système du programme à un filetage -
Utilisez la fonction
getrusage
pour mesurer le temps système du programme multi-thread
Cet article présentera plusieurs méthodes de mesure de l’heure du système avec la fonction getrusage
en C.
Utilisez la fonction getrusage
pour mesurer le temps système du programme à un filetage
En général, il y a deux composantes de temps dans tout programme en cours d’exécution. L’heure système représente la période pendant laquelle le programme s’exécute en mode noyau et le temps utilisateur, indiquant le temps d’exécution écoulé en mode utilisateur. La somme des deux valeurs est appelée temps de traitement, ce qui est une mesure utile lors de l’optimisation des performances du programme.
La fonction getrusage
récupère plusieurs points de données sur le processus, et l’un d’entre eux est l’heure système représentée par l’objet struc timeval
. getrusage
prend une valeur entière et une adresse de l’objet struct rusage
comme arguments. L’entier spécifie quels threads / processus doivent être mesurés, et il peut avoir les valeurs de macro prédéfinies suivantes RUSAGE_SELF
, RUSAGE_CHILDREN
ou RUSAGE_THREAD
.
D’autre part, la structure rusage
doit être déclarée à l’avance, et l’appel de fonction réussi y stocke les valeurs correspondantes. La structure timeval
contenant deux données membres - secondes et microsecondes pour représenter le temps, nous avons implémenté les fonctions diffUserTime
et diffSystemTime
pour calculer le temps écoulé en secondes.
#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);
}
Production:
loopFunc1 stats:
CPU time: 0.002193 sec user, 0.000000 sec system
loopFunc2 stats:
CPU time: 0.002087 sec user, 0.000190 sec system
Utilisez la fonction getrusage
pour mesurer le temps système du programme multi-thread
La fonction getrusage
peut également récupérer l’heure système utilisée par tous les threads du processus appelant. L’argument RUSAGE_SELF
spécifie cette fonctionnalité, et elle est mutuellement utilisable dans un programme monothread comme vu dans l’exemple précédent.
Dans l’exemple de code suivant, nous créons 16 threads, qui exécutent tous la même fonction loopFunc2
et se terminent. Quoi qu’il en soit, le temps récupéré par l’appel getrusage
est égal au temps écoulé additionné dans tous les threads, y compris ceux qui les ont créés. Pendant ce temps, si l’utilisateur souhaite mesurer le temps système consommé par le thread appelant uniquement, RUSAGE_THREAD
peut être passé comme premier argument. Notez cependant que la valeur RUSAGE_THREAD
est spécifique à Linux, et _GNU_SOURCE
doit être définie avant les fichiers d’en-tête pour l’inclure.
#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);
}
Production:
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