miércoles, 20 de noviembre de 2019

UNIDAD 3 - OPTIMIZACIÓN.

OPTIMIZACION.

La optimización busca mejorar la forma en que un programa utiliza los recursos. Las optimizaciones se realizan en base al alcance ofrecido por el compilador. La optimización va a depender del lenguaje de programación y es directamente proporcional al tiempo de compilación; es decir, entre más optimización mayor tiempo de compilación.
Existen diversas técnicas de optimización se pueden clasificar o dividir de diversas formas:
          1. Dependientes de la maquina: técnicas que solo se pueden aplicar a una determinada maquina objeto.
                2. Independientes de la maquina: técnicas que son aplicables a cualquier maquina objeto.
                3. Locales: analizaran solo pequeñas porciones de código y en ellas realizaran mejoras.
                 4. Globales: será necesario el análisis de todo el código.

3.1  TIPOS DE OPTIMIZACION:

Técnicas de optimización que se aplican al código generado para un programa sencillo (aquel que se reduce a un solo procedimiento o subrutina).


3. 1.1 LOCALES
La optimización local se realiza sobre módulos del programa. En la mayoría de las ocasiones a través de funciones, métodos, procedimientos, clases, etc.
Las características de las optimizaciones locales es que solo se ven reflejados en dichas secciones. La optimización local sirve cuando un bloque de programa o sección es crítico por ejemplo: la E/S, la concurrencia, la rapidez y confiabilidad de un conjunto de instrucciones.

EJEMPLOS:

1-      Ejecución en tiempo de compilación
Precalcular  expresiones constantes (con constantes o variables cuyo valor no cambia).
i = 5
j = 4
f = j + 2.5
!
j = 4
f = 6.5

2-     Reutilización de expresiones comunes
a = b + c
d = a - d
e = b + c
f = a - d
!
a = b + c
d = a - d
e = a
f = a – d

3-     Propagación de copias
Ante instrucciones f=a, sustituir todos los usos de f por a.
a = 3 + i
f = a
b = f + c
d = a + m
m = f + d
!
a = 3 + i
b = a + c
d = a + m
m = a + d

4-     Eliminación redundancias en acceso matrices
Localizar expresiones comunes en cálculo direcciones de matrices.

5-     Transformaciones algebraicas:
Aplicar propiedades matemáticas para simplificar expresiones

o   Eliminación secuencias nulas
o   Reducción de potencia
o   Reacondicionamiento de operandos

      3.1.2  CICLOS

Los ciclos son una de las partes más esenciales en el rendimiento de un programa dado que realizan acciones repetitivas, y si dichas acciones están mal realizadas, el problema se hace N veces más grandes. La mayoría de las optimizaciones sobre ciclos tratan de encontrar elementos que no deben repetirse en un ciclo.
El problema de la optimización en ciclos y en general radica en que es muy difícil saber el uso exacto de algunas instrucciones. Así que no todo código de proceso puede ser optimizado. Otro uso de la optimización puede ser el mejoramiento de consultas en SQL o en aplicaciones remotas (sockets, E/S, etc.).


3.1.3 Globales 

La optimización global se da con respecto a todo el código. Este tipo de optimización es más lenta pero mejora el desempeño general de todo programa. Las optimizaciones globales pueden depender de la arquitectura de la máquina. En algunos casos es mejor mantener variables globales para agilizar los procesos (el proceso de declarar variables y eliminarlas toma su tiempo) pero consume más memoria. Algunas optimizaciones incluyen utilizar como variables registros del CPU, utilizar instrucciones en ensamblador. 

3.1.4 DE MIRILLA

La optimización de mirilla trata de estructurar de manera eficiente el flujo del programa, sobre todo en instrucciones de bifurcación como son las decisiones, ciclos y saltos de rutinas. La idea es tener los saltos lo más cerca de las llamadas, siendo el salto lo más pequeño posible.
Ideas básicas:

  • Se recorre el código buscando combinaciones de instrucciones que pueden ser reemplazadas por otras equivalentes más eficientes.
  • Se utiliza una ventana de n instrucciones y un conjunto de patrones de transformación (patrón, secuencias, remplazan).
  • Las nuevas instrucciones son reconsideradas para las futuras optimizaciones.
