Verificando la optimización

Seré breve y solo les comentaré sobre una de las maneras de probar si el código realmente se está optimizando.

Utilizando el comando time que forma parte de los sistemas Unix-like podemos conseguir el tiempo que tarda en ejecutarse nuestro programa.
Esto incluye el tiempo real de computo( tiempo total de ejecucción ), el tiempo de usuario ( es el tiempo que tarda en los calculos y las llamadas al kernel ) y el tiempo de uso del sistema ( solo las llamadas al kernel ).
Podemos decir que cuando un programa esta haciendo iteraciones se esta acumulando tiempo de usuario solamente.

El resultado se nos despliega con

0m0.000s
minutos
segundos
milisegundos


El manual nos dice que el uso de este comando es de la siguiente forma:

time [options] command [arguments...]

para este caso solo nos interesan los tiempos así que no le daremos opciones.

Ejemplo:

int main(int argi,char *argv[]){                                                
  argi = 0;                                                                     
  puts("Inicio");                                                               
  while(!(argi == 1000000)){                                                    
      puts("Love,Love,Love");                                                   
      argi++;                                                                   
  }                                                                             
  puts("final");   
  return 0;                                                             
}


usaremos este codigo que imprime 1 millón de veces una cadena de caracteres.
Lo compararemos con este código que hace lo mismo, pero escrito en assembly con sintaxis de Intel.

section .data

hello:  db 'Inicio',10,13 
slong:  equ $-hello

notDone: db 'Love, Love, Love',10,13
notlong: equ $-notDone

done:  db 'final',10,13
donelong: equ $-done

 section .text
 global main 
main:
 mov eax,4
 mov ebx,1
 mov ecx,hello
 mov edx,slong
 int 0x80

 xor ecx,ecx

loop:
 push ecx
 mov eax,4
 mov ebx,1
 mov ecx,notDone
 mov edx,notlong
 int 0x80

 pop ecx
 add ecx,1
 cmp ecx,1000000  ;cantidad de ciclos
 jl loop

theend:
 mov eax,4
 mov ebx,1
 mov ecx,done
 mov edx,donelong
 int 0x80

Utilizamos el comando time de la siguiente manera:


*mande la salida de datos hacia /dev/null
 para evitar ver el millon de impresiones en pantalla*




time ./cicloAssembly > /dev/null  




time ./cicloC > /dev/null


Es obvio cual es mas eficiente, ¿no?.
Esto sucede porque el codigo en assembly hace una system call en cada ciclo, es decir realiza un millón de llamadas al kernel. Sumando ese millón de llamadas al kernel a las veces que ese proceso sufrio de un switch context, page faults o fue manipulado por el scheduler nos da un tiempo relativamente largo.

El ejecutable de C es mucho muy rapido por el simple hecho de no hacer llamadas al  kernel.

Ahora usare el comando gcc -S ciclo.c  y eliminare todas las lineas del GDB para despues compilarlo y apreciar si eliminando las lineas de debuggeo se logra optimizar un poco el ejecutable.

El codigo assembly quedo asi ( sin lineas de debuggeo ) 

.LC0:
 .string "Inicio"
.LC1:
 .string "Love,Love,Love"
.LC2:
 .string "final"
 .text
 .globl main
 .type main, @function
main:
.LFB0:
 pushl %ebp
 movl %esp, %ebp
 andl $-16, %esp
 subl $32, %esp
 movl $0, 28(%esp)
 movl $.LC0, (%esp)
 call puts
 jmp .L2
.L3:
 movl $.LC1, (%esp)
 call puts
 addl $1, 28(%esp)
.L2:
 cmpl $1000000, 28(%esp)
 jne .L3
 movl $.LC2, (%esp)
 call puts
 movl $0, %eax
 leave
 ret



time ./cicloCtoASM > /dev/null


Ahora vemos 2 cosas interesantes.

  1. El tiempo de usuario no cambio, es decir que para dicho programa queda claro que el tiempo que tarda en imprimir un millón de veces la cadena de caracteres es de 77 milisegundos y el tiempo real solo difiere de 1 milisegundo lo cual puede ser causa del scheduler.
  2. A pesar de ser un programa en assembly no se realizaron llamadas al kernel, es decir que como podemos ver en el codigo, solo se estan llamando las funciones del lenguaje C.

