Esta práctica tiene por objetivo el empleo de temporizadores
que nos permitan medir correctamente los tiempos de
ejecución asociados a programas o segmentos de código.
En Unix, se dispone de temporizadores ejecutables (en concreto time)
que nos proporcionan medidas de los tiempos
de ejecución de programas. Estos temporizadores nos proporcionan
tres medidas de tiempo:
El tiempo real también suele recibir el nombre de
elapsed
time o wall time. Algunos temporizadores también proporcionan
el porcentaje de tiempo que la CPU se ha dedicado al programa. Este porcentaje
viene dado por la relación entre el tiempo de CPU (user + sys)
y el tiempo real, y da una idea de lo cargado que se hallaba el sistema
en el momento de la ejecución del programa.
El grave inconveniente de los temporizadores ejecutables es que no son capaces de proporcionar medidas de tiempo de ejecución de segmentos de código. Para ello, hemos de invocar en nuestros propios programas a un conjunto de temporizadores disponibles en la mayor parte de las librerías de C de Unix, que serán los que nos proporcionen medidas sobre los tiempos de ejecución de trozos discretos de código.
En nuestras prácticas vamos a emplear una función que
actúe de temporizador y que nos proporcione los tiempos de CPU (user,
sys)
y el tiempo real. En concreto, vamos a emplear el procedimiento uswtime
listado a continuación.
#include <sys/resource.h>
#include <sys/time.h>void uswtime(double *usertime, double *systime, double *walltime)
{
double mega = 1.0e-6;
struct rusage buffer;
struct timeval tp;
struct timezone tzp;getrusage(RUSAGE_SELF, &buffer);
gettimeofday(&tp, &tzp);
*usertime = (double) buffer.ru_utime.tv_sec +
1.0e-6 * buffer.ru_utime.tv_usec;
*systime = (double) buffer.ru_stime.tv_sec +
1.0e-6 * buffer.ru_stime.tv_usec;
*walltime = (double) tp.tv_sec + 1.0e-6 * tp.tv_usec;
}
Este procedimiento en realidad invoca a dos funciones de Unix:
getrusage
y gettimeofday. La primera de ellas nos proporciona el tiempo de
CPU, tanto de usuario como de sistema, mientras que la segunda nos proporciona
el tiempo real (wall time). Estas dos funciones son las que disponen de
mayor resolución de todos los temporizadores disponibles en Unix.
Modo de Empleo:
La función uswtime se puede emplear para medir los tiempos de ejecución de determinados segmentos de código en nuestros programas. De forma esquemática, el empleo de esta función constaría de los siguientes pasos:
1.- Invocar a uswtime para fijar el instante a partir del cual se va a medir el tiempo.El modo de empleo que se acaba de describir se puede ver claramente en el siguiente ejemplo, en el que se mide los tiempos de ejecución (de CPU usuario y sistema, y wall time) de2.- Ejecutar el código cuyo tiempo de ejecución se desea medir.uswtime(&utime0, &stime0, &wtime0);
3.- Invocar a uswtime para establecer el instante en el cual finaliza la medición
del tiempo de ejecución.4.- Calcular los tiempos de ejecución como la diferencia entre la primera y segundauswtime(&utime1, &stime1, &wtime1);
invocación a uswtime:real: wtime1 - wtime0
user: utime1 - utime0
sys : stime1 - stime0El porcentaje de tiempo dedicado a la ejecución de ese segmento de código
vendría dado por la relación CPU/Wall:CPU/Wall = (user + sys) / real x 100 %
Ejecución de la práctica:
main()
{
double utime0, stime0, wtime0,
utime1, stime1, wtime1;
register int i,j,k,a;/* ---- Primera invocación a la función. ---- */
uswtime(&utime0, &stime0, &wtime0);/* ---- Segmento de código cuyo tiempo de ejecución se desea medir. --- */
for(i=0; i<1000; i++)
for(j=0; j<1000; j++)
for(k=0; k<100; k++)
a++;/* ---- Segunda invocación a la función. ---- */
uswtime(&utime1, &stime1, &wtime1);/* --- Cálculo del tiempo de ejecución e impresión de resultados. --- */
printf("\n");
printf("real %.3f\n", wtime1 - wtime0);
printf("user %.3f\n", utime1 - utime0);
printf("sys %.3f\n", stime1 - stime0);
printf("\n");
printf("CPU/Wall %.3f %% \n",
100.0 * (utime1 - utime0 + stime1 - stime0) / (wtime1 - wtime0));
printf("\n");
}
1.- Compile el programa anterior con el compilador
gcc.
2.- Ejecute el programa.
3.- Ejecute de nuevo el programa invocando, además,
al temporizador ejecutable "time", y compare los resultados.
¿Existe diferencia entre los tiempos proporcionados por el propio
programa y los proporcionados por "time" ??
... ¿A qué cree que se debe esa diferencia?
4.- A continuación implemente los códigos
que se relacionan en la siguiente práctica: Mecanismos
Básicos de
Optimización de Código, y mida los
tiempos de ejecución de los distintos segmentos de códigos
mediante
el empleo de la función uswtime, tal y como se describe en el correspondiente
guión de prácticas.