Ejemplos:

  • Eliminación de cargas innecesarias
  • Reducción de potencia
  • Eliminación de cadenas de saltos

3.2 COSTOS.

3.2.1   costos de ejecución.(memoria, registros,pilas).

Los costos de ejecución son aquellos que vienen implícitos al ejecutar el programa.
• En algunos programas se tiene un mínimo para ejecutar el programa, por lo que el espacio y la velocidad del microprocesador son elementos que se deben optimizar para tener un mercado potencial más amplio.

Memoria

Servicios genéricos de memoria

Los registros del procesador se emplean para controlar instrucciones en ejecución, manejar direccionamiento de memoria y proporcionar capacidad aritmética. Los registros son espacios físicos dentro del microprocesador con capacidad de 4 bits hasta 64 bits dependiendo del microprocesador que se emplee. Los registros son direccionables por medio de una viñeta, que es una dirección de memoria. Los bits, por conveniencia, se numeran de derecha a izquierda (15,14,13…. 3,2,1,0), los registros están divididos en seis grupos los cuales tienen un fin especifico.

La pila

La aparición de lenguajes con estructura de bloque trajo consigo la necesidad de técnicas de alojamiento en memoria más flexibles, que pudieran adaptarse a las demandas de memoria durante la ejecución del programa.
En, en general los compiladores, la asignación de memoria de variables locales se hace de una forma flexible, atendiendo al hecho de que solamente necesitan memoria asignada desde el momento que comienza la ejecución de la función hasta el momento en que ésta finaliza.
La memoria es uno de los recursos más importantes de la computadora y, en consecuencia, la parte del sistema operativo responsable de tratar con este recurso, el gestor de memoria, es un componente básico. Los costos de ejecución son aquellos que vienen implícitos al ejecutar el programa.
En algunos programas se tiene un mínimo para ejecutar el programa, por lo que el espacio y la velocidad del microprocesador son elementos que se deben optimizar para tener un mercado potencial más amplio.
Algunos lenguajes de programación utilizar la pila para almacenar datos que son locales a espacio para los datos locales se asigna a los temas de la pila cuando el procedimiento se introduce, y son borradas cuando el procedimiento termina.
Organización de la memoria en tiempo de ejecución
Las técnicas de gestión de la memoria durante la ejecución del programa difieren de unos lenguajes de programación a otros, e incluso de unos compiladores a otros.
Para datos, básicamente la memoria se divide en:
- Memoria Estática.
- La Pila.
- (Heap El Monton).


3.2.2 - Criterios para mejorar el código.
La mejor manera de optimizar el código es hacer ver a los programadores que optimicen su código desde el inicio, el problema radica en que el costo podría ser muy grande ya que tendría que codificar más y/o hacer su código mas legible.

 Los criterios de optimización siempre están definidos por el compilador.

Criterios de optimización 
• Muchos de estos criterios pueden modificarse con directivas del compilador desde el código o de manera externa. 
• Este proceso lo realizan algunas herramientas del sistema como los ofuscadores para código móvil y código para dispositivos móviles.


3.2.3 Herramientas para el análisis del flujo de datos


Existen algunas herramientas que permiten el análisis de los flujos de datos, entre ellas tenemos los depuradores y desambladores.

 La optimización al igual que la programación es un arte y no se ha podido sistematizar del todo.










Unidad 4 - GENERACIÓN DE CÓDIGO OBJETO

4.1 - REGISTRO.

¿Qué son?

Los registros son la memoria principal de la computadora. Existen diversos registros de propósito general y otros de uso exclusivo. Algunos registros de propósito general son utilizados para cierto tipo de funciones. Existen registros acumuladores, puntero de instrucción, de pila, etc.

Los registros son espacios físicos dentro del microprocesador con capacidad de 4 bits hasta 64 bits dependiendo del microprocesador que se emplee.

¿Quiénes lo utilizan?


