Analizando scripts lentos que utilizan Bucles utilizando time, pprofile3/cProfile y kcachegrind

Los bucles son herramientas extremadamente útiles que nos permiten realizar tareas repetitivas, pero hay que utilizarlas con precaución. Analizar las operaciones que realiza un bucle y evitar aquellos que realizan operaciones costosas para el ordenador, es lo que veremos a continuación.

Tiempos de ejecución

Una forma sencilla de comprobar cuanto tarda un script en ejecutarse, es utilizar el comando time. Esto quiere decir que el comando time ejecutará el script y visualizará en pantalla el tiempo que ha tardado este en ejecutarse.

Nos devuelve 3 valores, real, sys, user y cpu.

  • real, es el tiempo real que tardó en ejecutarse el comando, sin importar lo que esté sucediendo en el equipo en ese momento.
  • user, mide el tiempo que se ha dedicado a realizar las operaciones en el espacio de trabajo del usuario.
  • sys, es la cantidad de tiempo dedicado en operaciones de sistema.

Todo el tiempo dedicado a sys y user no siempre se incluirá como tiempo real.

Generador de Perfiles

Para comprobar donde está perdiendo más tiempo nuestro script, existen herramientas llamadas generadores de perfiles (profilers). Estos se encargan de medir todos los recursos utilizados por nuestro código y nos permiten comprender mejor lo qué está sucediendo. Por ejemplo, nos ayudan a comprobar cómo asigna la memoria y cuánto tiempo se emplea en ello.

Cada lenguaje de programación suele tener sus propios generadores de perfiles, por lo que podemos usaremos gprof para analizar un programa escrito en C, el módulo cProfile para analizar un programa escrito en Python.

Por lo que utilizando estas herramientas podemos comprobar qué funciones utiliza nuestro programa, cuantas veces se llama a cada función y cuánto tiempo dedica nuestro programa en cada una de ellas. De esta forma podemos comprobar si una función es llamada innecesariamente o comprobar qué función no es tan rápida como pensábamos.

En este breve tutorial vamos a utilizar pprofile3con un script escrito en Python. Procedemos a instalarlo para poder utilizarlo:

pprofile3 se encargará de generar el perfil detallando todos los procesos y subprocesos que van sucediendo durante la ejecución del script.

  • Con la opción -o le podemos indicar que queremos almacenar la salida de información en un fichero.
  • Con la opción -f indicamos el formato de salida que puede ser callgrind o text.

callgrind es un formato de fichero ASCII no muy fácil de leer pero si de analizar con ciertos herramientas, que veremos a continuación.

Acabamos de generar un informe detallado y podemos abrirlo con cualquier herramienta que admita el formato callgrind.

kcachegrind

Para visualizar y leer más fácilmente los resultados generados por pprofile vamos a utilizar kcachegrind. Esta interfaz gráfica nos permite visualizar y analizar este tipo de ficheros, por lo que vamos a proceder a instalarla:

Una vez instalada podemos comprobar el fichero con formato callgrind.

En la parte inferior derecha podemos comprobar la cantidad de veces que se ha ejecutado cada función en nuestro script y el tiempo que tardan estas en ejecutarse. De esta forma podemos obtener información que nos permite reconocer funciones innecesarias.

El módulo cProfile de Python

El módulo cProfile de Python también nos permite generar perfiles y estas son sus principales ventajas:

  • Tiempos de ejecución de nuestro código.
  • Análisis y comparación de partes del código que necesitan optimización.
  • Cantidad de veces que son llamadas cada función.
  • Exportación de datos

Para poder utilizarlo en nuestros scripts procedemos a importarlo:

La función run() s encarga de analizar y recopilar información durante la ejecución del script y puede tomar hasta 3 argumentos;

  • El código o el nombre de una función a analizar.
  • El fichero de salida.
  • La ordenación.

Veamos un ejemplo en el que analizamos una función:

El resultado que obtenemos será un informe detallado con las siguientes columnas:

  • ncalls, la cantidad de llamadas realizadas.
  • tottime, el tiempo tomado por cada función.
  • percall, el tiempo total.
  • cumtime, tiempo total de funciones y subfunciones (útil si se está utilizando recursividad para llamarlas).
  • percall
  • filename:lineno(function)

Si nuestro código llama a otras funciones, podemos perfilar nuestro código de la siguiente forma:

Para información detallada de este módulo seguir el siguiente enlace.

Deja una respuesta

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.