Mesurer l'heure du système avec la fonction getrusage en C

Jinku Hu 12 octobre 2023
  1. Utilisez la fonction getrusage pour mesurer le temps système du programme à un filetage
  2. Utilisez la fonction getrusage pour mesurer le temps système du programme multi-thread
Mesurer l'heure du système avec la fonction getrusage en C

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
Auteur: Jinku Hu
Jinku Hu avatar Jinku Hu avatar

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

Article connexe - C Time