Con estas pruebas podemos darnos cuenta que el codigo assembly escrito desde scratch puede llegar a ser muy pesado y no tan eficiente en terminos de velocidad de ejecucción mas sin embargo es mas versatil porque puede utilizar alrededor de 190 system calls diferentes, ademas que se puede ver que el hecho de traducir el codigo de C hacia Assembly no quiere decir que este será reducido al nivel mas bajo de integración con el procesador.

Por mi parte mi tarea sobre lenguaje ensamblador no fue en pro de una optimización, fue dirigida hacia el uso de las system calls, pero para aquellos que buscaban optimización esta entrada puede ser útil.

Como recomendación: si quieren velocidad utilizen el puts() ya que es mucho mas rapido que el printf. Verifiquen el codigo.s si le llegan a poner mas de 1 millón de iteraciones en su codigo de C, por alguna extraña razón el codigo.s quedaba sin delimitantes haciendo un loop infinito, y también si llegan a usar un trillón de iteraciones no duden en irse por un café true story.

Referencia:
printf versus puts

Recursos adicionales de los microcontroladores

Independientemente de su arquitectura basica los microcontroladores incorporan recursos especificos a su modelo.

Algunos de ellos son:


  • Temporizadores.
  • Sensores guardianes.
  • Protectores contra fallo de alimentación.
  • Estado de reposo.
  • Conversor alterna a directa o directa hacia alterna.
  • Comparador analógico.
  • Modulador de anchura de pulsos (PWM)
  • Puertos de entrada y salida digitales.
  • Puertos de comunicación.

Temporizadores.

Timer 555 ejemplo de temporizador
Se utilizan para controlar periodos de tiempo y llevan por lo general un contador de las instrucciones que succeden mediante E/S. 
Para medir los tiempos, se carga un registro con el valor adecuado y a continuación dicho valor se va incrementando o decrementando al ritmo de los pulsos de reloj o algún múltiplo hasta que se desborde o llegue a 0, que es justo cuando se produce el aviso. Los contadores por lo general estan en alguna de las patitas del microcontrolador, y se va llenando un registro al igual que con el temporizador.


Sensores guardianes

Tambíen son llamados Watchdogs
En una computadora personal suele suceder que por un fallo del software se bloquea la computadora, y para que vuelva a funcionar tenemos que reiniciar el sistema. Un microcontrolador debe funcionar sin un supervisor y de forma continua mientras se le suministre corriente. El sensor guardián consiste en un temporizador que, cuando se desborda y para por 0, se provoca un reset automáticamente en el sistema. Los sistemas deben diseñar un programa que controle la tarea de forma que se refresque el sensor guardián antes de que provoque un reset, si el programa falla no se refresca el sensor guardiánm y al completar el ciclo, fallara hasta provocar un reset.




Protector contra fallo de alimentación

Es un circuito simple que resetea al microcontrolador cuando el voltaje de alimentacion ( comunmente el VDD ) es inferior al voltaje mínimo. Mientras el voltaje de alimentación sea inferior al minimo el dispositivo se mantiene reseteado, comenzando a funcionar hasta que se sobrepasa ese valor.

Estado de reposo.

En muchas ocasiones los microcontroladores estan diseñados para esperar sin hacer nada hasta que se produzca algún acontecimiento externo que lo pongo a funcionar. Para ahorrar energía, los microcontroladores disponen de una instrucción especial ( conocido como SLEEP ), que les pasa al estado de reposo o de bajo consumo, en el cual los requerimientos de potencia son mínimos. Dicho estado detiene el reloj principal y detiene sus circuitos asociados, quedando sumido en un sueño electronico. Al activarse una interrupción ocasionada por un acontecimiento el microcontrolador se despierta e inicia su trabajo.

Conversor A/D y D/A

Los microcontroladores pueden tener un conversor analógico a digital para procesar señales analógicas utilizando un multiplexor que permite aplicar a la entrada del conversor diversas señales desde las patitas analógicas de los circuitos integrados.
El conversor de datos digitales obtiene dichos datos del procesamiento de una computadora en su correspondiente señal analógica que saca al exterior por una de las patitas de la cápsula. La gran mayoria de los microcontroladores disponen de estos conversores para poder trabajar con la corriente electrica y señales.


