martes, 3 de marzo de 2009

Sobre el software DSP (parte III)

Capítulo IV

Velocidad de ejecución: Hardware


La potencia de las computadoras está aumentando tan rápidamente, que cualquier libro sobre el tema estará obsoleto antes de que sea publicado. El IBM PC original fue presentado en 1981, con base en el microprocesador 8088 con un reloj de 4,77 MHz y un bus de datos de 8 bits. Este fue seguido por una nueva generación de computadoras personales que se están introduciendo cada 3-4 años 8088→ 80286→ 80386→ 80486→ 80586 (Pentium). Cada uno de estos nuevos sistemas de computación impulsó la velocidad por un factor de cinco más que la tecnología anterior. En 1996, la velocidad de reloj había aumentado a 200 MHz, y el bus de datos a 32 bits. Con otras mejoras, esto se tradujo en un aumento de la potencia de las computadoras de casi mil en sólo 15 años. Podemos esperar otro factor de mil en los próximos 15 años.

La única forma de obtener información al día en la rápida evolución de este campo es directamente de los fabricantes: anuncios, folletos, listas de precios, etc. Olvídese de los datos de rendimiento de libros, revistas y busque en su diario. Esperamos que la velocidad de cálculo en bruto será más del doble cada dos años. Aprender sobre el estado actual de la potencia de las computadoras no es suficiente; necesitas comprender y seguir la forma en que está evolucionando.

Teniendo esto en cuenta, podemos saltar a una visión general de cómo la velocidad de ejecución está limitada por el hardware. Dado que las computadoras se componen de muchos subsistemas, el tiempo necesario para ejecutar una tarea en particular dependerá de dos factores principales: (1) la velocidad de los distintos subsistemas, y (2) el tiempo que se toma para la transferencia de datos entre estos bloques. La Figura 4-5 muestra un esquema simplificado de los más importantes componentes de la limitación de velocidad en un típico ordenador personal. La Unidad Central de Procesamiento (CPU) es el corazón del sistema. Como se describe anteriormente, se compone de una docena de registros, cada uno con capacidad para 32 bits (en la actual generación de computadoras personales). También se incluye en la CPU la electrónica digital necesaria para las operaciones rudimentarias, como el movimiento en torno a los bits y aritmética de punto fijo.

La mayoría de las matemáticas implicadas se manejan transfiriendo los datos a un circuito de hardware especial denominado coprocesador matemático (también llamado una unidad lógica aritmética, o ALU). El coprocesador matemático puede estar contenido en el mismo chip de la CPU, o puede ser otro dispositivo electrónico. Por ejemplo, la adición de dos números de punto flotante requeriría que la CPU transfiriera 8 bytes (4 por cada número) al coprocesador matemático, y de varios bytes que describieran qué hacer con los datos. Después de un corto tiempo de cálculo, el coprocesador matemático pasaría cuatro bytes de nuevo a la CPU, que contiene el número de punto flotante que es la suma. La mayoría de los sistemas de computación de bajo costo no tienen un coprocesador matemático, o lo proporcionan sólo como una opción. Por ejemplo, el microprocesador 80486DX tiene un coprocesador matemático interno, en tanto que el 80486SX no. Estos sistemas de rendimiento reducido sustituyen hardware con software. Cada una de las funciones matemáticas se dividen en operaciones elementales binarias que se pueden manejar directamente dentro de la CPU. Si bien esto proporciona el mismo resultado, el tiempo de ejecución es mucho más lento, por ejemplo, en un factor de 10 a 20.


La mayoría de software en el ordenador, puede ser utilizado con o sin un coprocesador matemático. Esto se logra haciendo que el compilador genere código de máquina para manejar ambos casos, todos almacenados en el programa ejecutable final. Si un coprocesador matemático está presente en el equipo concreto que se está utilizando, una sección del código se ejecutará. Si un coprocesador matemático no está presente, la otra sección del código será utilizado. El compilador también puede ser dirigido para generar el código sólo para una de estas situaciones. Por ejemplo, usted de vez en cuando encontrará un programa que requiere que un coprocesador matemático esté presente, y se colgará cuando se ejecuta en un ordenador que no tiene uno. Aplicaciones tales como tratamiento de textos por lo general no gozan de un coprocesador matemático. Esto es debido a que implican modificar los datos en torno a la memoria, no el cálculo de expresiones matemáticas. Del mismo modo, los cálculos de punto fijo variables (enteras) no se ven afectadas por la presencia de un coprocesador matemático, ya que se manejan dentro de la CPU. Por otro lado, la velocidad de ejecución de DSP y otros programas computacionales usando cálculos de punto flotante pueden ser de un orden de magnitud diferente con y sin coprocesador matemático.