Antes de nada, para el desarrollo de esta parte hablaremos indistintamente de registros de activación o de marcos de pila. Esto se debe a que en la documentación encontrada sobre el manejo de los registros ebp y esp se hace mención a dicho concepto de marco de   pila.   Puesto   que   el   lenguaje   permite   recursividad,   los   registros   de   activación   se asignan dinámica mente. 


Distribución

La UCP o CPU tiene 14 registros internos, cada uno de ellos de 16 bits (una palabra). Los bits están enumerados de derecha a izquierda, de tal modo que el bit menos significativo es el bit 0.
Los registros se pueden clasificar de la siguiente forma: 

Registros de datos:

AX: Registro acumulador. Es el principal empleado en las operaciones aritméticas.
BX: Registro base. Se usa para indicar un desplazamiento.
CX: Registro contador. Se usa como contador en los bucles.
DX: Registro de datos.

Estos registros son de uso general y también pueden ser utilizados como registros de 8 bits, para utilizarlos como tales es necesario referirse a ellos como por ejemplo: AH y AL, que son los bytes alto (high) y bajo (low) del registro AX. Esta nomenclatura es aplicable también a los registros BX, CX y DX. 

Registros de segmentos: 

CS: Registro de segmento de código. Contiene la dirección de las instrucciones del programa. 
DS: Registro segmento de datos. Contiene la dirección del área de memoria donde se encuentran los datos del programa.
SS: Registro segmento de pila. Contiene la dirección del segmento de pila. La pila es un espacio de memoria temporal que se usa para almacenar valores de 16 bits (palabras).
ES: Registro segmento extra. Contiene la dirección del segmento extra. Se trata de un segmento de datos adicional que se utiliza para superar la limitación de los 64Kb del segmento de datos y para hacer transferencias de datos entre segmentos.

Registros punteros de pila:

SP: Puntero de la pila. Contiene la dirección relativa al segmento de la pila.
BP: Puntero base. Se utiliza para fijar el puntero de pila y así poder acceder a los elementos de la pila.

Registros índices:

 SI: Índice fuente.
 DI: Índice destino.


¿Cuales su aplicación en la generación de códigos?

1. usar el registro de y si está en un registro que no tiene otra variable, y además y no
está viva ni tiene uso posterior. Si no:
2. usar un registro vacío si hay. Si no:
3. usar un registro ocupado si op requiere que x esté en un registro o si x tiene uso
Posterior. Actualizar el descriptor de registro. Si no:
4. usar la posición de memoria de x


VIDEO DE LOS REGISTROS DEL PROCESADOR:



4.2 Lenguaje ensamblador

¿Qué es?

El   lenguaje   Assembly  (Urbina,   2011)  (a   veces   mal   llamado   "Ensamblador"   por  su traducción literal al español) es un tipo de lenguaje de bajo nivel utilizado para escribir programas informáticos, y constituye la representación más directa del código máquina específico para cada arquitectura de computadora.




 Segunda generación de lenguajes

Versión simbólica de los lenguajes máquina (Urbina, 2011) (MOV, ADD).La comunicación en lenguaje de máquina es particular de cada procesador que se usa, y programar en este lenguaje es muy difícil y tedioso, por lo que se empezó a buscar mejores medios de comunicación con ésta. Los lenguajes ensambladores tienen ventajas sobre los lenguajes de máquina.

Este lenguaje  fue  usado  ampliamente  en el  pasado para  el  desarrollo de software, pero actualmente sólo se utiliza encontradas   ocasiones,   especialmente   cuando   se requiere   la manipulación directa del hardware o se pretenden rendimientos inusuales de los equipos


VIDEO DE INTRODUCCION AL LENGUAJE ENSAMBLADOR.


Características:

El programa lee un archivo escrito en lenguaje ensamblador y sustituye cada uno de los códigos mnemotécnicos por su equivalente código máquina. Los programas se hacen fácilmente portables de máquina a máquina y el cálculo de bifurcaciones se hace de manera fácil.

Clasificación:
  • Ensambladores básicos: Son de muy bajo nivel, y su tarea consiste básicamente, en ofrecer nombres simbólicos a las distintas instrucciones, parámetros y cosas tales como los modos de direccionamiento
  • Ensambladores modulares, o macro ensambladores: Descendientes de los ensambladores básicos, fueron muy populares en las décadas de los 50 y los 60, fueron antes de la generalización de los lenguajes de alto nivel. Un macroinstrucción es el equivalente a una función en un lenguaje de alto nivel.