Comparador analógico

Compración logica.
Por lo general los comparadores analógicos estan internamente agregados a los microcontroladores, los cuales disponen de un amplifícador operacional que actúa como comparador entre una señal fija de referencia y otra variable que se aplica por una de las patitas. La salida del comparador proporciona un nivel lógico 1 o 0 según una señal sea mayor o menor que la otra. También hay modelos de microcontroladores con un módulo de tensión de referencia que proporciona diversas tensiones de referencia que se pueden aplicar en los comparadores.



Modulador de anchura de pulso (PWM)

Ancho regulador con salida PWM
Estos circuitos permiten una salida de pulsos de anchura variable, es decir que se ofrecen al exterior a través de las patitas del microcontrolador una serie de salidas regulables analógicamente, para darle una cantidad especifíca de corriente.







Puertos de entrada y salida digitales

Basicamente es un interruptor
que decide si seran Entradas
o Salidas.
Estos puertos se agrupan por lo general en grupos de ocho en ocho formando puertos. Las líneas digitales de los puertos pueden configurarse como entrada o salida cargando un 1 o un 0 en el bit correspondiente de un registro destinado a la configuración.






Puertos de comunicación

Para poder comunicar el microcontrolador de la posibilidad de comunicarse con otros dispositivos, otros buses de microprocesadores, sistemas, redes y poder adaptarlos con otros elementos bajo protocolos especifícos, algunos modelos de microcontroladores le proporcionan recursos que permiten dichas tareas.
Algunos son:
  • UART ( adaptador de comunicación serie asíncrona ). El cual tiene como objetivo convertir los datos recibidos del bus del microcontrolador en formato paralelo, a un formato serie que será utilizado en la transmisión hacia el exterior.
  • USART ( adaptador de comunicación serie síncrona y asíncrona ). El cual es una puerta paralela esclava para poder conectarse con los buses de otros microprocesadores.
  • USB ( Universal serial bus ). El cual es el adaptador de comunicaciones síncronas y asíncronas mas moderno actualmente.
  • CAN ( Red de area del controlador ). El cual permite la adaptación con redes de conexionado multiplexado para el cableado de dispositivlos automóviles por ejemplo.

Referencias.

Lo basico de un microcontrolador


Un microcontrolador es un circuito integrado de alta escala de integracion
que incorpora la mayor parte de los elementos que configuran un controlador, dicho controlador el dispositivo que se emplea para el gobierno de uno o varios procesos.

Un microcontrolador dispone por lo general de lo siguiente:

  • Unidad central de procesamiento.
  • Memoria RAM para los datos que se contendran.
  • Memoria [ ROM | PROM | EPROM ] para el programa.
  • Linea de Entrada/Salida para comunicacion exterior.
  • Modulos de control de perifericos 
  • Generadores de pulsos de reloj para la sincronizacion del sistema.


Las ventajas de usar los microcontroladores son muchas, como por ejemplo el aumento de control sobre los elementos que lo utilizan, la mayor flexibilidad con sus modulos de memoria reprogramable, mayor eficiencia al tener un solo dispositivo para diversos trabajos y requerimento de menos ajustes al ser un simple circuito integrado, ademas que por el simple hecho de ser tan reducido se puede adherir al elemento que debe gobernar, al hacer eso recibe el nombre de controlador embebido.

Porque es diferente un microprocesador y un microcontrolador?.

El microprocesador es un circuito integrado que contiene una unidad central de procesamiento que intepreta las instrucciones en conjunto del camino de datos. Cada una de las patitas del microprocesador sacan lineas de buses de direcciones,datos y control para poder conectarle memoria, y los demas modulos de entrada y salida, para de estar forma poder configurar una computadora con el conjunto de varios circuitos integrados. Un microprocesador puede variar deacuerdo con los modulos que se le conecten.


El microcontrolador es un sistema invariable, ya que contiene sus modulos de memoria y E/S en su interior y solo sobresalen sus lineas de gobernacion ( de control ).