El procesador y la memoria principal están contenidos en chips separados en la mayoría de los sistemas informáticos. Por razones obvias, te gustaría que la memoria principal fuese muy grande y muy rápida. Lamentablemente, esto hace la memoria muy cara. La transferencia de datos entre la memoria principal y la CPU es un cuello de botella muy común en la velocidad. La CPU pide a la memoria principal la información binaria en una dirección de memoria y, a continuación, debe esperar a recibir la información. Una técnica común para sortear este problema es utilizar una memoria caché. Esta es una muy pequeña cantidad de memoria de alta velocidad utilizada como un amortiguador entre la CPU y la memoria principal. Unos cientos de kilo bytes es típico. Cuando la CPU pide a la memoria principal proporcionar datos binarios en determinada dirección, la electrónica digital de alta velocidad copia e una sección de la memoria principal en torno a esta dirección en la memoria caché. La próxima vez que la CPU pida a la memoria información, es muy probable que ya estén contenidos en la memoria caché, con lo que la recuperación será muy rápida. Esto se basa en el hecho de que los programas tienden a acceder a lugares de la memoria que son vecinos a los que se a accedido previamente. En la aplicación típica de ordenador personal, la adición de una memoria caché puede mejorar en general la velocidad por varias veces. La memoria caché puede estar en el mismo chip de la CPU, o bien puede ser un dispositivo electrónico externo.

La tasa a la cual los datos se pueden transferir entre subsistemas depende del número de líneas de datos paralelas previstas, y la tasa máxima que las señales digitales que se pueden transmitir a lo largo de cada línea. Los datos digitales en general, pueden ser transferidos a una tasa muy superior dentro de un chip, frente a la transferencia de datos entre chips. Asimismo, los caminos de datos que deben pasar a través de conectores eléctricos a otras placas de circuito impreso (es decir, la estructura de bus) Puede ser más lento todavía. Esta es una fuerte motivación para el relleno de tanta electrónica como sea posible dentro de la CPU.

Un problema especialmente desagradable para la velocidad del ordenador es la compatibilidad hacia atrás. Cuando una empresa de computadoras introduce un nuevo producto, digamos una tarjeta de adquisición de datos o un programa de software, quieren vender el producto en el mercado más grande posible. Esto significa que debe ser compatible con la mayoría de las computadoras actualmente en uso, que puede abarcar varias generaciones de tecnologías. Con frecuencia, esto limita el rendimiento del hardware o software a la de un sistema mucho más antigua. Por ejemplo, supongamos que usted compra una tarjeta I / O que se conecta en el bus de 200 MHz Pentium de su computadora personal, que le proporciona ocho líneas digitales que pueden transmitir y recibir datos de un byte a la vez. Así, puede escribir un programa en ensamblador para la rápida transferencia de datos entre el ordenador y algunos dispositivos externo, como un experimento científico o con otra computadora. Pero para su sorpresa, la máxima tasa de transferencia de datos es sólo unas 100,000 bytes por segundo, más de mil veces más lento que la tasa del reloj del microprocesador! El villano es el bus ISA, una tecnología que es compatible hacia atrás con las computadoras de los primeros 1980.

La Tabla 4-6 proporciona tiempos de ejecución para varias generaciones de ordenadores. Obviamente, debe tratar estas aproximaciones como muy toscas. Si quieres entender tu sistema, toma mediciones de tu sistema. Es muy fácil; escribir un bucle que ejecute una operación que ejecute un millón de alguna operación, y mirar el tiempo que tarda. Los tres primeros sistemas, el 80286, 80486 y Pentium, son el estándar de ordenadores de escritorio personales de 1986, 1993 y 1996, respectivamente. El cuarto es un microprocesador de 1994 diseñado especialmente para tareas de DSP, el Texas Instruments TMS320C40.



El Pentium es más rápido que el sistema 80286 por cuatro razones, (1) la mayor velocidad de reloj, (2) más líneas en el bus de datos, (3) la adición de una memoria caché, y (4) una mayor eficiencia interna de diseño, que requiere un menor número de ciclos de reloj por instrucción.

Si el Pentium era un Cadillac, el TMS320C40 sería un Ferrari: menos comodidad, pero velocidad cegadora. Este chip es representante de varios microprocesadores diseñados específicamente para reducir el tiempo de ejecución de algoritmos DSP. Otros en esta categoría son el i860 de Intel, AT & T DSP3210, Motorola DSP96002, y la Analog Devices ADSP-2171. A estos se les conoce por los nombres siguientes: microprocesador DSP, Digital Signal Processor, y RISC (Reduced Instruction Set Computer). Este último nombre refleja que el aumento de la velocidad se debe a un menor número de instrucciones de montaje nivel que se pone a disposición de los programadores. En comparación, los microprocesadores más tradicionales, como el Pentium, son llamados CISC (Complex Instruction Set Computer).

Los microprocesadores DSP se utilizan de dos formas: como módulos esclavos bajo el control de un ordenador más convencional, o como incrustados en un procesador dedicado, como un teléfono móvil. Algunos modelos sólo manejan números de punto fijo, mientras que otros pueden trabajar con punto flotante. La arquitectura interna utilizada para obtener la mayor velocidad incluye: (1) los lotes de la caché de memoria muy rápida que figuran en el chip, (2) buses separados para el programa y los datos, lo que permite el acceso a dos a la vez (llamada Arquitectura de Harvard), (3) hardware rápido para cálculos matemáticos que figuran directamente en el microprocesador, y (4) el diseño pipeline.

