Medir el tiempo del sistema con la función getrusage en C

Jinku Hu 12 octubre 2023
  1. Utilice la función getrusage para medir el tiempo del sistema de un programa de un solo hilo
  2. Utilice la función getrusage para medir el tiempo del sistema de un programa multiproceso
Medir el tiempo del sistema con la función getrusage en C

Este artículo demostrará varios métodos sobre la medición del tiempo del sistema con la función getrusage en C.

Utilice la función getrusage para medir el tiempo del sistema de un programa de un solo hilo

Generalmente, hay dos componentes de tiempo en cualquier programa en ejecución. El tiempo del sistema representa el período de ejecución del programa en modo kernel y el tiempo del usuario, lo que indica el tiempo de ejecución transcurrido en modo usuario. La suma de ambos valores se denomina tiempo de proceso, que es una medida útil a la hora de optimizar el rendimiento del programa.

La función getrusage recupera múltiples puntos de datos sobre el proceso, y uno de ellos es el tiempo del sistema representado como un objeto struc timeval. getrusage toma un valor entero y una dirección del objeto struct rusage como argumentos. El número entero especifica qué subprocesos / procesos deben medirse y puede tener los siguientes valores macro predefinidos RUSAGE_SELF, RUSAGE_CHILDREN o RUSAGE_THREAD.

Por otro lado, la estructura rusage debe declararse de antemano, y la llamada de función exitosa almacena los valores correspondientes en ella. Dado que la estructura timeval contiene dos miembros de datos: segundos y microsegundos para representar el tiempo, implementamos las funciones diffUserTime y diffSystemTime para calcular el tiempo transcurrido en segundos.

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

Producción :

loopFunc1 stats:
  CPU time: 0.002193 sec user, 0.000000 sec system
loopFunc2 stats:
  CPU time: 0.002087 sec user, 0.000190 sec system

Utilice la función getrusage para medir el tiempo del sistema de un programa multiproceso

La función getrusage también puede recuperar la hora del sistema utilizada por todos los subprocesos en el proceso de llamada. El argumento RUSAGE_SELF especifica esta característica, y se puede utilizar mutuamente en un programa de un solo subproceso, como se ve en el ejemplo anterior.

En el siguiente código de muestra, creamos 16 subprocesos, todos los cuales ejecutan la misma función loopFunc2 y terminan. Independientemente, el tiempo recuperado por la llamada getrusage es igual al tiempo transcurrido sumado en todos los hilos, incluidos los que los crearon. Mientras tanto, si el usuario desea medir el tiempo del sistema consumido solo por el hilo de llamada, se puede pasar RUSAGE_THREAD como primer argumento. Sin embargo, tenga en cuenta que el valor de RUSAGE_THREAD es específico de Linux y debe definirse _GNU_SOURCE antes de los archivos de encabezado para incluirlo.

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

Producción :

loopFunc2 stats:
  CPU time: 0.599556 sec user, 0.233000 sec system
Autor: 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

Artículo relacionado - C Time