Autor Tema: Complicando para simplificar  (Leído 16349 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 18286
    • MicroPIC
Complicando para simplificar
« en: 13 de Septiembre de 2007, 06:03:08 »
Este hilo también podía haberse llamado "Añadiendo código para optimizar".

Lo que pretendo compartir con vosotros es algo que he observado en mis programas en C, e imagino que muchos de vosotros también lo ha visto.

He adquirido la costumbre de revisar el código ASM que generan mis programas una vez compilados y cuando veo algo que me sorprende por su tamaño, intento mejorarlo.

Así, en ocasiones he observado como a veces un código más largo o complejo en C, genera paradójicamente un código más compacto, corto y rápido en ASM.

Os dejo por aquí un ejemplo, y me comprometo a ir posteando los que me vaya encontrando a lo largo del camino por si sirve de ilustración.

Observad este trocito de código, que compara una Variable de 16 bits con una constante:
if (Variable>0x0A00)
      Variable=0;


Pues bien, al compilarlo genera un ASM de 12 CICLOS:
Código: ASM
  1. ....................    if (Variable>0x0A00)
  2. 0047:  BCF    03.5
  3. 0048:  MOVF   22,W
  4. 0049:  SUBLW  09
  5. 004A:  BTFSC  03.0
  6. 004B:  GOTO   055
  7. 004C:  XORLW  FF
  8. 004D:  BTFSS  03.2
  9. 004E:  GOTO   053
  10. 004F:  MOVF   21,W
  11. 0050:  SUBLW  00
  12. 0051:  BTFSC  03.0
  13. 0052:  GOTO   055

Puestos a probar otras alternativas, lo modifiqué así:
if ((Variable>>8)>0x0A)
      Variable=0;


Y el código generado se redujo en dos ciclos:
Código: ASM
  1. ....................    if ((Variable>>8)>0x0A)
  2. 005B:  MOVF   22,W
  3. 005C:  MOVWF  23
  4. 005D:  CLRF   24
  5. 005E:  MOVF   24,F
  6. 005F:  BTFSS  03.2
  7. 0060:  GOTO   065
  8. 0061:  MOVF   23,W
  9. 0062:  SUBLW  0A
  10. 0063:  BTFSC  03.0
  11. 0064:  GOTO   067

Mi grata sorpresa vino cuando compilé esta tercera versión del código:
if (make8(Variable,1)>0x0A)
      Variable=0;


Con esta última version, obviamente más larga y compleja que la primera, el código ASM se quedó en 4 CICLOS:
Código: ASM
  1. ....................    if (make8(Variable,1)>0x0A)
  2. 0055:  MOVF   22,W
  3. 0056:  SUBLW  0A
  4. 0057:  BTFSC  03.0
  5. 0058:  GOTO   05B

Os recomiendo reviséis el ASM porque, sobre todo en micros pequeñitos, podemos ganar bastante haciendo ligeros cambios en nuestros programas.

Desconectado elmasvital

  • Administrador
  • PIC24H
  • *******
  • Mensajes: 1713
Re: Complicando para simplificar
« Respuesta #1 en: 13 de Septiembre de 2007, 11:50:26 »
A ver comentemoslo de forma amistosa...

en el primer compilado de 12 ciclos en ASM estamos haciendo que el micro compare 2 números de 16 bits.

en el segundo compilado de 10 ciclos en ASM estamos haciendo que el micro convierta una variabe de 16 a 8 bits y lo compare con uno de 8 bits

y en el tercer caso hay algo que no me cuadra muy bien, pq hace tiempo que no toco ccs... Make8 es una instrucción del precompilador? Es una rutina?... No me cuadra en ningun caso pq si fuera algo del precompilador no podrias hacerlo en medio del programa y si fuera una rutina deberia plasmarse tal cosa en ASM y claramente ese compilado muestra unicamente una comparacion de dos numeros de 8 bits.

Tambien puede ocurrir algo y es que en las rutinas generales que mete ccs en el compilado asm esté la de make8... entonces si veriamos ahorro de codigo pero deberia reflejarse en un desplazamiento de la variable a algun registro y el salto a esa rutina en el asm cosa que no se ve en el asm del 3er caso.

Comprueba el hex resultante manolo en ambos casos a ver si cambia de tamaño.

1 saludo.

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 18286
    • MicroPIC
Re: Complicando para simplificar
« Respuesta #2 en: 13 de Septiembre de 2007, 12:28:55 »
Es muy simple, José Antonio.

make8 es una función del compilador, que extrae un byte de un word (o incluso de un long word).

Como el compilador sabe cuál es el byte que voy a extraer porque se lo estoy indicando con una constante, genera el código asm que apunta directamente a ese byte en la memoria (MOVF   22,W) y se ahorra el resto de operaciones.

Este CCS, cuando no tiene bugs, está muy bien hecho.

Desconectado sander

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 624
Re: Complicando para simplificar
« Respuesta #3 en: 13 de Septiembre de 2007, 12:50:13 »
Aqui hay algo que no me cuadra, la primera instruccion  que pones es variable > 0x0A00 , si variable es igual a 0X0A01 se cumplira la condicion, en tu ultima "optimizacion"  comparas la parte alta de variable con 0x0A y si variable vale  0x0A01 no se no entra el if , entonces lo primero y lo ultimo no es lo mismo.
La electrónica es el arte de manipular señales eléctricas que transportan información
Jan Davidse

Visita mi blog
Visita mi canal de youtube

Desconectado micro_cadaver

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 2102
    • blog microembebidos
Re: Complicando para simplificar
« Respuesta #4 en: 13 de Septiembre de 2007, 12:54:18 »
es la optimizacion del C mediante el propio programador. aunque en el caso de sander habria que probar otro metodo.
a cosechar!!!... :P
pic32... ahi voy....
aguante el micro 16f84  !!!!

visita mi pagina: http://www.microembebidos.wordpress.com

Desconectado PalitroqueZ

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5474
    • Electrónica Didacta
Re: Complicando para simplificar
« Respuesta #5 en: 13 de Septiembre de 2007, 13:52:47 »
Normalmente cuando veo en mis programas que no hay espacio u otra anormalidad, procuro llevar ciertas funciones al asm
de todas formas es una buena costumbre, así se conoce como trabaja el compilador, aprovechando este hilo, recuerdo haber leido en uno de tus post manolo, algo relacionado a usar los if en vez de los case para simplificar el código generado, no recuerdo donde está el post.
La propiedad privada es la mayor garantía de libertad.
Friedrich August von Hayek

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 18286
    • MicroPIC
Re: Complicando para simplificar
« Respuesta #6 en: 13 de Septiembre de 2007, 14:56:11 »
Sander, tienes razón. Es muy buena la observación, aunque para el caso que lo necesito no me afecta en absoluto.

Desconectado PalitroqueZ

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5474
    • Electrónica Didacta
Re: Complicando para simplificar
« Respuesta #7 en: 17 de Marzo de 2008, 18:32:45 »
Acerca de las directivas #inline y #separate

en la ayuda dice:

#inline:
"Tells the compiler that the function immediately following the directive is to be implemented INLINE.   This will cause a duplicate copy of the code to be placed everywhere the function is called.  This is useful to save stack space and to increase speed. Without this directive the compiler will decide when it is best to make procedures INLINE."


#separate:
"Tells the compiler that the procedure IMMEDIATELY following the directive is to be implemented SEPARATELY.  This is useful to prevent the compiler from automatically making a procedure INLINE. This will save ROM space but it does use more stack space. The compiler will make all procedures marked SEPARATE, separate, as requested, even if there is not enough stack space to execute"

probando con unas funciones, antes y después, cambiando las directivas, tengo las siguientes estadisticas:







debido a limitaciones no he comprobado fisicamente si aumenta la velocidad de ejecución del código, pero si esto es cierto, para aquellos que necesiten velocidad, les caerá bien, (y en aquellos pic que sean generosos en memoria de programa)

« Última modificación: 17 de Marzo de 2008, 18:34:57 por PalitroqueZ »
La propiedad privada es la mayor garantía de libertad.
Friedrich August von Hayek

Desconectado sander

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 624
Re: Complicando para simplificar
« Respuesta #8 en: 17 de Marzo de 2008, 19:57:39 »
Alguna vez use el separate porque el codigo resultaba muy grande, en esa ocacion analice un poco el codigo en ensamblador que genero el compilador y lo que hacia era sustituir el codigo por un call o un goto hacia la subrutina, por lo que me parece que la velocidad de ejecucion no mejora mucho que digamos 1 call + 1 return 4 ciclos de reloj, claro que segun la aplicacion esto puede ser importante.

Saludos
La electrónica es el arte de manipular señales eléctricas que transportan información
Jan Davidse

Visita mi blog
Visita mi canal de youtube

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 18286
    • MicroPIC
Re: Complicando para simplificar
« Respuesta #9 en: 18 de Marzo de 2008, 04:00:55 »
Pero no es solamente el goto o el call; también te evitas que guarde contexto en el stack.

Desconectado stk500

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 4919
Re: Complicando para simplificar
« Respuesta #10 en: 18 de Marzo de 2008, 04:27:15 »
Tranquilo en mi PC leyendos las compliaciones de Manolo,  :D :D :D :D y lo que hace el Ron,  :D :D :D siga Maestros  :lol: :lol: :lol:
porque hare despues mis preguntas,  :D :D :D

Desconectado RICHI777

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1498
Re: Complicando para simplificar
« Respuesta #11 en: 18 de Marzo de 2008, 12:08:58 »
Hola, en si la funcion make8 se puede implementar como macro, son casi standar de factos las implementaciones de
  • HI_NIBBLE y LO_NIBBLE ( Extren el nibble mas alto y el nibble mas bajo respectivamente de un byte )
  • HI y LO ( Extren el byte mas alto y el byte mas bajo respectivamente de un word )
  • HIWORD y LOWORD ( Extren el word mas alto y el word mas bajo respectivamente de un dword )
Les dejo la implementacion de HI y LO
Código: [Seleccionar]
/* Get High byte of the an word */
#define HI( Data )                                                \
           (( byte ) (((( word ) Data ) >> 8 ) & 0xFF ))          \

/* Get Low byte of an word */
#define LO( Data )                                                \
           (( byte ) ((( word )( Data )) & 0xFF ))                \
En mi caso estas macros las tengo implementadas en un modulo que exporto de proyecto en proyecto y asi no dependo tanto de las funciones que me brinde el compilador.

En el caso de las optimizaciones es muy buena la observacion de sander, el tema seria lo mismo si la Variable que en ejemplo 1 es un word pase a ser un byte, al compilador le resulta menos esfuerzo lidiar con bytes que con words, de ahi la optimización.

Saludos !




Desconectado sander

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 624
Re: Complicando para simplificar
« Respuesta #12 en: 18 de Marzo de 2008, 13:34:17 »
Pero no es solamente el goto o el call; también te evitas que guarde contexto en el stack.

mmm guarda el contexto en el stack cuando salta a una interrupcion, pero para una subrutina lo principal seria la inicializacion de las variables locales que usa la subrutina, pero esto lo hace con el #inline o el #separate

Saludos
La electrónica es el arte de manipular señales eléctricas que transportan información
Jan Davidse

Visita mi blog
Visita mi canal de youtube

Desconectado RICHI777

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1498
Re: Complicando para simplificar
« Respuesta #13 en: 18 de Marzo de 2008, 13:37:21 »
Me parece que mas que el contexto de stack es el "Stack frame" ....

Desconectado Sispic

  • Moderadores
  • PIC24H
  • *****
  • Mensajes: 1685
    • winpic800
Re: Complicando para simplificar
« Respuesta #14 en: 18 de Marzo de 2008, 14:42:50 »

Os recomiendo reviséis el ASM porque, sobre todo en micros pequeñitos, podemos ganar bastante haciendo ligeros cambios en nuestros programas.


No te conozco Manolo ... asi que ahorrando ciclines .
Se supone que "Variable" es de 16 bits

if (make8(Variable,1)>0x0A)
Si el byte menos significativo no lo verifica  no se cumple "if (Variable>0x0A00)" si por ejemplo "Variable" vale 0x0A01
Aunque quizas ya te valia asi .





 

anything