Una arquitectura pipelin (tubería) rompe el hardware necesario para una determinada tarea en varias etapas sucesivas. Por ejemplo, la adición de dos números puede hacerse en tres etapas pipeline. La primera etapa del pipeline, no hace nada pero obtiene los números a sumar de memoria. La única tarea de la segunda etapa consiste en añadir los números. La tercera etapa no hace nada, pero almacena el resultado en la memoria. Si cada etapa puede concluir su tarea en un solo ciclo de reloj, todo el procedimiento se llevará a tres ciclos de reloj para ejecutarse.

La característica fundamental de la estructura de tuberías es que otra tarea se puede iniciar antes de la anterior tarea esté finalizada. En este ejemplo, podría comenzar la adición de otros dos números tan pronto como la primera etapa esté inactiva, al final del primer ciclo de reloj. Para un gran número de operaciones, la velocidad del sistema se cita como una suma por ciclo de reloj, incluso aunque la adición de dos números cualesquiera requiere de tres ciclos de reloj para completarse. Los pipeline son de gran velocidad, pero pueden ser difíciles de programar. El algoritmo debe permitir el comienzo de un nuevo cálculo, a pesar de que los resultados de los cálculos anteriores no estén disponibles (ya que aún están en tramitación).

Velocidad de ejecución: Consejos de programación

Aunque computadoras y lenguajes de programación son importantes para maximizar la velocidad de ejecución, no son algo tu puedas cambiar de un día para otro. En comparación, la forma en que programas lo puedes cambiar en cualquier momento, y afecta de manera drástica al tiempo en que el programa requerirá para ejecutarse. He aquí tres sugerencias.

En primer lugar, utiliza variables enteras en lugar de punto flotante cuando sea posible. Los microprocesadores convencionales, como los utilizados en los ordenadores personales, procesan los enteros de 10 a 20 veces más rápido que los números de punto flotante. En los sistemas sin un coprocesador matemático, la diferencia puede ser de 200 a 1. Una excepción a esto es la división, que es a menudo realizada mediante la conversión de los valores en coma flotante. Esto hace la operación horriblemente lenta en comparación con otros cálculos enteros.

En segundo lugar, evita el uso de funciones como: sin(x), log(x), yx, etc. Estas trascendentales funciones se calculan como series de adiciones, sustracciones y multiplicaciones. Por ejemplo, las series de potencias de Maclaurin disponen:


Si bien estas relaciones son de longitud infinita, los términos se vuelven rápidamente lo suficientemente pequeños como para ser ignorados. Por ejemplo:


Estas funciones requieren alrededor de diez veces más tiempo para calcularse que una sola adición o multiplicación. Varios trucos se pueden utilizar para eludir estos cálculos, tales como: x3 =x ∙ x ∙ x; sin (x) = x, cuando x es muy pequeño; sin (-x) = -sin (x) , donde ya sabes uno de los valores y necesitas encontrar el otro, etc. La mayoría de los lenguajes sólo tienen unas pocas funciones trascendentales, y esperan que usted derive las demás por medio de las relaciones en la siguiente tabla. No es de extrañar, que estos cálculos que se derivan sean aún más lentos.



Otra opción es precalcular estas funciones lentas, y almacenar los valores en una tabla de búsqueda "look-up table" (LUT). Por ejemplo, imagine que un sistema de 8 bits de adquisición de datos utilizados para supervisar continuamente el voltaje a través de una resistencia. Si el parámetro de interés es la potencia que se disipa en la resistencia, la medición de voltaje se puede utilizar para calcular: P=V2 / R. Como alternativa más rápida, la potencia correspondiente a cada uno de las 256 posibles mediciones de voltaje se puede calcular de antemano, y se almacenan en una LUT. Cuando el sistema está en funcionamiento, la medición de tensión, un número digital entre 0 y 255, se convierte en un índice en la LUT para encontrar la correspondiente potencia. La búsqueda en tablas pueden ser cientos de veces más rápida que el cálculo directo.

En tercer lugar, aprende lo que es rápido y lo que es lento en su sistema en particular. Esto viene con la experiencia y las pruebas, y siempre habrá sorpresas. Presta especial atención a los comandos gráficos y I / O. Usualmente hay varias formas de manejar estos requisitos, y las velocidades pueden ser tremendamente distintas. Por ejemplo, el comando de BASIC: BLOAD, transfiere un archivo de datos directamente a una sección de la memoria. Al leer el mismo archivo en la memoria byte-por-byte (en un bucle) puede ser 100 veces más lento. Como otro ejemplo, el comando de BASIC: LINE, se puede utilizar para dibujar un cuadro de color en la pantalla de vídeo. Dibujar el mismo cuadro píxel por píxel puede ser 100 veces más lento. Incluso poner una declaración de impresión dentro de un bucle (para realizar un seguimiento de lo que está haciendo) puede demorar la operación por ¡miles de veces!

Texto basado en: "The Scientist and Engineer's Guide to Digital Signal Processing"
Steve Smith

No hay comentarios:

Publicar un comentario