Operaciones básicas

(Urbina, 2011) Las operaciones básicas en un lenguaje ensamblador son la suma la resta la multiplicación y la división y Necesitara un poco más de información sobre la  arquitectura y SO para el cual programas.
Pero la idea básica es:

--definir que parámetros tendrá la función.
--hacer el programa, propiamente dicho, en assembler.

Siguiendo la convención de pasaje de parámetros, manejará registros y posiciones de  memoria, devolviendo los resultados en donde deba (una posición de memoria, el registro eax, etc.).


4.3 Lenguaje Máquina

 Es el que proporciona poca o ninguna abstracción del microprocesador de un ordenador. El lenguaje máquina solo es entendible por las computadoras. Se basa en una lógica binaria de 0 y 1, generalmente implementada por mecanismos eléctricos. En general el lenguaje maquina es difícil de entender para los humanos por este motivo hacemos uso de lenguajes más parecidos a los lenguajes naturales.




Se denomina lenguaje máquina a la serie de datos que la parte física de la computadora o hardware, es capaz de interpretar. El lenguaje máquina fue el primero que empleo el hombre para la programación de las primeras computadoras. Una instrucción en lenguaje máquina puede representarse   de   la   siguiente   forma:  011011001010010011110110.   Esta   secuencia   es fácilmente ejecutada por la computadora, pero es de difícil interpretación, siendo aún más difícil la interpretación de un programa (conjunto de instrucciones) escrito de esta forma.
Esta   dificultad   hace   que   los   errores   sean   frecuentes   y   la   corrección   de   los   mismos costosa, cuando no imposible, al igual que la verificación y modificación de los programas.

Características:

El lenguaje máquina realiza un conjunto de operaciones predeterminadas llamadas micro operaciones. Las micro operaciones sólo realizan operaciones del tipo aritmética (+,- ,*,/), lógicas (AND, OR, NOT) y de control (secuencial, de control y repetitiva). El lenguaje maquina es dependiente del tipo de arquitectura. Así un programa máquina para una arquitectura Intel x86 no sé ejecutara en una arquitectura Power PC de IBM (al menos de manera nativa).

Algunos microprocesadores implementan mas funcionalidades llamado CISC, pero son más lentos que los RISC ya que estos tienen registros más grandes.

Ventajas

  • Mayor adaptación al equipo.
  • Máxima velocidad con mínimo uso de memoria.


Desventajas

  • Imposibilidad de escribir código independiente de la máquina.
  • Mayor dificultad en la programación y en la comprensión de los programas.
  • El programador debe conocer más de un centenar de instrucciones.
  • Es necesario conocer en detalle la arquitectura de la máquina.

VIDEO INTRODUCTORIO DE LENGUAJE MAQUINA.



4.4 Administrador de memoria


La administración de la memoria es un proceso hoy en día muy importante, de tal modo que su mal o buen uso tiene una acción directa sobre el desempeño de memoria. En general un ensamblador tiene un administrador de memoria más limitado que un compilador; en la mayoría de los lenguajes de programación el uso de punteros no estaba vigilado por lo que se tienen muchos problemas con el uso de memoria. Los lenguajes más recientes controlan el uso de punteros y tienen un programa denominado recolector de basura que se encarga de limpiar la memoria no utilizada mejorando el desempeño.

La   memoria   principal   puede   ser   considerada   como   un arreglo lineal de localidades de almacenamiento de un byte de tamaño. Cada localidad de almacenamiento tiene asignada una dirección que la identifica

 Se distinguen los siguientes propósitos del sistema de administración de memoria:
Protección.
Si   varios   programas   comparten   la   memoria   principal,   se   debería   asegurar   que   el programa no sea capaz de cambiar las ubicaciones no pertenecientica él. Aunque una acción  de  escritura  puede  tener efectos  más graves que una  de  lectura,  esta última tampoco debería estar permitida, para proporcionar algo de privacidad al programa.



