Medir el 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 -
Utilice la función
getrusage
para medir el tiempo del sistema de un programa multiproceso
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
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