Arquitectura basica de un microcontrolador

La mayor parte de los microcontroladores estan basados en la arquitectura Harvard, dicha arquitectura dispone de dos memorias independientes, yna que contiene solo instrucciones y otra solo datos. Estas dos memorias disponen de sus respectivos sistemas de buses de acceso y es posible realizar operaciones de acceso simultaneamente en ambas memorias. Los microcontroladores PIC llevan una arquitectura Hardvard.

La unidad central de procesamiento de un microcontrolador

Es la encargada de direccionar la memoria de instrucciones, recibir el codigo de la instruccion, decodificarla y ejecutar la operacion, asi como el almacenamiento del resultado. Existen tres orientaciones en cuanto a la arquitectura de los microcontroladores.

- CISC ( Computadores de juego de Instrucciones Complejo ) Disponen de instrucciones maquina en su repertorio, son mucho muy potentes y requieren de muchos ciclos para su ejecuccion. Su ventaja es que ofrecen instrucciones coplejas que actuan como macros.
- RISC ( Computadores de juego de Instrucciones Reducido ) El repertorio de instrucciones maquina es muy reducido y las instrucciones son simples y, generalmente, se ejecutan en un ciclo. La sencillez permite optimizar el hardware y el software de dicho procesador.
SISC ( Computadores de juego de Instrucciones Especifico ) Estan hechos para aplicaciones especificas como su nombre lo dice y el sistema de instrucciones se adapta a la aplicacion prevista a crear.

Memoria de un microcontrolador

Como se menciono arriba, en los microcontroladores la memoria de instrucciones y la de datos estan integradas en el chip. Una parte de esta memoria es no volatil del tipo Read Only Memory y esta destinada a contener las instrucciones que goriernan la aplicacion, es decir el programa que le hemos desarrollado para su control. Cabe destacar que los microcontroladores no tienen sistemas de almacenamiento masico como discos duros, ya que para su ejecuccion solo necesita un unico programa. Por ultimo para la ROM normalmente se le dan de 512 bytes hasta 8 kb.
Otra parte es Random Access Memory y se utiliza para guardar datos durante la ejecuccion de las instucciones. Dicha memoria es reducida ya que solo necesita contener unas cuantas variables y cambios de informacion durante la ejecuccion del programa. A esta memoria se le otorgan alrededor de 512 bytes.

Los microcontroladores actuales solo pueden tener uno de cinco de los tipos de memoria no volatil, como son:

-ROM: una memoria no volatil que puede procesar cantidades de varios miles de unidades.
-OTP: una memoria no volatil que solo puee ser programada una sola vez por el usuario.
-EPROM: su nombre indica su funcion (Erasable programmable read only memory) solo cuenta con una particularidad ya que debe exponerse a rayos ultravioleta durante varios minutos para poder borrarle el contenido.
-EEPROM: es la version mejorada de la EPROM ya que este tipo de memorias se pueden borrar con electricidad, no son necesarios los rayos UV. Pero se deben usar con cuidado ya que su reprogramacion cumple un ciclo finito de veces, no son eternos.
-FLASH: cumple la funcion de una ROM y una RAM, porque se puede leer y escribir informacion en dicha memoria, haciendola una memoria mas veloz que la EEPROM pero cambiando el coste de tolerancia para los ciclos de escritura y borrado.

EPROM

Modulos de control y generador de pulsos 

Los microcontroladores estan diseñados para soportar lineas de E/S para comunicar el computador interno con los perifericos exteriores y asi proporcionar soporte a las señales de entrada, salida y control. Cada microcontrolador dispone de un circuito oscilador que genera un onda cuadrada de alta frecuencia ( es decir, una onda que envia valores entre dos rangos fijos ) que configura los pulsos de reloj usados en la sincronización de todas las operaciones del sistema.
Para estabilizar la frecuencia de trabajo suele usarse un cristal de cuarzo junto con otros elementos pasivos, en su defecto un resonador ceramico, o una red RC.
Aumentar la frequencia de reloj hace una ejecuccion de instrucciones mucho mas rapida, pero aumenta considerablemente el consumo de energía.


Referencia
website Dr. villafaña

Ever Medina. Con la tecnología de Blogger.