El OProfile es una herramienta
para hacer profiling con una serie de características que lo diferencian del
GNU gprof. Si
tienes curiosidad o un momento de aburrimiento, sigue leyendo.
Índice
1. Mmm, profiling… ¿mande?
1.1. Ventajas y desventajas del método clásico
1.2. Cuándo usar OProfile
2. Cómo funciona OProfile
2.1. Eventos
3. Manos a la obra
3.1. Configuración del kernel
3.2. Instalación de las herramientas
3.3. Profiling, mayormente
1. Mmm, profiling… ¿mande?
La traducción más próxima a este tecnicismo sería perfilar, dado que
consiste en obtener un perfil de ejecución de nuestros programas que nos indique
en qué partes se está utilizando la mayoría del tiempo. Una actividad muy
recomendable a realizar antes de ir ciegamente a optimizar un programa pues
este perfilamiento[1] nos puede dar pistas de, en el caso de que sea necesario optimizar
código, dónde serán más notorias las mejoras.
Para obtener esta información de profiling lo que se suele hacer es
interrumpir la ejecución del programa de forma periódica y, en cada sample,
recolectar información diversa para analizar a posteriori. Se pueden tomar,
a mi conocer, dos alternativas:
que se ejecuta. Por ejemplo, la clásica combinación GCC con parámetro -pg y
gprof.
(normalmente hardware y kernel) para ir tomando muestras del estado de la
ejecución. OProfile lo hace así.
1.1. Ventajas y desventajas del método clásico
Ninguna de las dos opciones es mejor que la otra en todos los casos. Utilizar
gprof es muy
cómodo cuando sólo queremos buscar las funciones que mayor porcentaje de
ejecución se llevan y disponemos del código fuente, tiempo y ganas para compilar
el programa[2].
Pero gprof
no da una información de tiempo y recursos (user, system, elapsed) demasiado
fiable. Esto es culpa de la escala de tiempo que utiliza; la comprobación fácil
es medir los tiempos de un programa instrumentalizado con el comando
time(1) y compararlo con los
resultados que muestra
gprof.
1.2. Cuándo usar OProfile
OProfile no es tan cómodo de usar como
gprof, pero es
mucho más potente en algunos aspectos. Por ejemplo,
OProfile es capaz de perfilar binarios
NO instrumentalizados y librerías dinámicas. Es más, incluso puede
utilizarse para analizar la ejecución del propio kernel Linux.
Además, no sólo es capaz de obtener información acerca de consumo de CPU sino
también puede sacar otras estadísticas como fallos en algunos niveles de
cache[3], predicciones de
salto acertadas, instrucciones SIMD ejecutadas, fallos del TLB, etc. Pero
cuidado, las posibilidades varían de un procesador a otro como veremos más
adelante.
2. Cómo funciona OProfile
Algunos procesadores modernos incluyen contadores hardware del rendimiento
que se van incrementando a medida que ocurren eventos específicos en la CPU.
OProfile aprovecha estos contadores para
indicar a la CPU qué eventos quiere monitorizar y a qué intervalos. Cuando un
contador alcanza un cierto valor la CPU interrumple la ejecución actual para que
OProfile pueda guardar la información de
ese mismo sample.
Pongamos un ejemplo. Digamos que configuramos
OProfile para que vaya controlando los
ciclos de reloj que transcurren en la ejecución y le decimos que tome muestras
cada 500000 ciclos. Aquí cada evento es un ciclo de reloj, con lo que el
contador se incrementa a cada ciclo de ejecución de la CPU. Cuando el contador
alcance el valor 500000 se interrumpla la ejecución actual para dar paso al
profiler; este recolecta toda la información que necesita, resetea el contador
de ciclos y reanuda la ejecución en el punto en que se interrumpió. Más adelante
veremos cómo configurar el tamaño del sample para cada tipo de evento,
nótese ahora que cuando aumenta el número que indicamos al contador perdemos
precisión; pero, para este caso en concreto, no deberíamos establecer valores
muy bajos[4] porque se estaría
interrumpiendo la ejecución cada pocos ciclos con lo que el sistema se vendría
abajo.
En realidad, el tema de los contadores no funciona exactamente así pero es la
mejor forma de entenderlo para poder usar la información
OProfile más provechosamente.
Dado que OProfile depende
totalmente del soporte hardware que haya debajo, las posibilidades de
monitorización varían mucho de un procesador a otro. Esto también limita la
portabilidad. En este enlace se
puede encontrar un listado de los procesadores soportados.
2.1. Eventos
Hay un concepto importante que no se ha aclarado del todo: los eventos.
Un evento está asociado a un recurso hardware del que se puede obtener
información referente a la ejecución y su rendimiento. Cada evento puede
englobar distintos contadores que se activan o desactivan mediante una máscara.
OProfile es capaz de rastrear varios
contadores de un mismo evento e incluso varios eventos distintos a la vez hasta
un cierto límite que varía en función del procesador sobre el que se esté
trabajando.
3. Manos a la obra
Ahora paso a explicar rápidamente los pasos a realizar para configurar
OProfile y cómo hacer el profiling. Para
simplificar boy a limitar nuestro entorno de trabajo a
Debian GNU/Linux con un kernel de la rama 2.6. Para
otras distribuciones lo único que cambia es la instalación del
OProfile.
Utilizar OProfile no es difícil pero
sí tedioso para algunas tareas debido al modelo de trabajo que tiene.
3.1. Configuración del kernel
OProfile se compone de varias partes.
Una de ellas es un módulo del kernel que permiten a las otras componentes
acceder a ciertos privilegios de la CPU. Con la llegada del kernel 2.6 el
soporte para OProfile ya viene de serie
en los kernels vanilla. Con esta nueva rama del kernel también han sido
soportadas nuevas arquitecturas. Aunque hay otras (IA64) que únicament están
soportadas en la rama 2.4. Si tu kernel es 2.4 es necesario compilar un módulo
aparte. Yo sólo explicaré cómo utilizarlo con un kernel 2.6 porque es la única
rama en la que lo he probado.
Pues con cualquiera de los sabores de configuración, asegúrate de tener
activada la opción de soporte para profiling del kernel:
#
# Profiling support
#
CONFIG_PROFILING=y
CONFIG_OPROFILE=m
Si utilizáis make menuconfig, basta con ir al submenú Profiling
support en el propio menú general y seleccionar:
[*] Profiling support (EXPERIMENTAL)
<M> Oprofile system profiling (EXPERIMENTAL)
Compilarlo como módulo o integrado es cosa tuya.
3.2. Instalación de las herramientas
La vida es fácil con Debian:
etanol@om:~$ sudo apt-get install oprofile
3.3. Profiling, mayormente
Como ya he mencionado, OProfile son
varias componentes. Aparte del módulo del kernel hay un demonio y unas cuantas
herramientas (binarios) de control y visualización. La carga/descarga del módulo
así como el control del demonio se realizan mediante el comando opcontrol.
Este comando necesia privilegios de root por lo que puedes ejecutarlo como
superusuario, asignarle el bit SUID o bien utilizar
sudo.
Para simplificar voy a suponer que se está ejecutando como usuario root en esta demostración, aunque el prompt indique lo contrario 😉
Primero de todo hay que inicializar todo el tinglado, esto se hace con el
comando:
etanol@om:~$ opcontrol –init
etanol@om:~$ opcontrol –reset
Esto carga el módulo del kernel y limpia las estadísticas de ejecuciones
anteriores. En este estado ya podemos obtener información sobre los eventos
soportados en la CPU que estamos trabajando gracias al comando ophelp sin
argumentos. A continuación tenemos que configurar los eventos del procesador a
capturar. Por ejemplo, tenemos un Pentium IV y queremos seguir la pista de
los fallos en memoria cache de nivel 2:
etanol@om:~$ opcontrol –setup –no-vmlinux –event=BSQ_CACHE_REFERENCE:7500:0x100:0:1
El parámetro –no-vmlinux indica que NO queremos que tenga en cuenta
el código del kernel. El parámetro –event activa el seguimiento de un
evento en particular, en nuestro caso el nombre del evento es
BSQ_CACHE_REFERENCE; esta información está disponible en ophelp. El
número 7500 es el número de eventos que provocan una interrupción en la
ejecución de la CPU, es decir, el tamaño del sample. El número 0x100 es
la máscara que habilita los contadores a utilizar, si queremos activar más de un
contador para este evento basta con calcular el OR de las máscaras que
activan cada uno de los contadores; esto también está disponible en ophelp
para cada evento. Los dos últimos números indican si queremos contar eventos en
modo kernel (nivel de privilegio en la CPU) y en modo usuario respectivamente.
En resumen, con el argumento anterior hemos indicado que
OProfile debe interrumpir la CPU cada
7500 fallos de cache de segundo nivel que se hayan producido en modo usuario.
Tras esto vamos a empezar a perfilar 😛
etanol@om:~$ opcontrol –start
etanol@om:~$ ./mi_programa_a_investigar
etanol@om:~$ opcontrol –stop
En este punto ya tenemos información de profiling almacenada en algún lugar
de nuestro disco duro. Ahora el abanico de posibilidades para visualizar la
información se abre. Aquí hay dos comandos que nos interesan: opreport y
opannotate. El primero da la información similar a la que da
gprof[5]. Al
segundo comando hay que indicarle qué fichero en particular debe anotar. Anotar
consiste en mostrar información de profiling por línea de código en lugar de por
función. Para que el opannotate funcione es necesario que el/los binario/s
que queramos anotar haya/n sido compilado/s con los símbolos de debug
(opción -g del GCC).
No quiero enrrollarme mucho en cómo se usan los comandos de visualización de datos porque podréis encontrar ejemplos más directos aquí.
Una vez terminada la sesión de profiling, podemos recoger el chiringuito:
etanol@om:~$ opcontrol –shutdown
etanol@om:~$ opcontrol –deinit
Y esto ha sido todo por hoy, amiguitos del progresif. Si queréis saber más o
tenéis dudas, ya sabéis: RTFM.
[1] En el resto del artículo usaré el término en
inglés
[2] Hay programas que son poco afines ser recompilados: xorg,
kde, gnome…
[3] Normalmente cualquiera salvo el nivel 1
[4] Muy bajo sería inferior a 75000
[5] Incluso puede mostrar los árboles de llamadas a funciones
Este post ha sido traido de forma automatica desde https://web.archive.org/web/20140625063149/http:/bulma.net/body.phtml?nIdNoticia=2238 por un robot nigromante, si crees que puede mejorarse, por favor, contactanos.