Compartimiento.
Este objetivo parece contradecir al anterior, sin embargo a veces es necesario para los usuarios poder compartir y actualizar información (por ejemplo, en una base de datos) y, si se organiza la tarea de entrada a la misma, se puede evitar el tener varias copias de la rutina.

Reubicación.
La técnica de multiprogramación requiere que varios programas ocupen la memoria al mismo  tiempo.   Sin   embargo   no   se   sabe   con   anticipación   donde   será   cargado   cada programa por lo que no es práctico usar direccionamiento absoluto de memoria.

Organización física.
Debido al  costo  de una  memoria  principal  rápida, éste se   usa   en   conjunto  con una memoria secundaria mucho más lenta (y por consiguiente, barata) a fines de extender su capacidad.

Organización lógica.
 Aunque   la   mayor   parte   de   las   memorias   son   organizadas   linealmente   con   un direccionamiento secuencial, esto difícilmente concuerde con el camino seguido por el programa, debido al uso de procedimientos, funciones, subrutinas, arreglos, etc.






martes, 22 de octubre de 2019

Lenguaje Ensamblador (NASM)


¿Que son los registros?

Los registros de datos, como su nombre indica, contienen generalmente datos. Los registros del procesador son una porción de memoria ultrarrápida, se emplean para:
• Controlar instrucciones en ejecución. 
• Manejar direccionamiento de memoria. 
• Proporcionar capacidad aritmética.

Los registros son espacios físicos dentro del microprocesador con capacidad de 4 bits hasta 64 bits dependiendo del microprocesador que se emplee.


Tipos de registros:

Uno puede mover los datos de unos registros a otros con prácticamente total libertad. También podremos realizar operaciones sobre ellos, como sumar el contenido de BX y DX para guardar el resultado en DX, y cosas así. La primera restricción al respecto (y bastante razonable) es que los operandos tendrán que ser del mismo tamaño (no podremos sumar BX con DH, por ejemplo).


Registros de uso general:
  • AX: Acumulador (AL:AH)
  • BX: Registro base (BL:BH)
  • CX: Registro contador (CL:CH)
  • DX: Registro de datos (DL:DH)


Cada registro de estos está dividido a su vez en dos registros de 8 bits, que pueden ser leídos o escrito de manera independiente:
    AX = AH | AL          BX = BH | BL
    CX = CH | CL          DX = DH | DL




Registros de segmento (Solo se pueden usar para los usos mencionados a excepción de ES):

  • DS: Registro del segmento de datos
  • ES: Registro del segmento extra
  • SS: Registro del segmento de pila
  • CS: Registro del segmento de código

Registros punteros (También pueden tener uso general):

  • BP: Registro de apuntadores base
  • SI: Registro índice fuente
  • DI: Registro índice destino


Registros especiales (Solo se pueden usar para los usos mencionados):

  • SP: Registro apuntador de la pila
  • IP: Registro apuntador de la siguiente instrucción
  • F: Registro de banderas (8 bits)


Bits del registro de banderas:

Overflow
  • NV (Apagado): No hay desbordamiento
  • OV (Encendido): Si lo hay


Direction
  • UP: Hacia adelante
  • DN: Hacia atras

Interrupts
  • DI: Desactivadas
  • EI: Activadas


Sign
  • PL: Positivo
  • NG: Negativo


Zero
  • NZ: No es cero
  • ZR: Si lo es

Auxilary carry
  • NA: No hay acarreo auxiliar
  • AC: Hay acarreo auxiliar

Parity
  • PO: Impar
  • PE: Paridad par


Carry
  • NC: No hay acarreo
  • CY: Si lo hay




Instrucciones del lenguaje ensamblador (NASM)


Instrucción MOV (MOVe):

Mueve o transfiere un byte o una palabra desde el operando fuente al operando destino. El dato transferido se copia, por lo que no desaparece del operando fuente. Tanto el operando fuente como el operando destino pueden ser un registro o un elemento de memoria. El operando fuente puede ser un valor inmediato.

 INSTRUCCIONES ARITMÉTICAS

Instruccione INC (INCrement):

