domingo, 25 de noviembre de 2012

Tutorial de ensamblador x86. Capítulo 3. Primeras optimizaciones



Hola a todos,

Si habéis ido siguiendo el curso, y habéis mirado los ejemplos, lo más normal es que hayáis intentado programar alguna cosilla en asm. Y también lo más normal es que toda vuestra ilusión se haya ido al garete al ver que el rendimiento de vuestra aplicación más que mejorar , empeora.

Si vuestra aplicación pierde rendimiento al aplicarle ensamblador es por el sencillo motivo que el compilador sabe "compilar" un poco mejor que vosotros :D y tiene muy claras las normas de lo que se puede hacer y lo que no se puede hacer.

Os presento ahora la lista con las cosas más típicas que se pueden mejorar en vuestra aplicación y ya veréis como poco a poco el rendimiento os irá mejorando.

1. Dependencias de datos: Esta es la más típica y normalmente la que menos se puede solucionar. Cuando nosotros ejecutamos una instrucción en ensamblador el procesador realmente lo que hace es intentar adelantarse a los acontecimientos e ir ejecutando la parte que pueda de la siguiente instrucción (si queréis saber más tendréis que googlear un poco sobre segmentación de CPU y pipeline, pero no es fácil de entender de buenas a primeras). Si nosotros encadenamos dos funciones seguidas en que el resultado de la primera forma parte de los operandos de la segunda ya no podemos ir adelantando trabajo, haciendo que el rendimiento del procesador  disminuya drásticamente. La solución se basa en intercalar otras operaciones con otros operandos en medio de las zonas conflictivas a fin de que el procesador pueda ir adelantando trabajo de otras operaciones. El problema de hacer esto es que el código queda desordenado y es de difícil comprensión.

2. Saltos condicionales: Cada vez que vamos ha hacer un salto de código (jmp, je, jg , jl) el procesador intenta adivinar que será lo más probable y ya lo empieza a precalcular. Esto significa que hay un cierto número  de veces que el procesador hará trabajo por que si, ya que la comparación no será como el se esperaba. Hay casos en que el circuito que se encarga de preveer por donde irá nuestro código falla bastante y es extremadamente complejo de predecir, así que el único consejo que os puedo dar es que minimicéis el número de saltos en la medida de lo posible.

3. Acceso a memoria: Da igual que memoria tengáis o cuan cara y rápida sea, minimizad los accesos a memoria. Acceder a un registro cuesta 1 o 2 ciclos de reloj. Acceder a memoria pueden llegar a ser cientos de ciclos. Así pues, es sencillo. Aprovechad los registros, y haced un poco de trileros con los registros para que los valores que hayamos leído una vez no los tengamos que leer otra vez.  Solo con esta optimización podéis llegar a multiplicar x10 o x20 el rendimiento de vuestra aplicación.

4. Usad trucos de asm: El lenguaje ensamblador lleva décadas usándose normalmente en plataformas muy justas de recursos. Esto ha llegado a desarrollar unos trucos que nos permitirán arañar ciclos de reloj cuando pensemos que ya no podemos hacer nada más.
 - Usad xor eax,eax  en vez de mov eax,0. Hace lo mismo y es más rápido. La operación xor de una variable con ella misma siempre es 0.
- Usad desplazamientos de bits en vez de multiplicaciones o divisiones con múltiplos de dos:
   shr ecx, 1   es lo mismo que ecx /= 2 pero muchísimo más rápido
   shl eax,2 es lo mismo que eax *= 4 pero muchisimo más rápido.

5. Usad instrucciones especificas para problemas específicos: Los compiladores de C ,normalmente, usan solamente unas 20 instrucciones de ensamblador para hacerlo todo. Esto es debido a la gran complejidad del proceso de compilación, pero realmente los procesadores poseen centenares de instrucciones. Ejemplos lo tenéis a cientos, una instrucción como bswap te permite hacer en un solo ciclo el trabajo que se podría hacer en decenas de ciclos. y las instrucciones de SSE te permiten trabajar con 4 ints a la vez aplicando funcionalidades que tal vez no habías ni imaginado. Tendréis que investigar pero ya veréis que con el suficiente tiempo dedicado podréis encontrar alguna instrucción que os resulte extremadamente útil en vuestra aplicación.

Y con esto acaban los consejos básicos para optimizar vuestro código ensamblador.

Espero que os haya gustado,

Nos vemos

LordPakusBlog

0 comentarios :

Publicar un comentario

Entradas populares