Memoria del trabajo - Universidad de Buenos Aires

Anuncio
UNIVERSIDAD DE BUENOS AIRES
FACULTAD DE INGENIERÍA
C ARRERA DE E SPECIALIZACIÓN EN S ISTEMAS
E MBEBIDOS
M EMORIA DEL T RABAJO F INAL
Herramienta Gráfica para Analizar la
Ocupación de Memoria en Sistemas
Embebidos
Autor:
Ing. Alejandro C ELERY
Director:
Ing. Juan Manuel C RUZ
Jurados:
Ing. Juan A LARCÓN
Ms. Ing. Roberto B ARNEDA
Ing. Gerardo S AGER
Este trabajo fue realizado en las Ciudad Autónoma de Buenos Aires, entre
agosto de 2015 y julio de 2016.
III
Resumen
En el presente trabajo se plantea el uso de treemaps o gráficos de mapa
de árbol para representar gráficamente como se ocupan las memorias de
código y datos de un microcontrolador. Se desarrolla un plugin para Eclipse
que dibuja un treemap y presenta una lista de los nombres encontrados en
la tabla de símbolos de un archivo binario.
V
Agradecimientos
En primer lugar a mi pareja, Esmeralda Yañez Illera. Solo ella sabe los
sacrificios que ha hecho para permitirme hacer esta especialización.
A mi padre, por haberme permitido llegar hasta donde estoy hoy, por
los valores que me transmitió por el camino, y por el orgullo que siente en
este momento desde donde sea que me esté viendo.
A la comunidad del software libre en general, por haberme brindado
las herramientas con las que ejercí la profesión hasta hoy (y a la que espero
poder devolverle algo con este trabajo).
A las autoridades de la CESE por haberme otorgado una beca para hacer
este curso, sin la cual no hubiera sido posible mi presencia.
A Juan Manuel Cruz, siempre presente, tutor de este trabajo puntual y
de muchas otras cosas más.
A Roberto Barneda, por la inmensurable cantidad de sabiduría que derramó sobre mi persona durante mis años formativos. Ojalá el destino me
permita hacer los mismo por las generaciones futuras.
A Rubén Lozano y Juan Alarcón, compañeros en la profesión, por apoyarme en esta empresa siendo mis jurados. Espero que mi trabajo les compense de alguna manera el tiempo que invirtieron en acompañarme.
A Ben Shneiderman, creador de los diagramas NS y de los treemaps,
por compartir su investigación conmigo y por interesarse en mi trabajo.
Al Ingeniero Mirko Serra, incansable compañero con quien compartimos el último y el más difícil tramo de la carrera académica. Aún no se
dónde estaría sin la exitosa sociedad que supimos formar y que espero continúe durante muchos años.
VII
Índice general
Resumen
III
Agradecimientos
V
Registro de versiones
XI
1. Introducción General
1.1. Problemática de los consumos de memoria en un microcontrolador . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.2. Presentación de los treemaps . . . . . . . . . . . . . . . . . .
1.3. Presentación de Eclipse y su uso de plugins . . . . . . . . . .
1.4. Solución propuesta . . . . . . . . . . . . . . . . . . . . . . . .
1
2. Introducción Específica
2.1. Tabla de símbolos generada por el compilador . . . . . . . .
2.2. Herramientas disponibles de análisis de la tabla de símbolos
2.2.1. Herramienta objdump . . . . . . . . . . . . . . . . . .
2.2.2. Herramienta nm . . . . . . . . . . . . . . . . . . . . .
2.2.3. Herramienta pahole . . . . . . . . . . . . . . . . . . .
2.3. Investigacion sobre treemaps . . . . . . . . . . . . . . . . . .
2.4. Diseño y desarrollo de un plugin . . . . . . . . . . . . . . . .
7
7
8
9
9
10
12
13
3. Diseño e Implementación
3.1. Análisis de la tabla de símbolos . . . . . . . . . . . .
3.2. Desarrollo del plugin . . . . . . . . . . . . . . . . . .
3.2.1. Lista completa de símbolos . . . . . . . . . .
3.2.2. Lista filtrada de símbolos . . . . . . . . . . .
3.2.3. Treemap . . . . . . . . . . . . . . . . . . . . .
3.2.4. Interacciones entre las views . . . . . . . . .
3.2.5. Obtención de la tabla de símbolos a graficar
3.2.6. Modelo de los datos en memoria . . . . . . .
3.2.7. Presentación de los datos al usuario . . . . .
3.2.8. Opciones de configuración del plugin . . . .
3.2.9. Depuración del plugin . . . . . . . . . . . . .
3.3. Adopción de un algoritmo de treemapping . . . . .
3.3.1. Resolución gráfica . . . . . . . . . . . . . . .
3.3.2. Relación de aspecto . . . . . . . . . . . . . . .
3.3.3. Preservación del orden de los datos . . . . .
3.3.4. Estabilidad de los datos . . . . . . . . . . . .
3.3.5. Algoritmo elegido . . . . . . . . . . . . . . .
15
15
16
18
18
19
20
21
21
21
21
23
24
24
25
25
26
26
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
1
2
3
3
VIII
4. Ensayos y Resultados
4.1. Precisión del análisis de la tabla de símbolos . . . . . . . . .
4.1.1. Precisión de la identificación de secciones de la herramienta nm . . . . . . . . . . . . . . . . . . . . . . . . .
4.1.2. Resultados del ensayo . . . . . . . . . . . . . . . . . .
4.2. Consumo de recursos de hardware causado por el plugin . .
4.2.1. Medición del tiempo de procesamiento . . . . . . . .
4.2.2. Resultados del ensayo . . . . . . . . . . . . . . . . . .
4.3. Validación con usuarios finales . . . . . . . . . . . . . . . . .
4.3.1. Esp. Ing. Pablo Ridolfi . . . . . . . . . . . . . . . . . .
4.3.2. Ing. Mirko Serra . . . . . . . . . . . . . . . . . . . . .
5. Conclusiones
5.1. Grado de cumplimiento de los requerimientos del proyecto .
5.1.1. Representación visual del uso de la memoria interna
del MCU . . . . . . . . . . . . . . . . . . . . . . . . . .
5.1.2. Fácil identificación de los principales consumos de
memoria . . . . . . . . . . . . . . . . . . . . . . . . . .
5.1.3. Indicación de a qué zona de memoria fue asignada
cada variable . . . . . . . . . . . . . . . . . . . . . . .
5.1.4. Presentación de estos datos dentro de una ventana de
Eclipse . . . . . . . . . . . . . . . . . . . . . . . . . . .
5.2. Próximos pasos . . . . . . . . . . . . . . . . . . . . . . . . . .
29
29
29
30
32
32
33
33
34
35
37
37
37
38
38
39
39
A. Programa usado para los ensayos de medición
41
Bibliografía
43
IX
Índice de figuras
1.1.
1.2.
1.3.
1.4.
Vista de la aplicación Windirstat . . . . . . . .
Eclipse dibujando gráficos 2D . . . . . . . . . .
Eclipse dibujando gráficos 3D . . . . . . . . . .
Eclipse usado para diseño basado en modelos
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
2.1.
2.2.
2.3.
2.4.
2.5.
2.6.
2.7.
Fragmento de un archivo “.map”, sección “.bss” . . . . . . .
Fragmento de un archivo “.map”, sección “.text” . . . . . . .
Fragmento de la salida del comando objdump . . . . . . . .
Fragmento de la salida del comando nm . . . . . . . . . . . .
Fragmento de la salida del comando pahole . . . . . . . . . .
Vista del programa TreeViz . . . . . . . . . . . . . . . . . . .
Detalle de los componentes de la interfaz de usuario de Eclipse
2
4
4
5
7
8
9
10
11
12
14
3.1. Código de la clase “Shell”. . . . . . . . . . . . . . . . . . . . .
3.2. Códigos con los que el comando nm identifica cada sección
de memoria. . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.3. Código de la clase “Symbol”. . . . . . . . . . . . . . . . . . .
3.4. Lista completa de símbolos generada por el plugin . . . . . .
3.5. Lista filtrada de símbolos generada por el plugin . . . . . . .
3.6. Treemap generado por el plugin . . . . . . . . . . . . . . . .
3.7. Fragmentos del código que genera la lista completa de símbolos del plugin. . . . . . . . . . . . . . . . . . . . . . . . . . .
3.8. Diálogo de opciones de configuración . . . . . . . . . . . . .
3.9. Treemaps con alta relación de aspecto . . . . . . . . . . . . .
3.10. Esquema del algoritmo “Squarify” . . . . . . . . . . . . . . .
15
4.1. Imagen de la salida del size al analizar el programa de prueba.
4.2. Vista de la sumatoria del tamaño de los símbolos en la sección .bss . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.3. Vista de la sumatoria del tamaño de los símbolos en la sección .data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.4. Vista de la sumatoria del tamaño de los símbolos en la sección .text . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
30
5.1. Resultado final del desarrollo . . . . . . . . . . . . . . . . . .
37
A.1. Programa usado para contrastar los reportes del plugin contra el comando size. . . . . . . . . . . . . . . . . . . . . . . . .
42
16
17
18
19
20
22
23
25
27
31
31
32
XI
Registro de versiones
Revisión
1.0
1.1
1.2
1.3
Cambios realizados
Creación del documento
Correcciones de formato
Se agrega el capítulo “Ensayos y resultados”
Se agregan reportes de uso a la sección “Validacion con usuarios finales.”
Fecha
27/06/2016
29/06/2016
10/07/2016
15/07/2016
1
Capítulo 1
Introducción General
1.1.
Problemática de los consumos de memoria en un
microcontrolador
Los microcontroladores son dispositivos electrónicos omnipresentes en
el mundo de hoy. Están formados por un microprocesador capaz de ejecutar un programa almacenado previamente en su memoria interna y por un
conjunto de periféricos de comunicación e interfaces eléctricas que le permiten interactuar con el mundo exterior. Su costo ha bajado mucho en los
últimos años, causando que en la gran mayoría de los casos sean la solución
electrónica que mejor se adapta a cualquier requerimiento de un dispositivo
de control.
La memoria interna en la que almacenan el programa a ejecutar y los
datos que este utiliza tiene una capacidad finita, por lo que debe observarse
cómo se emplea la misma.
El dato de cómo se consume la memoria en una aplicación con microcontrolador era de uso cotidiano en la época de los microcontroladores con
unos pocos cientos de bytes de memoria de datos pero se fue perdiendo
con el advenimiento de dispositivos con cada vez más capacidad de memoria (actualmente hay microcontroladores con 1Mb de memoria de código y
192Kb de memoria de datos, contra los 8Kb y 256 bytes del primer microcontrolador con el que el autor tuvo su bautismo de fuego en la profesión).
La infromación del consumo de memoria la emite el compilador cada
vez que compila la aplicación, pero lo hace en un formato cuasi críptico que
es de difícil asimilación por programadores no experimentados. Aún en el
caso de programadores con trayectoria probada, buscar la información en
ese formato conlleva un gasto improductivo de tiempo.
La experiencia ha demostrado que se presentan dos situaciones cotidianas en el desarrollo de sistemas embebidos en las que este consumo se debe
tener muy presente:
Al encarar un desarrollo nuevo, se debe reducir al mínimo posible la
memoria utilizada por la aplicación con el fin de elegir el microcontrolador más económico que la pueda contener.
Al ampliar un diseño existente, se puede agotar la memoria disponible y ser necesario agregar una nueva funcionalidad.
Ante esta problemática, las herramientas de compilación gratuitas disponibles hoy en día al programador no ofrecen al mismo una solución. Si
bien existe la posibilidad de que las herramientas de uso profesional sí lo
hagan, esta posibilidad no se ha estudidado por el costo prohibitivo que las
mismas exhiben.
2
Capítulo 1. Introducción General
1.2.
Presentación de los treemaps
Los treemaps (o mapas de árbol) son un tipo de diagrama muy útil que
puede ayudar con la problemática presentada anteriormente. Siendo una
herramienta 100 % visual, se prefiere mostrarla antes que intentar describirla. Para contextualizar, la figura 1.1 muestra una imagen de una aplicación
llamada WinDirStat [18] que sirve para analizar cómo se está ocupando el
espacio disponible en un disco rígido, indicando cuáles archivos y/o carpetas ocupan el mayor espacio.
Figura 1.1: Vista de la aplicación Windirstat
En la figura 1.1 se pueden apreciar varias cuestiones:
En la ventana superior izquierda, una lista de las carpetas presentes
en el disco rígido ordenadas de mayor a menor.
En la parte derecha, una lista de los tipos de archivo encontrados
(imágenes, música, documentos, etc.) con un color asociado a cada
tipo.
En la parte inferior, un mapa gráfico con numerosos rectángulos de
distintos colores y tamaños. Cada archivo presente en el disco rígido
está representado por un rectángulo, donde su tamaño relativo al total del espacio ocupado se aprecia en el tamaño del rectángulo (para
ejemplificar, si un archivo ocupara la mitad del espacio en disco, su
rectángulo ocuparía la mitad del área graficada) y el color corresponde al tipo de archivo indicado en la parte superior derecha.
Cabe mencionar que para analizar un disco rígido no se lo recorre físicamente sector por sector sino que al comienzo del mismo hay una tabla
llamada FAT (File Allocation Table), que contiene el índice de qué archivo
está ubicado en qué parte del disco y qué tamaño ocupa.
1.3. Presentación de Eclipse y su uso de plugins
3
Recapitulando, existe una herramienta capaz de mostrar en forma gráfica e inmediata las relaciones de tamaño entre una gran cantidad de archivos
identificados al analizar una tabla de ubicación de un disco rígido. El lector
con experiencia en sistemas embebidos tal vez esté asociando en este momento esta herramienta con la problemática presentada en la sección 1.1,
que fue lo que hiciera el autor al verla por primera vez. Se discute esta posibilidad en la sección 1.4.
1.3.
Presentación de Eclipse y su uso de plugins
La herramienta de uso más popularizado en el desarrollo de sistemas
embebidos es sin duda un programa llamado Eclipse. Su historia se puede leer en Wikipedia [1], pero basta mencionar aquí su característica fundamental: es un programa libre y sumamente modular compuesto por un
pequeño núcleo cuya única función es cargar módulos conteniendo la funcionalidad deseada llamados “plugins” o “enchufables”.
De este modo, una única herramienta se puede utilizar para un sinnúmero de propósitos siempre y cuando tenga disponibles los plugins necesarios. La aplicación es 100 % libre y de código abierto, y están sumamente
documentados su uso y las técnicas de programación requeridas para desarrollar nuevos plugins. Por este motivo se han escrito módulos para permitirle funcionar para muchos propósitos. Sin ir más lejos, el plugin objeto
de este trabajo fue escrito en un entorno Eclipse y también lo fue este documento en su totalidad, en ambos casos con el agregado de los plugins
correspondientes.
En el desarrollo de sistemas embebidos se ha impuesto por sus numerosas virtudes, entre otras:
Es una herramienta libre y sin costo alguno.
Es muy sencillo de integrar con otras herramientas libres.
Es sumamente personalizable
Funciona indistintamente en Linux, Windows y MAC-OS.
Permite un uso muy flexible del espacio disponible en la pantalla.
Esto es muy útil en estos días de trabajar con computadores portátiles
adosados a un segundo monitor o un proyector.
Las siguientes tres figuras muestran sendas imágenes de Eclipse cumpliendo roles bien diferentes con el espíritu de transmitir su versatilidad.
El único requisito para poder programar un plugin es hacerlo en el lenguaje Java, pero el mismo es lo bastante similar al lenguaje C++ y de alguna
manera al lenguaje C (el de mayor uso en el desarrollo de SE) como para
que un programador de SE lo bastante motivado pueda emprender el desarrollo de un plugin.
1.4.
Solución propuesta
De los expuesto anteriormente, se puede inferir que tomando los siguientes recaudos se puede obtener una herramienta de gran valor:
4
Capítulo 1. Introducción General
Figura 1.2: Eclipse dibujando gráficos 2D
Figura 1.3: Eclipse dibujando gráficos 3D
En lugar de analizar una tabla de ubicación de archivos en un disco rígido, se debe analizar una tabla de ubicación de variables en la
memoria de un microcontrolador.
Se debe contemplar que las relaciones de anidamiento (es decir, un archivo dentro de una carpeta dentro de otra carpeta) no están presentes en la memoria de un microcontrolador (se discutirán más adelante
algunas excepciones).
1.4. Solución propuesta
5
Figura 1.4: Eclipse usado para diseño basado en modelos
Hay que obtener de alguna manera el algoritmo o receta para dibujar
un mapa propio, producto del análisis anterior.
Todo esto se discutirá en el capítulo 2.
Habiendo visto la problemática de los consumos de memoria, las bondades de los gráficos de treemap para representarla y la posibilidad de ampliar la herramienta de trabajo de uso cotidiano para incluir estos diagramas, resulta interesante la posibilidad de desarrollar un plugin para Eclipse
que atendiera esta problemática.
Entonces, con la motivación de diseñar y desarrollar una herramienta
de software que asista a los programadores de sistemas embebidos en su
función, permitiéndoles ver rápidamente cómo se está empleando la memoria interna del microcontrolador en uso; con la esperanza de que esta
herramienta ahorre tiempo al desarrollador al ejercer su función y le permita tomar mejores decisiones a la hora de elegir un microcontrolador para
un proyecto nuevo es que se eligió esta temática para desarrollar el presente
trabajo.
Durante el curso de gestión de proyectos se planificó este trabajo, y se
pusieron los siguientes requerimientos:
1. Representación visual del uso de la memoria interna de un microcontrolador.
2. Fácil identificación de los principales consumos de memoria.
3. Indicación de a qué zona de memoria fue asignada cada variable (FLASH,
RAM, EEPROM, etc).
4. Presentación de estos datos dentro de una ventana de Eclipse.
Se definió el alcance del proyecto como “la realización de dicho plugin
integrable a Eclipse y la entrega de un manual de usuario que permita la
6
Capítulo 1. Introducción General
instalación y uso del mismo. En este proyecto no se contemplan cursos de
capacitación en el uso de la herramienta generada.”
Fundamentado en los siguientes supuestos:
1. No hay actualmente una herramienta que cumpla estos requisitos.
2. Hay una población de programadores de sistemas embebidos que se
beneficiaría de tener tal herramienta.
3. El programador no experimentado suele ignorar esta problemática y
tal herramienta lo ayudará a superar la misma.
Habiendo expuesto el panorama encontrado al momento de planificar
el proyecto y los supuestos sobre los que se decidió llevarlo adelante, se
pasa a la siguiente sección en la que se describen en detalle los componentes
que formaron parte de la solución y sus problemáticas asociadas.
7
Capítulo 2
Introducción Específica
2.1.
Tabla de símbolos generada por el compilador
El punto de partida del análisis detallado tiene que ser necesariamente
la identificación de los datos a graficar. El primer contacto con ellos es un
archivo llamado “map file” o mapa del archivo, que el compilador genera
luego de hacer una compilación. La figura 2.1 presenta un fragmento del
mismo para referencia del lector:
.bss.bufferColumnaVacia
0x10002b88
0x7f
...(CM3_Display_C12.o)
0x10002b88
bufferColumnaVacia
.bss.bufferColumnaGrafica
0x10002c07
0x7f
...(CM3_Display_C12.o)
0x10002c07
bufferColumnaGrafica
.bss.buffer10medicionesPong
0x10002c86
0xa
...(CM3_Display_C12.o)
0x10002c86
buffer10medicionesPong
.bss._ZZ16BSP_DibujarPuntoiimbE14tocaTransferir
0x10002c90
0x1
...(CM3_Display_C12.o)
0x3
*fill* 0x10002c91
Figura 2.1: Fragmento de un archivo “.map”, sección “.bss”
El programador experimentado puede inferir rápidamente la siguiente
información:
Todos los símbolos están ubicados en una misma sección llamada
“bss”.
Los símbolos identificados son: bufferColumnaVacia, bufferColumnaGrafica, buffer10medicionesPong, tocaTransferir.
El símbolo tocaTransferir es declarado con el modificador “static” y
es local a la función BSP_DibujarPunto
Las direcciones de memoria comienzan en 0x10002b88
Los tamaños ocupados por los símbolos son de 127, 127, 10 y 1 bytes
(en el orden en que se reconocen los símbolos).
El último símbolo de la lista ocupa 1 byte pero luego de él se reserva un espacio desperdiciado de 3 bytes, para que todos los símbolos
empiecen en una dirección múltiplo de 4.
8
Capítulo 2. Introducción Específica
Todos pertenecen al archivo CM3_Display_C12
Por la propia experiencia del autor, se concluye que estas determinaciones escapan al programador principiante. Ciertamente durante la formación académica recibida en la carrera de Ingeniería Electrónica (que generalmente son quienes suelen dedicarse a los sistemas embebidos) no se
llega a examinar el software producido con el nivel de detalle suficiente
para percibir estas cuestiones.
En el fragmento analizado se hizo incapié en unas declaraciones de variables en el segmento de datos. Si ahora miramos un fragmento del mismo
archivo referido al segmento de código y la declaración de funciones vemos
que la situación es similar, como se puede ver en la figura 2.2:
.text.ColaReset
0x00016db4
0x00016db4
.text.ColaInit
0x00016dce
0x00016dce
.text.ColaCantidad
0x00016df2
0x00016df2
.text.ColaDisponible
0x00016e04
0x00016e04
0x1a
...(ColaCircular.o)
ColaReset
0x24
...(ColaCircular.o)
ColaInit
0x12
...(ColaCircular.o)
ColaCantidad
0x16
...(ColaCircular.o)
ColaDisponible
Figura 2.2: Fragmento de un archivo “.map”, sección “.text”
En este caso se pueden sacar similares conclusiones, con la salvedad de
que los símbolos están en la sección “text”.
Para contextulizar finalmente la complejidad de encontrar estos datos
en el archivo, vale mencionar que el ejemplo del que se tomaron estos fragmentos tiene 7230 líneas de largo y que el mismo incluye numerosos artefactos producidos por el compilador durante el proceso de compilación que
no tienen importancia para el programador.
2.2.
Herramientas disponibles de análisis de la tabla
de símbolos
Habiendo visto las vicisitudes de analizar manualmente el resultado del
proceso de compilación, vale mencionar que existen herramientas de software que hacen ese trabajo notablemente más fácil. Dos de ellas son parte
del grupo de herramientas llamadas “binutils” y están disponibles a partir
de que se instalan las herramientas para programar un microcontrolador
(en adelante “toolchain” o “cadena de herramientas”). Es importante recordar que la salida producida por estas herramientas solo sirve si puede ser
recogida y tabulada para su posterior uso por herramientas gráficas, este
fue el criterio que se utilizó para elegir una de las tres.
2.2. Herramientas disponibles de análisis de la tabla de símbolos
<1><894a>: Número de Abrev: 143
<894c>
DW_AT_decl_line
:
<894e>
DW_AT_decl_file
:
<8950>
DW_AT_type
:
<8954>
DW_AT_external
:
<8955>
DW_AT_location
:
<895b>
DW_AT_name
:
<1><8965>: Número de Abrev: 130
<8967>
DW_AT_type
:
<896b>
DW_AT_external
:
<896c>
DW_AT_declaration :
<896d>
DW_AT_name
:
<1><8998>: Número de Abrev: 130
<899a>
DW_AT_type
:
<899e>
DW_AT_external
:
<899f>
DW_AT_declaration :
<89a0>
DW_AT_name
:
9
(DW_TAG_variable)
835
50
<0x8aeb>
1
bloque de byte 5: 3 ...
buffer_tx
(DW_TAG_variable)
<0x8b28>
1
1
c
(DW_TAG_variable)
<0x89c9>
1
1
hayContraseniaCorrecta
Figura 2.3: Fragmento de la salida del comando objdump
2.2.1.
Herramienta objdump
Objdump fue la primera herramienta analizada. Es la más conocida de
las tres por los programadores, ya que forma parte del proceso estándar de
compiación de un programa para microcontrolador. El siguiente es un fragmento de su documentación disponible en forma online: “objdump muestra
información sobre uno o más archivos objeto. Tiene opciones para controlar qué información en particular se muestra. Esta información es mayormente útiles para
los programadores que trabajan en las herramientas de compilación y no para los
programadores que solo quieren que su programa compile y funcione. . . ” [10].
Es una herramienta sumamente versátil y como tal tiene muchas opciones para configurar su uso. La dificultad en su uso se menciona en la
descripción precedente: al estar orientada a desarrolladores de herramientas no hay ningún interés en presentar la información en forma sencilla.
La figura 2.3 muestra un ejemplo de lo que se puede esperar cuando se la
utiliza:
Se puede ver que por cada entidad encontrada en el archivo analizado
se produce un bloque que empieza con la línea que contiene “Número de
Abrev”. A simple vista no se puede extraer la información de tamaño de
los símbolos encontrados ni de la sección en la que fueron ubicados. Más
aún, esta información probablemente esté en otra parte de la salida y sea
necesario hacer una correlación de más de una.
Habiendo visto la dificultad de encontrar la información buscada y más
aún recogerla programáticamente para procesarla, se detuvo el análisis preliminar de esta herramienta en este punto y se pasó a la siguiente.
2.2.2.
Herramienta nm
Nm es una herramienta más sencilla, con un propósito más específico:
“nm lista los símbolos encontrados en una lista de archivos objeto. . . ” [9].
10
Capítulo 2. Introducción Específica
00049418
00070334
00032192
...
08388612
08388622
...
08388804
08389492
08389540
00000148 t _ProcEstadoInterfazBloqueada
00000148 t _ControlaPresionSeteada
00000142 t _VerificaFuentesGases
00000010 D _umbralEstadosBateriaDescarga
00000010 D _umbralEstadosBateriaCarga
00000032 B _flags_t_svc
00000032 B _flags_t_est
00000016 B _estado_equipo
Figura 2.4: Fragmento de la salida del comando nm
Por su descripción, nm parece ser la herramienta hecha a medida para
el propósito buscado. La figura 2.4 muestra un ejemplo de su uso para
compararlo con la anterior:
Se puede ver a simple vista el formato de lista en el que se muestran los
resultados. En una segunda inspección, se aprecia la siguiente información:
La primera columna contiene la dirección en memoria de cada símbolo.
La segunda muestra el tamaño de los mismos.
Luego sigue una letra que el observador experimentado puede reconocer como la sección en la que se ubica el símbolo. Recuérdese que
recabar esta información es uno de los requerimientos del proyecto.
A esta altura el autor pudo apreciar que esta herramienta supera con
creces a la anterior. En la sección 4.1 se analizará el grado de precisión con
el que se extrae la información de esta tabla para tener una métrica cuantitativa de los resultados de este trabajo.
2.2.3.
Herramienta pahole
Pahole es una herramienta complementaria para los objetivos de este
trabajo. “pahole muestra la disposición de las estructuras de datos que se almacena
en los símbolos de depuración. . . ” [11].
Su propósito no es identificar los símbolos declarados en un programa sino hacer un análisis de cómo el compilador organiza las estructuras
de datos declaradas por el programador. Para contextualizar este análisis
se menciona que muchas veces estas estructuras se usan cuando se escribe código para acceder a hardware, y en estos casos es necesario que el
compilador respete la ubicación exacta de cada bit y byte declarado por el
programador. En algunos casos los compiladores no hacen esto sino que
agregan bits de relleno en las estructuras buscando un acceso más rápido a
la memoria.
Por completitud, se muestra un ejemplo de su uso en la figura 2.5 :
2.2. Herramientas disponibles de análisis de la tabla de símbolos
11
struct st_evento {
unsigned char
cod_evento;
unsigned char
detalle_evento;
unsigned char
dia;
unsigned char
mes;
unsigned char
anio;
unsigned char
hora;
unsigned char
minutos;
unsigned char
segundos;
/*
/*
/*
/*
/*
/*
/*
/*
0
1
2
3
4
5
6
7
1
1
1
1
1
1
1
1
*/
*/
*/
*/
*/
*/
*/
*/
/* size: 8, cachelines: 1, members: 8 */
/* last cacheline: 8 bytes */
};
struct st_tabla_estado {
unsigned short
estado_on_off;
/*
unsigned short
boot_count;
/*
unsigned short
estado_falla;
/*
unsigned short
horas_uso_cpu;
/*
unsigned short
horas_ultimo_service; /*
unsigned char
minutos_uso_cpu;
/*
unsigned char
t_est_reservado;
/*
unsigned short
ciclos_valvulas;
/*
unsigned short
horas_uso_turbina;
/*
0
2
4
6
8
10
11
12
14
2
2
2
2
2
1
1
2
2
*/
*/
*/
*/
*/
*/
*/
*/
*/
/* size: 16, cachelines: 1, members: 9 */
/* last cacheline: 16 bytes */
};
Figura 2.5: Fragmento de la salida del comando pahole
12
2.3.
Capítulo 2. Introducción Específica
Investigacion sobre treemaps
Habiendo establecido la conveniencia de los mapas de árbol para representar información, resulta apropiado indagar un poco más sobre ellos. Se
puede leer un racconto muy detallado de su historia en [13] contado por el
propio Ben Shneiderman de la Universidad de Maryland, Estados Unidos,
creador de estos diagramas.
El comienzo de su investigación lo explica así (traducido por el autor):
“En 1990, en respuesta a la problemática común de un disco rígido lleno, me obsesioné con la idea de producir una visualización compacta de las estructuras de
árbol de directorios. Dado que el disco rígido de 80 Megabytes usado en el laboratorio de Interacción hombre-computador era compartido por 14 usuarios, era muy
difícil determinar cómo y dónde se usaba su capacidad. . . ”
“Los diagramas con estructura de árbol y vinculados en los nodos se volvían
muy grandes para ser útiles, así que exploré maneras de mostrar un árbol en un
formato con espacio limitado. Rechacé las estrategias que dejaban espacios en blanco.(. . . ) Mostrar el tamaño de los archivos codificándolo por área parecía atractivo,
pero las formas rectangulares, triangulares y circulares todas tenían problemas. Finalmente un día meditando sobre esto en el salón de la facultad, tuve el momento
Ajá! de dividir la pantalla en rectángulos alternando las direcciones vertical y horizontal a medida que se atraviesan los distintos niveles.”
En el marco de su investigación, Ben Shneiderman y Brian Johnson escribieron la primera implementación de un visor de ocupación de espacio
en disco rígido y lo bautizaron TreeViz. La figura 2.6 muestra una imagen
del mismo.
Figura 2.6: Vista del programa TreeViz, primero en implementar la visualización mediante treemaps. Figura tomada
de [13]
Luego en la misma página menciona el software que se adoptó en este trabajo: “Para apoyar a investigadores y estudiantes, Ben Bederson y Martin
2.4. Diseño y desarrollo de un plugin
13
Wattenberg escribieron una librería de código abierto en Java 1.1 con 5 algoritmos de treemap. Son genéricos y debieran poder usarse sencillamente en cualquier
aplicación. Cada una toma una lista de números y un rectángulo, y genera un conjunto de sub-rectángulos que son proporcionales en área a los números de entrada
y particiona el espacio del rectángulo de entrada. Los 5 algoritmos implementados
son:
BinaryTree - Partially ordered, not very good aspect ratios, stable
Ordered - Partially ordered, medium aspect ratios, medium stability
SliceAndDice - Ordered, very bad aspect ratios, stable
Squarified - Unordered, best aspect ratios, medium stability
Strip - Ordered, medium aspect ratios, medium stability”
En este punto vale aclarar que un “algoritmo de treemapping” se debe
entender como un criterio para repartir el espacio disponible entre los distintos rectángulos. Shneiderman ordena estos 5 algoritmos según sus capacidades de orden, relación de aspecto y estabilidad. La eleccción de uno de
estos algoritmos y las características mencionadas de los mismos se discutirá en la sección 3.3.
Lo último que resulta interesante citar son funciones adicionales que
se desarrollaron durante la investigación: “La implementación del estudiante de doctorado Brian Johnson agregó muchas otras funciones interesantes, como
ser zooming, sonido (como una codificación redundante, por ejemplo los archivos
más grandes tenían un sonido más grave), control de matiz y saturación, muchas
variantes de bordes y control de etiquetado. . . ” . Algunas de estas funciones adicionales se tomaron como ideas para los próximos pasos posteriores a este
trabajo, como se muestra en la sección 5.2.
2.4.
Diseño y desarrollo de un plugin
Se ha dicho anteriormente que Eclipse es una plataforma formada por
un pequeño núcleo capaz de cargar módulos externos a él y que le brindan
funcionalidad. A continuación analizamos estos módulos y cómo se desarrolla uno propio.
Tanto el núcleo de Eclipse como los plugins se escriben en el lenguaje
Java. De hecho, Eclipse nace dentro de la firma IBM [1] como un entorno
para programar en dicho lenguaje y se lo considera el mejor entorno para
tal función. Así las cosas, un plugin no es más que un pequeño programa
en Java que se desarrolla usando el mismo Eclipse.
Para simplificar el proceso de desarrollo, el mismo no se hace partiendo
de un lienzo en blanco sino que se parte de diversas plantillas de plugins
que luego el programador modifica para sus propósitos. Tanto estas plantillas como las herramientas de software necesarias para escribir, ensayar y
validar un plugin están contenidas dentro del llamado PDE o “Plugin Development Environment”, es menester instalarlo para encarar el desarrollo
de un plugin. Casualmente, el PDE es un conjunto de plugins diseñados
para permitir el desarrollo de otros plugins.
14
Capítulo 2. Introducción Específica
Los plugins tienen una característica particular: por un lado se listan en
forma declarativa las capacidades que aportan a Eclipse y su funcionalidad
se programa en lenguaje Java en otro lugar. Esto permite que al iniciar Eclipse no haya que cargar todos los plugins que le fueron instalados sino que
tan solo lee estas listas logrando así arrancar muy rápidamente. Es recién
cuando el usuario invoca alguno de estos plugins que se procede a cargarlo
en memoria.
La figura 2.7 muestra una imagen básica de una ventana de Eclipse para
presentar sus elementos:
Figura 2.7: Detalle de los componentes de la interfaz de
usuario de Eclipse
Como regla general, a todos los elementos destacados en la imagen se
puede agregar funcionalidad. Pongamos algunos ejemplos:
A la barra de menúes se pueden agregar nuevos menúes, y a estos
nuevas opciones.
A la barra de herramientas se pueden agregar nuevos botones.
Se pueden agregar editores especializados en algún lenguaje en particular.
Lo más importante (y lo que se ha hecho en el presente trabajo) es agregar nuevas ventanas (llamadas “Views” en la jerga). Estas pueden contener
cualquier información de interés y se pueden hacer varias operaciones sobre ellas. En la sección 3.2 se expone en detalle la funcionalidad que se
implementó.
15
Capítulo 3
Diseño e Implementación
3.1.
Análisis de la tabla de símbolos
Para extraer la información de la tabla de símbolos se eligió finalmente
la herramienta “nm”. Su formato tabular hace que sea muy sencillo procesar la información y capturarla en el plugin.
Para invocar a nm se usa la clase Shell (presentada en la figura 3.1), que
tiene un único método estático “command”. El mismo genera un nuevo
proceso para el sistema operativo que invoca al proceso recibido como parámetro. En este caso la llamada es “nm –print-size –size-sort –reverse-sort
–radix=dec nombreArchivo.elf”.
1
3
public c l a s s Shell
{
s t a t i c A r r a y L i s t < S t r i n g > output ;
p u b l i c s t a t i c A r r a y L i s t < S t r i n g > command ( f i n a l S t r i n g cmdline ,
final String directory )
throws IOException , I n t e r r u p t e d E x c e p t i o n
{
Process process =
new P r o c e s s B u i l d e r ( new S t r i n g [ ] { " bash " , "−c " , cmdline
})
. redirectErrorStream ( true )
. d i r e c t o r y ( new F i l e ( d i r e c t o r y ) )
. start () ;
5
7
9
11
13
output = new A r r a y L i s t < S t r i n g > ( ) ;
BufferedReader br = new BufferedReader (
new InputStreamReader ( p r o c e s s . getInputStream ( ) ) ) ;
15
17
String line = null ;
while ( ( l i n e = br . readLine ( ) ) ! = n u l l ) {
output . add ( l i n e ) ;
}
19
21
23
i f ( 0 ! = p r o c e s s . waitFor ( ) ) {
return null ;
}
25
27
r e t u r n output ;
}
29
}
Figura 3.1: Código de la clase “Shell”.
16
Capítulo 3. Diseño e Implementación
Esta llamada devuelve una lista donde cada elemento es una línea de
texto con una columna para cada dato que contiene, por ejemplo: 00032192
00000142 t VerificaFuentesGases
Las mismas se interpretan de la siguiente manera:
1. Dirección de memoria del símbolo. En este plugin no se hace uso este
dato ya que no es un requerimiento del mismo hacer un mapa topográfico de la memoria. En una segunda mirada, los microcontroladores organizan las secciones de código y datos en ciertos rangos de
direcciones, con lo cual con de la dirección de memoria de un símbolo
se puede inferir la sección en la que está ubicado. Esta posibilidad se
descartó en este trabajo dado que impondría al usuario la necesidad
de aprender el mapa de memoria del microcontrolador en uso y como
se verá en breve la tercera columna da esta información.
2. Tamaño en memoria del símbolo.
3. Una letra que indica la sección de memoria donde el símbolo fue ubicado.
4. Nombre del símbolo.
La figura 3.2 muestra como identifica nm las secciones [9]:
"B"
"b" The symbol is in the uninitialized data section
(known as BSS).
"D"
"d" The symbol is in the initialized data section.
"T"
"t" The symbol is in the text (code) section.
"?" The symbol type is unknown, or object file
format specific.
Figura 3.2: Códigos con los que el comando nm identifica
cada sección de memoria.
Para alojar estos datos se diseñó la clase Symbol, presentada en la figura
3.3:
Se puede ver en el método “Symbol” el proceso de análisis, donde según
el valor del carácter en la columna 3 (en el código se ve 2 porque cuenta
desde 0) se asigna el nombre por el que los programadores conocen a las
secciones.
3.2.
Desarrollo del plugin
A la hora de presentar la información al usuario, fue necesario decidir
la mejor manera de hacerlo. Se optó por un esquema con 3 views:
1. Lista completa de símbolos
3.2. Desarrollo del plugin
2
4
17
p u b l i c c l a s s Symbol {
p r i v a t e S t r i n g name ;
private Integer size ;
private String section ;
p r i v a t e boolean enabled ;
6
p u b l i c Symbol ( S t r i n g name , I n t e g e r s i z e , S t r i n g s e c t i o n ) {
t h i s . name = name ;
this . size = size ;
this . section = section ;
t h i s . enabled = t r u e ;
}
8
10
12
p u b l i c Symbol ( S t r i n g nmOutput ) {
t h i s . enabled = t r u e ;
14
16
S t r i n g [ ] tokens = nmOutput . s p l i t ( " " ) ;
t h i s . s i z e = I n t e g e r . p a r s e I n t ( tokens [ 1 ] ) ;
t h i s . name = tokens [ 3 ] ;
18
20
i f ( tokens [ 2 ] . e q u a l s I g n o r e C a s e ( " b " ) )
t h i s . s e c t i o n = " BSS " ;
e l s e i f ( tokens [ 2 ] . e q u a l s I g n o r e C a s e ( " d " ) )
t h i s . s e c t i o n = " Data " ;
e l s e i f ( tokens [ 2 ] . e q u a l s I g n o r e C a s e ( " t " ) )
t h i s . s e c t i o n = " Text " ;
e l s e i f ( tokens [ 2 ] . e q u a l s I g n o r e C a s e ( "w" ) )
t h i s . s e c t i o n = " Text−Weak" ;
else
t h i s . s e c t i o n = tokens [ 2 ] ;
22
24
26
28
30
}
32
@Override
public String toString ( ) {
r e t u r n name + " − " + s i z e ;
}
34
36
p u b l i c boolean isInROM ( ) {
r e t u r n s e c t i o n . e q u a l s ( " Text " ) || s e c t i o n . e q u a l s ( " Text−Weak
");
}
38
40
p u b l i c boolean isInRAM ( ) {
r e t u r n ! isInROM ( ) ;
}
42
44
}
Figura 3.3: Código de la clase “Symbol”.
2. Lista filtrada de símbolos
3. Treemap.
Primero se introducirá cada una por separado con sus capacidades y luego se analizará la interacción entre ellas que es lo que genera el valor del
plugin.
18
3.2.1.
Capítulo 3. Diseño e Implementación
Lista completa de símbolos
Este es el punto de partida del desarrollo. Se optó por presentar el total
de los símbolos identificados en el archivo binario en un formato de tabla con 3 columnas. En estas se presentan respectivamente el nombre del
símbolo, su tamaño en memoria y la sección en la que fue ubicado por el
compilador. Podría decirse que solo con esta lista se brinda una gran ayuda
al programador. Como se ve en la figura 3.4, el objetivo principal de esta
lista es presentar la visión total de los contenidos del archivo analizado.
Figura 3.4: Lista completa de símbolos generada por el plugin
Su principal característica es que cada símbolo tiene una casilla de verificación que indica si será graficado o no en el mapa y en la lista filtrada. Esto
permite que el plugin presente información sobre la totalidad del archivo o
solo sobre el subconjunto del mismo que sea de interés para el usuario.
Además de mostrar los símbolos, se incluyeron dos ayudas para el usuario: un campo de búsqueda en el cual se puede escribir una parte del símbolo buscado y que la lista oculte los que no coinciden con él y un filtro que
permite seleccionar todos los símbolos que correspondan a una sección en
particular. De este modo es fácil ver el mapa de todos los símbolos, el mapa
de la memoria de código, el mapa de la memoria de datos y una distinción
entre dos secciones de la memoria de datos: las llamadas “bss” y “data”
que representan los datos que no tienen un valor inicial y los que sí deben
tenerlo respectivamente.
3.2.2.
Lista filtrada de símbolos
La figura 3.5 muestra la lista filtrada de símbolos. Esta lista es la que alimenta el treemap, todos los símbolos que esté mostrando son graficados. Si
bien podría haberse mantenido oculta al usuario se decidió dejarla visible.
3.2. Desarrollo del plugin
19
El plugin puede funcionar con o sin ella habilitada. Incluye un totalizador
que suma el tamaño de todos los símbolos mostrados.
Figura 3.5: Lista filtrada de símbolos generada por el plugin
3.2.3.
Treemap
La vista treemap se puede apreciar en la figura 3.6. Muestra el mapa de
árbol de los símbolos contenidos en la lista filtrada. Lo hace ordenando los
símbolos por tamaño descendente, ya que se encontró que este es el criterio
de mayor utilidad según los requerimientos del proyecto.
En la imagen se pueden apreciar tres cuestiones importantes:
Un símbolo muy grande en color gris oscuro que representa el espacio
libre en memoria (si bien esta imagen no lo muestra, se verá luego en
la interacción con la lista que sí lo hace). De esto se puede inferir que
este microntrolador tiene capacidad de sobra para seguir agregándole
funcionalidad.
Un símbolo en verde oscuro en la parte inferior izquierda que ocupa
una parte significativa comparado con las demás. De ser necesario
liberar algo de memoria en esta aplicación, este sería el primer lugar
a revisar.
Una región en la esquina inferior derecha donde hay un sinnúmero
de variables de tamaño muy pequeño. Es razonable suponer que son
variables de 1 byte que representan estados de algún proceso en particular o contadores de 1 byte, con el rango de 0 a 256. Se ve que para
recuperar el tamaño equivalente a tan solo UN símbolo de los de la
parte superior derecha habría que eliminar muchos. Este es el punto
mencionado previamente de los rendimientos decrecientes, donde no
es provechoso aplicar un proceso de optimización. Si esta región fuese
muy grande solo se puede concluir que el programador responsable
de esta aplicación tiene algunos vicios que debe corregir.
El mapa se dibuja con una paleta de 5 colores generada en la web [14].
Para que los rectángulos adyacentes se puedan diferenciar fácilmente entre
20
Capítulo 3. Diseño e Implementación
Figura 3.6: Treemap generado por el plugin
sí se tomaron dos medidas: Por un lado, cada símbolo se dibuja con un
degradé entre su color base y uno que es un 20 % más oscuro, y por el otro
se los dibuja con un recuadro negro fino.
Para destacar el rectángulo que el usuario haya seleccionado, al mismo
se le dibuja un reborde blanco grueso alrededor.
3.2.4.
Interacciones entre las views
El treemap es el objetivo principal del desarrollo, pero para que tenga
una utilidad práctica es necesario tener control sobre lo que se está graficando. Para esto se decidió conectarlas de la siguiente manera:
Se puede trabajar con solo un subconjunto de lo símbolos del archivo:
Esto se logra destildando todos los símbolos de la lista completa y luego tildando los pocos que sean de interés. Esto último se ve ayudado
por el campo de búsqueda de la lista completa.
Cuando se quiere excluir un símbolo particular del análisis, se puede
destildar únicamente ese y el mapa se redibujará sin él.
Se puede concentrar el análisis en una sola sección, lo que se logra
eligiéndola en el filtro de secciones de la lista completa.
3.2. Desarrollo del plugin
21
Se pueden ordenar ambas listas por nombre, por tamaño y por sección, lo que permite ver más fácil los símbolos de interés. Esto no
modifica el treemap, que siempre se grafica ordenado por tamaño.
Se puede seleccionar un rectángulo en particular en el treemap para
ver a qué símbolo corresponde. Al hacer esto las listas lo muestran
seleccionado y resaltado para que sea más fácil encontrarlo.
3.2.5.
Obtención de la tabla de símbolos a graficar
Para adquirir la tabla de símbolos se hace desde el plugin una llamada
al comando “nm” usando la clase de Java “ProcessBuilder”. Esta se encarga
de generar un nuevo proceso del sistema operativo que se encarga de ejecutar el comando “nm” con las opciones discutidas previamente y recoger
la salida del mismo. El motivo de hacer esto fue mantener toda la funcionalidad en lenguaje Java y dentro del mismo plugin, para no imponer al
usuario final la instalación de herramientas adicionales.
3.2.6.
Modelo de los datos en memoria
Al programar en un lenguaje orientado a objetos como es Java se simplifica mucho la organización de los datos en la memoria. Se empezó por
definir una clase “Símbolo” que representa la información que se puede extraer del análisis de los datos: nombre, tamaño y sección. Luego se arma
una lista con estos Símbolos, a la que se llama Modelo.
3.2.7.
Presentación de los datos al usuario
Las buenas prácticas de programación mandan que hay que separar el
contenido de la presentación del mismo, de modo que se puedan alterar
ambas por separado. En este caso, Eclipse hace uso copioso de los llamados
“JFace viewers” [17]. Son numerosos visualizadores de datos a los que tan
solo hay que darles una semblanza de cómo los mismos están organizados.
La figura 3.7 se muestra el código (algo recortado) que genera la lista
completa de símbolos para demostrar la sencillez que se puede trabajar una
vez que se supera la curva de aprendizaje de estas herramientas:
En la línea viewer.setContentProvider(new ArrayContentProvider()); se le
dice a la tabla que los datos tienen forma de “Array” o vector, es decir que
están todos uno a continuación del otro y con el mismo formato.
Luego en viewer.setInput(Activator.getModel().getSymbols()); se le dice que
sus datos de entrada provienen de la lista de símbolos contenida en el modelo.
De la misma manera sencilla se ve como se programa el criterio para
ordenar las listas por cualquiera de las tres columnas.
3.2.8.
Opciones de configuración del plugin
Se implementaron 4 opciones que permiten personalizar el funcionamiento del plugin:
1. Indicar la ruta hacia el comando “nm”. Esto es fundamental para que
el plugin pueda funcionar en cualquier instalación que el usuario haya podido hacer de las herramientas de compilación.
22
1
3
Capítulo 3. Diseño e Implementación
p r i v a t e void c r e a t e V i e w e r ( Composite p a r e n t ) {
viewer = new CheckboxTableViewer ( new Table ( parent ,
createColumns ( parent , viewer ) ;
... ) );
viewer . s e t C o n t e n t P r o v i d e r ( new ArrayContentProvider ( ) ) ;
viewer . s e t I n p u t ( A c t i v a t o r . getModel ( ) . getSymbols ( ) ) ;
g e t S i t e ( ) . s e t S e l e c t i o n P r o v i d e r ( viewer ) ;
5
7
viewer . a d d C h e c k S t a t e L i s t e n e r ( new I C h e c k S t a t e L i s t e n e r ( ) {
@Override
p u b l i c void checkStateChanged ( CheckStateChangedEvent event ) {
O b j e c t [ ] ce = viewer . getCheckedElements ( ) ;
A c t i v a t o r . getModel ( ) . s e t E n a b l e d L i s t ( ce ) ;
}
}) ;
9
11
13
15
}
17
19
p r i v a t e void createColumns ( f i n a l Composite parent , f i n a l
TableViewer viewer ) {
S t r i n g [ ] t i t l e s = { "Name" , " S i z e " , " S e c t i o n " } ;
i n t [ ] bounds = { 2 0 0 , 1 0 0 , 100 } ;
21
// name column
TableViewerColumn c o l = createTableViewerColumn ( t i t l e s [ 0 ] ,
bounds [ 0 ] , 0 ) ;
c o l . s e t L a b e l P r o v i d e r ( new ColumnLabelProvider ( ) {
@Override
p u b l i c S t r i n g g e t T e x t ( O b j e c t element ) {
Symbol p = ( Symbol ) element ;
r e t u r n p . getName ( ) ;
}
}) ;
23
25
27
29
31
// s i z e column
// s e c t i o n column
33
}
35
37
39
41
43
45
47
p r i v a t e S e l e c t i o n A d a p t e r g e t S e l e c t i o n A d a p t e r ( f i n a l TableColumn
column , f i n a l i n t index ) {
S e l e c t i o n A d a p t e r s e l e c t i o n A d a p t e r = new S e l e c t i o n A d a p t e r ( ) {
@Override
p u b l i c void w i d g e t S e l e c t e d ( S e l e c t i o n E v e n t e ) {
comparator . setColumn ( index ) ;
i n t d i r = comparator . g e t D i r e c t i o n ( ) ;
viewer . g e t T a b l e ( ) . s e t S o r t D i r e c t i o n ( d i r ) ;
viewer . g e t T a b l e ( ) . setSortColumn ( column ) ;
viewer . r e f r e s h ( ) ;
}
};
return selectionAdapter ;
}
Figura 3.7: Fragmentos del código que genera la lista completa de símbolos del plugin.
2. Indicar la ruta hacia el archivo binario que se analizará. Si bien las
prácticas habituales en el desarrollo de plugins dictan que el mismo
3.2. Desarrollo del plugin
23
reconozca automáticamente en qué proyecto está trabajando el usuario y que de este mismo se pueda inferir cuál es el archivo a analizar,
las limitaciones de tiempo no permitieron lograr esta funcionalidad
y por esta razón debe indicarse al plugin cuál archivo se usará. Esta
mejora quedó para un próximo avance del trabajo como se puede ver
en la sección 5.2.
3. Tamaño de la memoria de código y datos del microcontrolador en
uso. Estos dos valores son para completar la presentación de la información, permiten calcular el espacio libre en cada una.
Para acomodar estas opciones fue necesario agregar un diálogo o pantalla de configuración del plugin. El mismo se muestra a continuación en la
figura 3.8.
Figura 3.8: Diálogo de opciones de configuración
3.2.9.
Depuración del plugin
El proceso de depuración es realmente sencillo, teniendo presente que
se está generando un agregado a la propia plataforma de desarrollo y que
la misma es sobresaliente a la hora de trabajar en el lenguaje Java.
Para probar el plugin no se puede hacer otra cosa que iniciar una nueva
ventana instancia de Eclipse donde el plugin está incorporado. Esto puede
ser algo lento si el computador en el que se hace el desarrollo no tiene un
hardware moderno. Al momento de escribir este trabajo el autor acababa
de adquirir un disco rígido de estado sólido y se pudo apreciar la ventaja
de los tiempos reducidos de carga que los mismos ofrecen.
El otro aspecto importante es que debido a las características técnicas de
Java, es posible reemplazar un pedazo del código en ejecución “en caliente”, es decir sin tener que detener el programa e iniciarlo de nuevo.
Se puede concluir esta sección mencionando que la parte de manipulación de datos no tiene ninguna novedad para el progamador versado en
programación orientada a objetos. La dificultad radica en aprender a usar
correctamente las herramientas que ofrece la plataforma Eclipse, pero una
24
Capítulo 3. Diseño e Implementación
vez logrado esto se ve que son lo bastante completas y poderosas como para
que la programación se vea reducida a descubrir como indicar claramente
a la plataforma la funcionalidad deseada.
3.3.
Adopción de un algoritmo de treemapping
La pieza final de la solución es finalmente el algoritmo de treemapping
a usar.
3.3.1.
Resolución gráfica
El primer intento se hizo con una implementación propia del más elemental, “SliceAndDice”. El mismo funciona particionando el área gráfica
en rectángulos en una sola dirección.
Se asumía que el área donde se dibujaría sería más ancha que alta y
por tanto cada fracción del tamaño total a representar se dibujaba mediante
un rectángulo con orientación vertical donde su ancho representaba el alto
del símbolo. Esto expuso inmediatamente la problemática de la representación gráfica: Supóngase que se está graficando en un rectángulo de 800x600
píxels un mapa de memoria de un microcontrolador de 512 Kbytes de memoria de código (una situación cotidiana, esa capacidad la tiene el LPC1769
que es el microcontrolador usado en el kit LPCXpresso usado ampliamente
en numerosas universidades en los últimos años). Un sencillo cálculo arroja
que hay que representar 524288 bytes en un rango de 800 píxels. Esto arroja
unos 655 bytes por píxel, de lo que se puede inferir que una cantidad de
memoria de menos de 655 bytes no amerita un píxel en la pantalla.
Ese tamaño de memoria genera una muy mala resolución gráfica, en la
práctica cotidiana lo suelen ocupar solamente los buffers de comunicación
y algunas estructuras de control de ciertos protocolos con muchos campos
de texto. Lo mismo ocurre en la sección de código, quedarían ocultas en el
gráfico numerosísimas funciones y resultaría un análisis muy pobre de la
ocupación de memoria.
La situación cambia al partir el espacio como sugiere Schneiderman,
alternando las dimensiones horizontal y vertical. En este caso un área de
800x600 píxels representa permite representar los 524288 bytes mediante
480000, quedando casi un pixel por byte. Es en este punto que se comenzó a buscar la adaptación de uno de los algoritmos implementados por la
Universidad de Maryland en lugar de seguir con el propio.
Estos algoritmos se pueden descargar libremente del Human-Computer
Interaction Laboratory (HCIL) [5]. Al estar desarrollados en Java es sencillo
integrarlos al plugin desarrollado. En este paquete de software se incluye
una aplicación de demostración que genera una lista de 20 rectángulos con
tamaños aleatorios distribuidos en forma Gaussiana y los dibuja en una
ventana. Esto permite experimentar con los distintos algoritmos y elegir el
más conveniente.
Se recordará que Shneiderman [4] los clasifica según tres atributos que
se analizan a continuación.
3.3. Adopción de un algoritmo de treemapping
3.3.2.
25
Relación de aspecto
Shneiderman define la relación de aspecto de un rectángulo en su paper
como “el mayor de ancho/alto y alto/ancho”, y luego dice “usando esta definición, cuanto menor sea la relación de aspecto de un rectángulo, más parecido a un
cuadrado es. Un cuadrado tiene una relación de aspecto de 1, que es el mínimo valor
posible.”
Figura 3.9: Treemaps con una relación de aspecto promedio
muy alta, producido por el algoritmo “Slice and dice”. A la
izquierda aplicado a un solo nivel de datos. A la derecha,
aplicado a datos organizados jerárquicamente.
La relación de aspecto resulta la principal métrica de calidad de un treemap por dos motivos:
Como se puede apreciar en la figura 3.9 resulta mucho más sencillo
comparar tamaños relativos de cuadrados que de franjas. Los humanos tendemos a percibir la información visual buscando una suerte
de “centro de masa” de la misma, o un punto central sobre el que se
pueda sacar una conclusión rápida sin tener que explorar el detalle
completo. Los cuadrados tienen esta propiedad, dado que se puede
percibir rápidamente que la figura es cuadrada explorándola visualmente en cualquier dirección. El rectángulo sin embargo obliga a recorrer la dirección en la que es más largo hasta encontrar el borde.
De acuerdo al análisis anterior sobre la resolución gráfica, los rectángulos con relación de aspecto muy alta obligan a dibujar franjas que
corren el riesgo de caer por debajo de la resolución mínima y por ende
desperdiciar pixels.
3.3.3.
Preservación del orden de los datos
La propiedad de ordenamiento de un treemap es su capacidad de preservar en la representación gráfica el orden que pudiera existir en los datos
a mostrar.
Al analizar este punto debe tenerse presente el uso que se da a los treemaps como herramienta de visualización. Schneiderman dice en su paper:
26
Capítulo 3. Diseño e Implementación
“muchos conjuntos de datos contienen información de ordenación que es útil para ver patrones o para localizar objetos particulares en el mapa. Por ejemplo, los
datos de bonos descritos en Johnson[1994] están ordenados naturalmente por fecha de madurez y tasa de interés. En muchos otros casos, el orden de los datos es
alfabético”.
Haciendo foco en los datos que se buscaron representar en este trabajo,
se puede ver que en el mapa la información de nombre del símbolo no genera una ordenación que se deba preservar, y lo mismo pasa con la sección
de memoria a la que pertenece cada uno ya que es muy sencillo dibujar un
mapa para cada una haciendo uso del campo de filtrado.
En una futura versión del plugin desarrollado sería util poder mostrar el
agrupamiento de los símbolos según el archivo en el que fueron declarados
y estos según la biblioteca a la que pertenecen. En ese caso sí sería de interés
elegir un algoritmo de treemapping que preservara este orden, pero esta
posibilidad queda por fuera del presente trabajo.
3.3.4.
Estabilidad de los datos
La estabilidad de los datos se refiere a cuánto cambian de posición los
rectángulos en un mapa al cambiar sus datos de entrada. Esto debe pensarse
para el caso de visualizar datos dinámicos como por ejemplo cotizaciones
de acciones de la bolsa de valores.
Una buena estabilidad hace que al mirar y asimilar un mapa, si sus datos cambian de alguna manera un símbolo representando un valor en particular no se mueva drásticamente en el mapa. Se dice que un algoritmo es
inestable cuando un cambio en el tamaño de un rectángulo hace que el mismo deba dibujarse en un lugar distinto (imagínese la progresión desde la
esquina inferior derecha a la superior izquierda de un rectángulo a medida
que crece en tamaño).
Si bien es una propiedad muy importante, en el trabajo presente los datos a representar no tienden a cambiar bruscamente salvo cuando se está
optimizando la asignación de la memoria.
3.3.5.
Algoritmo elegido
Habiendo ponderado las tres propiedades de los cinco algoritmos disponibles, se eligió “Squarified” como el más apropiado por ser el que da
mejor relación de aspecto. Esta característica se juzgó de mayor importancia que las otras dos. En la figura 3.10 se muestra el proceso mediante el
cual el algoritmo particiona el espacio disponible en subrectángulos, buscando la mejor relación de aspecto y perdiendo cualquier otro orden que
los datos pudieran tener.
3.3. Adopción de un algoritmo de treemapping
Figura 3.10: Particionado del espacio disponible en rectángulos, según el algoritmo “Squarify”. Figura tomada de [6]
27
29
Capítulo 4
Ensayos y Resultados
4.1.
Precisión del análisis de la tabla de símbolos
El presente trabajo se basó en la siguiente hipótesis: La suma de la totalidad de los tamaños en memoria reportados por nm para los símbolos de
cada sección tiene como resultado el tamaño total ocupado en la memoria
del microcontrolador. Para esta hipótesis se realizó el siguiente ensayo.
4.1.1.
Precisión de la identificación de secciones de la herramienta
nm
Se ha dicho en la subsección 2.2.2 que la herramienta nm asigna una
letra (’t’, ’b’ o ’d’) a cada símbolo que encuentra en su análisis de la tabla de símbolos y que cada una corresponde a una sección. En el apéndice
A se presenta un programa de prueba con símbolos de distintos tamaños
ubicados en las distintas secciones, usado como patrón de referencia para
verificar que el reporte es correcto.
El lector puede buscar la definición de los segmentos .text, .bss y .data
en [2] y [3]. De todos modos se presenta a continuación una breve reseña:
.text Sección de memoria donde se ubican las instrucciones de máquina a
ejecutar por el microprocesador. Esta sección de memoria no se modifica durante la ejecución del programa (existen excepciones a esta
regla pero su discusión no es relevante a este ensayo).
.bss Sección de memoria reservada a variables que no tienen un valor inicial dado.
.data Sección de memoria reservada a variables que sí tienen un valor inicial dado por el programador. Este valor inicial se almacena en la memoria de programa (sección .text) y tiene un impacto en la misma.
Los valores reportados por el plugin desarrollado se contrastaron contra la herramienta “size” [12], cuyo propósito es listar “los tamaños de las
secciones -y el tamaño total- de cada objeto (. . . ) en su lista de argumentos. . . )”.
La salida del mismo se muestra en la figura 4.1 como ejemplo, con la salvedad de que los valores reportados son arbitrarios y no deben tomarse como
parte del ensayo.
El programa de prueba se generó partiendo de un asistente (wizard)
para un nuevo proyecto utilizando las librerías LPCOpen en el entorno
LPCXpresso 8.1.4, e incluye las librerías estáticas “lpc_chip_ 175x_6x” y
“lpc_board_nxp _lpcxpresso_1769”. Luego se declararon las variables necesarias para el ensayo.
De acuerdo a Erich Styger [16], el resultado esperado es el siguiente:
30
Capítulo 4. Ensayos y Resultados
arm-none-eabi-size "TestProject1.axf"
text
data
bss
dec
hex filename
4004
200
8
4212
1074
TestProject1.axf
Figura 4.1: Imagen de la salida del size al analizar el programa de prueba.
En la sección .bss se espera que la suma de los tamaños reportados
por nm ocupe exactamente el tamaño reportado por el comando size.
En la sección .data se espera lo mismo.
En la sección .text hay que ponderar otras cuestiones que ponderar,
ya que se sabe que a veces los compiladores organizan las funciones
en direcciones de memoria múltiplo de 2 o 4 para optimizar el acceso
a las funciones y sobre esto no se encontró mención en la documentación del comando “size”. También hay una situación con las declaraciones “Weak”, que son funciones definidas con cierto nombre pero
que luego el programador puede sobreescribir (es decir, agregar una
segunda definición de esa función) y no está claro cómo se contabiliza
esto tampoco.
En este caso, el ensayo consiste en inspeccionar los totales reportados
por el plugin y compararlos contra la salida del comando size.
4.1.2.
Resultados del ensayo
La suma de los tamaños de las variables ubicadas en la sección .bss tuvo
un error de 3 bytes. Como se puede ver en la figura 4.2, size reportó 172
bytes y el plugin identificó lo esperado por el programador que fueron 165.
4 de esos 172 se encuentran en la variable SystemCoreClock, que no la declara el programador sino una de las librerías que incluye el programa de
ejemplo.
La figura 4.3 muestra que en la sección .data se encontró la misma discrepancia de 3 bytes.
En ambos casos (.bss y .data ) se considera despreciable el error de 3
bytes por la siguiente razón: Al trabajar con procesadores con una arquitectura de 32 bits, una declaración de variable de tipo int (el valor genérico
de un entero sin aplicarle ningún calificador ni modificador) ocupa 4 bytes,
por esta razón podría pensarse que 4 bytes es a efectos prácticos la resolución de la medición o la mínima variación del dígito menos significativo.
Por lo tanto una discrepancia inferior a 4 bytes no afecta la medición de
ninguna manera.
La figura 4.4 deja ver que en la sección .text sí se registraron algunas
discrepancias, a saber:
1. El comando size reportó 4204 bytes.
2. La sumatoria de los tamaños reportados en la sección .text fue de 3846
bytes.
4.1. Precisión del análisis de la tabla de símbolos
31
Figura 4.2: Vista de la sumatoria del tamaño de los símbolos
en la sección .bss
Figura 4.3: Vista de la sumatoria del tamaño de los símbolos
en la sección .data
3. El plugin por ahora no identifica símbolos con el atributo Weak, pero una exploración manual del archivo binario con el comando nm
mostró 274 bytes en símbolos con ese atributo.
Obviando las declaraciones “weak”, la diferencia es de 358 bytes o del
8,5 %. Si en cambio se suman esos 274 bytes la discrepancia baja a 84 bytes o
un 2 %. Debe notarse que la suma reportada por el plugin es en ambos casos
menor a lo reportado por el comando size, con lo cual se puede inferir que
el mismo contabiliza otras cosas además de la sumatoria de los símbolos
ubicados en dicha sección.
No se encontró documentación acerca de cómo exactamente contabiliza
el tamaño de la sección .text el comando size. Esto impidió incrementar la
precisión del análisis más allá del 8,5 % reportado en este caso. En una futura revisión de este trabajo se puede encontrar esta información haciendo
32
Capítulo 4. Ensayos y Resultados
Figura 4.4: Vista de la sumatoria del tamaño de los símbolos
en la sección .text
un análisis del código fuente del mismo, disponible en [8]. Esta posibilidad
quedó fuera del presente trabajo debido a limitaciones de tiempo.
Finalmente, se concluye que si bien un 8,5 % de diferencia no es lo bastante bueno como para dimensionar un microcontrolador para una aplicación, no se afecta el cumplimiento de ninguno de los requerimientos del
proyecto.
4.2.
Consumo de recursos de hardware causado por el
plugin
Otro ensayo que se consideró relevante realizar es evaluar el impacto
que el plugin causa en los recursos del computador en uso.
Se midió el tiempo de procesamiento que lleva dibujar el treemap y se
descartó la posibilidad de medir la memoria solicitada por el plugin. Las
aplicaciones en Java se ejecutan en una instancia de la JVM (Máquina Virtual Java) con una cantidad de memoria disponible predefinida, y durante
el desarrollo del plugin la misma nunca se agotó. Al no haber sido necesario agrandar la cantidad de memoria disponible para la JVM en cuestión se
concluyó que el consumo de memoria no resulta problemático.
4.2.1.
Medición del tiempo de procesamiento
Para esta medición se usa el método “nanoTime” incluído en el lenguaje
Java [7]. El mismo “Devuelve el valor actual del temporizador más preciso del
sistema, en nanosegundos”.
Este ensayo no buscó una medición exacta sino conocer el orden de
magnitud del tiempo invertido para determinar si el uso del plugin entorpece la labor cotidiana del programador.
El ensayo se realizó en las siguiemtes condiciones:
4.3. Validación con usuarios finales
33
Hardware: Computador portátil Asus K455L [15], al que se agregaron
4GB de memoria RAM adicionales para un total de 12Gb y se le reemplazó el disco rígido mecánico por uno de estado sólido Samsung
EVO 850 de 250Gb.
Sistema operativo: Ubuntu Mate 16.04, 64 bits, con el kernel 4.6.0040600rc6-generic.
Versión de Java: openjdk version “1.8.0_91”.
Versión de Eclipse: Mars 4.5.2.
Se compiló el programa de prueba como figura en el apéndice A.
El procedimiento de ensayo fue el siguiente:
1. Se tomó el tiempo actual del sistema con la funcion nanoTime.
2. Se provocó el redibujo del mapa dentro de un lazo cien veces.
3. Se tomó el tiempo final del ensayo.
4. Se lo dividió por cien.
5. Se repitieron los puntos anteriores 30 veces y se anotaron los resultados.
6. Se buscaron los valores mínimo y máximo.
7. Se sacó el promedio y el desvío estándar.
4.2.2.
Resultados del ensayo
Se observaron los siguientes valores (en microsegundos): 453, 612, 436,
819, 463, 729, 752, 429, 499, 772, 396, 504, 534, 761, 406, 400 393, 792, 403, 392,
409, 408, 395, 393, 389, 395, 436, 476, 392, 390.
Las mediciones presentan un promedio de 501 uS, y un desvío estándar
de 147 uS. El valor mínimo es de 389 uS y el máximo es de 819 uS.
El promedio se ponderó contra el tiempo que conlleva el proceso de
compilación (en la corrida de prueba fue reportado en 324ms) y resultó
despreciable. En segunda instancia se aplicó un criterio más estricto que
fue el de redimensionar la ventana que contiene el mapa (esto implica un
redibujo de la misma así sea que el tamaño cambia en un solo píxel) y no
se observó ningún enlentecimiento de la interfaz. Si bien esta apreciación
es puramente subjetiva se la puede tomar como un criterio de máxima y el
resultado es satisfactorio.
4.3.
Validación con usuarios finales
El paso final para la validación de un software nuevo es la llamada
“Beta-test”: una prueba previa a su distribución realizada por parte de una
muestra de los usuarios finales. A los usuarios que participan de esta prueba se los llama “Beta-testers”.
34
Capítulo 4. Ensayos y Resultados
Se dice que el software está en estado “Beta” cuando no ha sido utilizado aún por su público objetivo pero que ya está lo bastante maduro como
para un primer contacto con el mismo. Es fundamental hacer estas pruebas porque los usuarios no tienen el conocimiento interno del software que
tienen los desarrolladores del mismo, y por lo tanto tienen una perspectiva
imparcial sobre el uso y capacidades del mismo. De estas pruebas se espera que los testers descubran defectos y/o aporten nuevas perspectivas que
hayan escapado a la óptica del programador.
Cuando el software no ha llegado aún a este punto se lo llama “Alfa”.
Un software en este estado funciona bien en la medida que lo use una persona que conoce los defectos y limitaciones del mismo y lo use dentro de
estas.
Tanto en la industria del software como en la comunidad del software
libre, se suele buscar que las “Beta-tests” lleguen a la mayor cantidad de
usuarios posibles y en algunos casos se pide a los “Beta-testers” que previo a su participación informen algunos datos personales. Esto se hace para
tener un volumen significativo de realimentación acerca del uso del software y poder ponderarlo de acuerdo al perfil de los testers. Si bien este es
el procedimiento que aporta mayor valor estadístico, requiere de un equipo de personas que procese los reportes recibidos y que pueda actuar en
consecuencia. Al ser este un desarrollo académico hecho por un solo programador se optó en cambio por armar un “focus-group”, o una pequeña
muestra formada por un grupo reducido de usuarios con perfiles bien diferenciados que represente a un grupo genérico de usuarios.
A quienes se les envió el software para evaluar también se les sugirió el
siguiente cuestionario con impresiones que se buscaban recabar acerca del
uso del software:
1. La instalación es confusa o se parece a cualquier otro plugin?
2. En qué variante y versión de Eclipse lo instalaron?
3. Las instrucciones le sirvieron para instalar y usar el software?
4. El uso del software resulta intuitivo?
5. El software le resultó útil?
6. El uso del software hizo que se ponga lento el entorno donde fue instalado?
7. Alguna otra impresión que le haya causado?
Los siguientes son los reportes que se alcanzaron a recibir a la fecha de
cierre de este trabajo, sin ningún orden particular.
4.3.1.
Esp. Ing. Pablo Ridolfi
Pablo Ridolfi es Ingeniero en electrónica, graduado de la UTN-FRH.
También tiene el título de Especialista en Sistemas Embebidos. Actualmente
es coordinador general del proyecto CIAA.
4.3. Validación con usuarios finales
35
1. Tuve que deshabilitar la opción de mostrar por categorías, sino no
aparece nada. Salvo eso (fijate si lo podés corregir y te vas a ahorrar un
montón de comentarios tipo "no me aparece nada") instaló perfecto,
avisando que no está firmado digitalmente.
2. LPCXpresso v8.1.4 [Build 606] [2016-03-14]
3. Sí, sirvieron, al menos yo lo entendí, pero es obvio que no somos novatos. Deberías mandarle esto a un alumno que recién está empezando
para ver si lo puede hacer.
4. Sí, pero idem anterior.
5. Creo que si estuviera justo de recursos y necesito hacer un análisis
para priorizarlos me resultaría útil.
6. No.
7. Estaría bueno poder hacer zoom en el treemap. Cuando hay mucha
RAM/Flash libre lo demás te queda muy chiquito, aunque se pueden
deshabilitar las áreas “Free ROM” y “Free RAM”. Al menos agregaría
una opción tipo toolbar sobre el treemap para deshabilitarlas rápidamente y ver sólo lo que está ocupando espacio. Por lo demás me
parece muy copado lo que hiciste, felicitaciones!
4.3.2.
Ing. Mirko Serra
Mirko Serra es Ingeniero en electrónica, graduado de la UTN-FRBA. Se
dedica al desarrollo de sistemas embebidos en forma independiente.
1. Hay que asegurarse de que no esté tildado Group items by category
para que lo muestre cuando se instala localmente. En el caso del servidor lo muestra dentro de la categoría ESMP.
2. LPCXpresso v8.1.4 [Build 606] [2016-03-14].
3. Lo quise instalar en el Eclipse que tenía funcionando y no andaba. Resulta que es una versión vieja. Me deja instalarlo pero no encontraba
el Memory Profiler.
4. No encontré la forma fácil de visibilizar todo de una. Vine a la captura
que me mandaste vos y ahí pude visibilizarlos poniendo en Quick
Access una por una las vistas de Treemap Views, Symbol List, Filtered
Symbol List.
5. Resulta MUY práctico el manejo general. Elijo Text y tengo una idea
del uso de memoria (libre vs ocupada); hago click en el cuadrado
grande, lo destildo y saqué la memoria libre de la ecuación y puedo
ver el uso desde el programa.
6. No.
7. La pestaña Memory Profiler aparece vacía. Sería bueno que apareciera
convalores por defecto.
37
Capítulo 5
Conclusiones
5.1.
Grado de cumplimiento de los requerimientos del
proyecto
Para beneficio del lector se reproducen los 4 objetivos originales del proyecto, luego se analiza el grado de cumplimiento de cada uno en particular:
1. Representación visual del uso de la memoria interna del MCU.
2. Fácil identificación de los principales consumos de memoria.
3. Indicación de a qué zona de memoria fue asignada cada variable.
4. Presentación de estos datos dentro de una ventana de Eclipse.
La figura 5.1 muestra el resultado final del plugin y sirve de sustento al
análisis siguiente.
Figura 5.1: Resultado final del desarrollo
5.1.1.
Representación visual del uso de la memoria interna del
MCU
El primer objetivo se considera perfectamente logrado. Al incluirse un
símbolo representando la memoria disponible (el recuadro oscuro de mayor tamaño), al usuario no le quedan dudas de que lo que está mirando
38
Capítulo 5. Conclusiones
inicialmente es la memoria completa del microprocesador, y con esto en
mente, se pueden hacer rápida y visualmente varios análisis:
Determinar el grado de ocupación del CPU, algo sumamente útil en
el desarrollo para saber si el microprocesador está bien dimensionado
para el desarrollo o si será menester cambiarlo.
Discernir si es provechoso optimizar el uso de memoria de la aplicación. Se sabe que todo proceso de optimización tiene un punto de
rendimientos decrecientes, esto es un punto a partir del cuál el tiempo
invertido en mejorarlo rinde menos que los beneficios obtenidos. En
el caso de una aplicación con microprocesador, este es el punto en el
que el gasto principal de memoria no está concentrado en unos pocas
variables sino que hay numerosas variables que ocupan 4 o 2 bytes
cuando podrían haber ocupado 2 o 1.
Si resultara provechoso hacer un proceso de optimización, sería evidente el punto de partida del mismo.
5.1.2.
Fácil identificación de los principales consumos de memoria
El segundo objetivo también se considera logrado al 100 %. El autor considera que la representación visual mediante tamaños relativos es mucho
más rápida de asimilar que extraer información numérica de una tabla, tenga esta el formato que tenga. Como ejemplo de esto se puede citar el diseño
de los tableros de mandos de las aeronaves comerciales, en el que un piloto
debe monitorear una cantidad apreciable de indicadores y por esta razón se
prefieren indicadores del tipo de aguja en lugar de indicadores numéricos.
Esto último permite hacer una rápida inspección visual y detectar rápidamente una aguja con una inclinación distinta a las demás.
Adicionalmente, el proceso de obtener información numérica para procesarla conlleva un pequeño esfuerzo mental que si bien es despreciable en
cada ocasión, a lo largo de un día completo de trabajo acumula un gasto
que redunda en un cansancio adicional y una caída en la productividad del
programador.
5.1.3.
Indicación de a qué zona de memoria fue asignada cada variable
El objetivo número 3 también está logrado. Esta información se ve no
en los mapas gráficos sino en las listas de símbolos completa y filtrada,
ambas tienen una columna llamada “Section” donde se expone el nombre
de la sección en la que el compilador ubicó cada símbolo. Este objetivo no
se ha logrado en la misma medida que los demás, ya que esta ubicación sí
se debe obtener de una tabla con los perjuicios mencionados anteriormente.
Se podría haber utilizado una segunda paleta de colores para diferenciar las
distintas secciones en el mapa gráfico, pero se consideró que no reportaría
un beneficio significativo. Esto sumado a la falta de tiempo hizo que esta
funcionalidad quedara por fuera del proyecto.
5.2. Próximos pasos
5.1.4.
39
Presentación de estos datos dentro de una ventana de Eclipse
El último objetivo se logró también por completo. La figura 5.1 habla
por sí misma en este punto.
5.2.
Próximos pasos
Si bien el proyecto logró sus objetivos iniciales, durante el desarrollo
se identificaron varias posibilidades de mejora que el tiempo no permitió
abordar, pero que de todos modos se listan a continuación con la esperanza
de que este trabajo pueda ser continuado por otra persona o por el mismo
autor en el camino de una maestría.
Mejorar la precisión de la medición de la sección .text Como se mencionó
en la sección 4.1.1 la medición de la ocupación de la memoria de código tiene un error apreciable, pero hay fuentes de información que
permiten seguir investigando este tema cuando el tiempo lo permita.
Extensión al lenguaje C++ El mismo presenta algunos desafíos a la hora
de identificar los nombres de los símbolos ya que el compilador los
deforma en pos de soportar algunas características avanzadas del lenguaje. Esta dificultad se evitó en esta instancia del trabajo.
Agrupación jerárquica de librerías y módulos El algoritmo actual dibuja
los símbolos ordenados por tamaño, sin que se pueda apreciar en qué
archivo fueron declarados. A veces en el desarrollo puede ser útil ver
la jerarquía de qué símbolos provienen de qué archivos y a su vez
qué archivos forman qué bibliotecas de código. Esto se obvió ya que
no forma parte de los requerimientos del proyecto, pero resulta una
buena adición en una próxima etapa.
Distribución automatizada En la jerga se le llama a esto “deployment”. En
este ámbito se refiere al proceso mediante el cual se construye y empaca el software para su distribución a los usuarios finales del mismo.
Actualmente esto se hace con unos cuantos procedimientos manuales
que resultan algo tediosos. Se experimentó someramente con programas para hacer la distribución automáticamente pero no se los pudo
poner en práctica por falta de tiempo.
Mejorar la integración del plugin con la interfaz de usuario de Eclipse El
programador con experiencia en el uso de Eclipse como herramienta
de programación seguramente notará que si bien el plugin desarrollado cumple con su función, resuelve algunas cuestiones de forma
diferente a lo esperado. Esto se debe a la inexperiencia desarrollando plugins del autor de este trabajo (recuérdese que este es el primero
que escribe), en un próximo avance esta situación debería remediarse.
Representación gráfica de vectores y estructuras como mapas anidados Para
beneficio del lector inexperto en software se recuerda que los vectores
son una suerte de listas de elementos donde todos son del mismo tipo, y que las estructuras son agrupaciones de elementos que pueden
40
Capítulo 5. Conclusiones
ser de distintos tipos. Lo que ambos tienen en común es que son conjuntos de varios elementos, y en su representación en el mapa podría
hacerse esta distinción. Esta posibilidad se descartó porque no aporta a ninguno de los requerimientos iniciales del proyecto, servirían
como un refinamiento gráfico.
I18N I18N es una suerte de abreviatura de la palabra inglesa “internationalization” (se cuentan 18 letras entre la ’I’ y la ’N’) y representa el
proceso de traducir fácilmente una aplicación a varios idiomas. En el
plugin actual no se contempló esta posibilidad sino que se optó por
usar el idioma inglés en la interfaz de usuario para llegar a la mayor cantidad de usuarios posibles. En un futuro desarrollo se debería
poder traducir la interfaz de usuario a otros idiomas.
41
Apéndice A
Programa usado para los
ensayos de medición
42
2
4
//
//
//
//
Apéndice A. Programa usado para los ensayos de medición
Name
Author
Version
Description
:
:
:
:
TestProject1 . c
Ing . Alejandro Celery
1.0
Programa para ensayar mediciones de nm
6
8
# i n c l u d e " board . h "
# i n c l u d e < c r _ s e c t i o n _ m a c r o s . h>
# i n c l u d e < s t d i n t . h>
10
# d e f i n e N 10
12
14
16
18
20
int8_t
int16_t
int32_t
int64_t
int8_noInit ;
int16_noInit ;
int32_noInit ;
int64_noInit ;
int8_t
int16_t
int32_t
int64_t
i n t 8 _ n o I n i t _ v e c 1 0 [N] ;
i n t 1 6 _ n o I n i t _ v e c 1 0 [N] ;
i n t 3 2 _ n o I n i t _ v e c 1 0 [N] ;
i n t 6 4 _ n o I n i t _ v e c 1 0 [N] ;
int8_t
int16_t
int32_t
int64_t
int8_init
int16_init
int32_init
int64_init
int8_t
int16_t
int32_t
int64_t
i n t 8 _ i n i t _ v e c 1 0 [N]
i n t 1 6 _ i n i t _ v e c 1 0 [N]
i n t 3 2 _ i n i t _ v e c 1 0 [N]
i n t 6 4 _ i n i t _ v e c 1 0 [N]
22
24
26
28
30
=
=
=
=
0 x12 ;
0 x1234 ;
0 x12345678 ;
0 x1234567812345678 ;
=
=
=
=
{
{
{
{
0 x12 } ;
0 x1234 } ;
0 x12345678 } ;
0 x1234567812345678 } ;
32
i n t main ( void ) {
34
SystemCoreClockUpdate ( ) ;
Board_Init ( ) ;
Board_LED_Set ( 0 , t r u e ) ;
36
38
i n t i = 0 ; // V a r i a b l e l o c a l , no s a l e en e l r e p o r t e
40
while ( 1 )
for ( i
if (
if (
if (
if (
42
44
46
if
if
if
if
48
50
(
(
(
(
{
= 0 ; i < N; ++ i ) {
int8_init > 0 ) int8_noInit =
int16_init > 0 ) int16_noInit
int32_init > 0 ) int32_noInit
int64_init > 0 ) int64_noInit
1;
= 1;
= 1;
= 1;
int8_init_vec10 [ i ] > 0 ) int8_noInit_vec10 [ i ] =
int16_init_vec10 [ i ] > 0 ) int16_noInit_vec10 [ i ]
int32_init_vec10 [ i ] > 0 ) int32_noInit_vec10 [ i ]
int64_init_vec10 [ i ] > 0 ) int64_noInit_vec10 [ i ]
}
}
return 0 ;
52
54
}
Figura A.1: Programa usado para contrastar los reportes del
plugin contra el comando size.
1;
= 1;
= 1;
= 1;
43
Bibliografía
[1] Artículo de Wikipedia sobre Eclipse. [Online]. Disponible: https : / /
es . wikipedia . org / wiki / Eclipse _ (software). Fecha de
última actualización. 2016.
[2] Artículo de Wikipedia sobre el segmento de código. [Online]. Disponible:
https://en.wikipedia.org/wiki/Code_segment. Fecha de
última actualización. 2016.
[3] Artículo de Wikipedia sobre el segmento de datos. [Online]. Disponible:
https://en.wikipedia.org/wiki/Data_segment. Fecha de
última actualización. 2016.
[4]
B. B. Bederson, Ben Shneiderman y Martin Wattenberg. «Ordered and
Quantum Treemaps: Making Effective Use of 2D Space to Display
Hierarchies». En: ACM Transactions on Graphics 21.12 (oct. de 2002),
págs. 833-854. URL: http://portal.acm.org/citation.cfm?
doid=571647.571649.
[5]
Ben Bederson y Martin Wattenberg. Librería de algoritmos de treemapping. [Online]. Disponible: www . cs . umd . edu / hcil / treemap history/Treemaps-Java-Algorithms.zip.
[6]
Mark Bruls, Kees Huizing y Jarke van Wijk. «Squarified Treemaps».
En: In Proceedings of the Joint Eurographics and IEEE TCVG Symposium
on Visualization. Press, 1999, págs. 33-42.
[7] Documentación de la clase System, método nanoTime. [Online]. Disponible: http://docs.oracle.com/javase/1.5.0/docs/api/
java/lang/System.html. Fecha de consulta. 2016.
[8] Index of /gnu/binutils. [Online]. Disponible: https : / / ftp . gnu .
org/gnu/binutils/. Fecha de consulta. 2016.
[9] Manpage del comando nm. [Online]. Disponible: https://sourceware.
org / binutils / docs / binutils / nm . html. Fecha de consulta.
2016.
[10]
Manpage del comando objdump. [Online]. Disponible: https://sourceware.
org/binutils/docs/binutils/objdump.html. Fecha de consulta. 2016.
[11]
Manpage del comando pahole. [Online]. Disponible: http://linux.
die.net/man/1/pahole. Fecha de consulta. 2016.
[12]
Manpage del comando size. [Online]. Disponible: https://sourceware.
org/binutils/docs/binutils/size.html. Fecha de consulta.
2016.
[13]
Ben Shneiderman. Treemaps for space-constrained visualization of hierarchies. [Online]. Disponible: http : / / www . cs . umd . edu / hcil /
treemap-history/. Fecha de primera publicación. 1998.
44
BIBLIOGRAFÍA
[14] Sitio web coolors.co. [Online]. Disponible: https://coolors.co/
app. Fecha de consulta. 2016.
[15] Sitio web de Asus, descripción del producto usado para el ensayo. [Online]. Disponible: https://www.asus.com/latin/Notebooks/
X455LJ/specifications/. Fecha de consulta. 2016.
[16] text, data and bss: Code and Data Size Explained. [Online]. Disponible:
https://mcuoneclipse.com/2013/04/14/text-data-andbss- code- and- data- size- explained. Fecha de publicación.
2013.
[17]
Lars Vogel y Simon Sholz. Eclipse JFace Overview - Tutorial. [Online].
Disponible: http://www.vogella.com/tutorials/EclipseJFace/
article.html. Fecha de publicación. 2014.
[18] Windirstat. [Online]. Disponible: https://windirstat.info/.
Descargar