Incrementa (suma 1 a) el contenido de un registro o de una posición de memoria.

 Instruccion DEC (DECrement):

Decrementa (resta 1 a) el contenido de un registro o de una posición de memoria. 

Instruccion ADD (ADDition):

Suma al operando de destino el valor o contenido del operando fuente, almacenándose el resultado en el operando de destino. Ambos operandos han de ser del mismo tamaño (byte o palabra).

Instruccion SUB (SUBstract):

Resta al operando de destino el valor o contenido del operando fuente, almacenándose el resultado en el operando de destino. Ambos operandos han de ser del mismo tamaño (byte o palabra).  

Instrucciones MUL (MULTiply) e IMUL:

Realiza una multiplicación con el acumulador. Si se realiza con AL, el operando de la instrucción debe ser de 8 bits, y ambos generan un resultado de 16 bits que se almacena en el registro AX. Sin embargo, si se realiza con AX, el operando de la instrucción debe ser de 16 bits, con lo que el resultado será de 32 bits y se almacenará en el par de registros DX (palabra de mayor peso) yAX (palabra de menor peso).

La diferencia entre MUL e IMUL, es que la instrucción MUL realiza una multiplicación sin signo (sin complemento a dos), mientras que la instrucción IMUL realiza una multiplicación con signo (con complemento a dos). 

Instrucciones DIV (DIVide) e IDIV:

 Realiza una división entre un número de 16 bits y otro de 8 bits, o entre un número de 32 bits y otro de 16 bits.

En el primer caso, el dividendo ha de estar en el registro AX, y el divisor será el operando, con un tamaño de 8 bits. Como resultado, el cociente de 8 bits se almacena en AL, y el resto de 8 bits se almacena en AH.

En el segundo caso, el dividendo ha de estar en la pareja de registros DX (palabra de mayor peso) y AX (palabra de menor peso), y el divisor ser el operando, con un tamaño de 16 bits. Como resultado, el cociente de 16 bits se almacena en AX, y el resto de 16 bits se almacena enDX. 

La diferencia entre DIV e IDIV es que la instrucción DIV realiza una división sin signo (sin complemento a dos), mientras que la instrucción IDIV realiza una división con signo (con complemento a dos). 


INSTRUCCIONES LÓGICAS  

Instruccion NOT (NOT):

Realiza un NOT lógico, bit a bit, con el operando, es decir, que invierte el valor de cada uno de los bits del operando.

Instruccion AND (AND):

Realiza un AND lógico, bit a bit, entre el operando destino y el operando fuente, almacenando el resultado en el operando destino. Como la filosofía de esta operación es "valor 1 si los dos bits son 1", se puede utilizar como máscara, filtrando sólo aquellos bits (1) del primer operando que coincidan con los bits (1) del segundo operando. 

Instruccion OR (OR):

Realiza un OR lógico, bit a bit, entre el operando destino y el operando fuente, almacenando el resultado en el operando destino. La filosofía de esta operación es "valor 0 si los dos bits son 0". Su utilidad es poner algunos bits a 1, inalterando el resto.

Instrucción XOR (eXclusive OR):

Realiza un XOR lógico, bit a bit, entre el operando destino y el operando fuente, almacenando el resultado en el operando destino. La filosofía de esta operación es "valor 0 si los dos bits son iguales". Su utilidad es invertir el valor de algunos bits, inalterando el resto; o bien hacer un XOR consigo mismo para poner el operando a 0.


Instrucción LOOP:

Gestiona un bucle, tomando el registro CX como contador del mismo. En sí, la instrucción LOOPdecrementa el valor de CX y, si no es igual a cero, salta a la etiqueta especificada. 

 
INSTRUCCIONES DE SALTO INCONDICIONAL.

 
Instrucción JMP (JuMP):

Realiza un salto de ejecución incondicional hacia la dirección o etiqueta especificada. 

Instrucciónes CALL Y RET (RETurn):

Realiza un salto incondicional hacia la dirección, etiqueta o procedimiento especificado. A diferencia de la instrucción JMP, la instrucción CALL realiza un salto a una subrutina con retorno. El salto puede ser cercano o lejano.