Buscar en este blog

Tema 2.d: Explicación en detalle de los predictores de salto multinivel y adaptativos


En este artículo exploraremos con un poco más de profundidad algunas de las técnicas de resolución de riesgos de control, de los que ya hablamos en un artículo anterior.
Los riesgos de control son aún más frecuentes que los de datos, se dan en una de cada cinco instrucciones habitualmente, y tienen un impacto muy negativo sobre el cauce de ejecución de las instrucciones, penalizando incluso las soluciones tomadas para resolver los otros tipos de riesgo.

Nos centraremos en los predictores de salto multinivel y adaptativos.

Los predictores multinivel se denominan así porque pueden tener en cuenta información tanto local (del salto que se está intentando predecir) como global (de los demás saltos del programa). Estarán compuestos entonces de predictores locales y predictores globales y seguirán una notación como la siguiente (G, L) en la que la letra G indica el número de saltos globales que se tienen en cuenta y la L el número de bits del predictor local.

De los predictores locales hay dos tipos que son los que se usan con más frecuencia: los de 1 y 2 bits que en la notación vista se denominarían (0,1) y (0,2) respectivamente.

El de 1 bit sigue el esquema siguiente: tiene valor 1 si la última vez se tomó el salto y 0 si no fue así. Si la predicción falla se cambia su valor. Es un planteamiento muy sencillo y con una utilidad limitada ya que para ciclos repetitivos se suele fallar dos veces.

Con dos bits el esquema se vuelve un poco más complejo y nos protegemos de las excepciones en bucles condicionales repetitivos, se puede observar mejor su comportamiento en la siguiente figura:


Pueden implementarse predictores de más de dos bits pero la práctica ha demostrado que no merece la pena.

El uso de los predictores multinivel se basa en que se puede predecir el resultado del salto de una instrucción en función de los resultados de instrucciones de salto anteriores.

Los predictores adaptativos (o tournament predictors) tienen la capacidad de escoger un predictor local o un predictor global según cuál se vaya a comportar mejor para un determinado salto.

Si el buffer de predicción predice que el salto no se toma, no hay ningún retraso puesto que al ciclo siguiente se busca la instrucción siguiente. Pero si se predice que el salto se va a tomar, no se puede buscar la instrucción destino de salto hasta que no se haya calculado la dirección de esta instrucción. Y una vez que se conozca esta instrucción ya se conoce si el salto se toma realmente o no, así que no tiene sentido continuar utilizando la predicción.

La solución está en implementar algún mecanismo que permita predecir también la dirección destino de salto. Este mecanismo es el buffer de predicción de destino de salto llamado BTB (Branch Target Buffer).

El uso del BTB resulta especialmente importante en arquitecturas como la MIPS en la que conocemos a la vez el resultado de evaluar la condición de salto y la dirección de destino del mismo. El BTB es en esencia una caché que almacena la dirección destino que tuvo cada salto la última vez que se tomó. El acceso al BTB se hace durante la etapa IF de las instrucciones: al mismo tiempo que se busca la instrucción en la memoria de instrucciones con su dirección se accede al BTB para saber si se trata de una instrucción de salto.

Otra forma de predicción de saltos adaptativa y que resulta especialmente útil para aquellos saltos que se evalúan en tiempo de ejecución (saltos indirectos) es la pila de direcciones. La razón por la que no se puede usar el BTB con la misma fiabilidad para este tipo de saltos radica en que la dirección de destino del salto va variando en cada ejecución de la instrucción de retorno.

Esta pila funciona de manera que se almacenan las direcciones desde las que se llama a los procedimientos. Si la pila es lo suficientemente profunda, cuando se realicen los retornos se irán recuperando las direcciones adecuadas de la pila y se cumplirán las predicciones con un elevado porcentaje de acierto.

En el gráfico siguiente se puede ver el rendimiento de esta técnica en distintos procesadores.

Tema 2.f: Utilización del multithreading en las arquitecturas para gráficos y multimedia


Como su propio nombre indica el ‘multithreading’ (procedente de ‘thread’: hilo, en consecuencia ‘múltiples hilos’) es una técnica muy común en el mundo de la informática que permite ejecutar secuencias de instrucciones (diferentes partes de un programa) de forma simultánea y en paralelo con otras funciones. Dicho de otra manera el multithreading permite ejecutar múltiples subprocesos a la vez (o de forma concurrente). De esta manera se optimizan al máximo los recursos disponibles, ya que se pueden procesar instrucciones de dos o más hilos a la vez utilizando el paralelismo a nivel de hilo (ya hemos visto otro tipo de uso del paralelismo: segmentación). Lo que supone un uso racional y eficiente de los recursos de nuestro ordenador, ya que empleamos los recursos que ya están en uso para una tarea simultánea con una ligera variante de un mismo proceso.

A la tarea de crear un nuevo ‘hilo’ de ejecución dentro de un proceso existente, en vez de empezar un nuevo proceso para una nueva función es a lo que denominamos ‘multithreading’.

Como hemos esbozado al principio los threads o ‘hilos’ son semiprocesos que comparten memoria y datos entre ellos y están caracterizados por un punto definido de comienzo, una secuencia de ejecución y un punto de finalización.

 Así es posible utilizar tareas que se ejecutan en segundo plano, tratar flujos de entrada simultáneos, administrar interfaces de usuario, entre otras cosas.

Por lo tanto algunas de las ventajas del multithreading son: que las aplicaciones tienen un mejor tiempo de respuesta (incluso en máquinas con un solo CPU), que permite que una aplicación utilice varios procesadores simultáneamente y, en definitiva, produce un mejor aprovechamiento del sistema informático.

Otras de las ventajas que se pueden advertir con respecto a la programación secuencial son: la división de las secuencias de instrucciones o tareas en partes más simples, tratando cada una de ellas de forma parcial o completamente en paralelo. También el multithreading aprovecha los tiempos muertos que pueda encontrar en varias sub-fases en la resolución de problemas para construir otra parte del proceso. A lo que se suma que el multithreading es más barato en términos de recursos de sistema utilizados que los sistemas multiproceso.
Para desempeñar de forma óptima su tarea el multithreading utiliza contadores de programas independientes, mecanismos de etiquetado para distinguir las instrucciones de diferentes hilos y un mecanismo que ‘dispara’ el cambio de hilo.

También tendremos que diferenciar el ‘multi-hilo preventivo’ en el que el sistema operativo distribuye el tiempo del proceso entre los hilos y los interrumpe a intervalos regulares para dar paso al siguiente en la cola (ejemplo: Windows 95/ NT,Unix) y el ‘multi-hilo cooperativo´ en el que cada hilo o thread toma el control de la CPU el tiempo que necesita.

Las tareas que involucran mucha ejecución, las operaciones de matrices, las tareas de procesamiento de señales digitales, los elementos llamados por una aplicación con frecuencia, la validación de datos y los procesos que consumen mucho tiempo de CPU, entre otros, son los más indicados para utilizar los multithreading.

Por este motivo el multithreading juega un papel clave en los procesadores gráficos actuales, ya que es muy sencillo aprovechar los paralelismos. Por ejemplo, en los cálculos que se deben realizar para cada vértice o fragmento, se produce el ahorro de tener que repetir la misma tarea una y otra vez sobre diferentes datos en memoria.


Ejemplo de multithreading en una tarjeta gráfica

Por lo tanto, la capacidad de las GPUs actuales que solucionan cálculos de manera eficaz aprovechando los paralelismos a través del multithreading, no solo se utilizan para generar gráficos sino que se emplean también en complejas operaciones de cálculo científico que se descomponen a la vez en muchos hilos que resuelven dichas operaciones.

 

Algunas de las APIS (application programming interface) como DirectX11 de Microsoft, incluye el multithreading entre sus cualidades, con lo que consigue tasas de frames por segundo (FPS) más rápidos para los juegos, sin perder por ello ningún detalle visual.

Tema 2.g: Análisis de una arquitectura de procesador de propósito general; el FX-8150 de AMD



En el artículo de hoy vamos a analizar la arquitectura del procesador FX-8150 Black Edition de AMD.

Sus características son:

  • -        Presume de ser el primer procesador para ordenadores de sobremesa que dispone de 8 núcleos.
  • -        Está basado en el socket AM3+ (tipo de interconexión con la placa base).
  • -        Cada núcleo está desbloqueado de fábrica para permitir el overclock con el software propio de AMD OverDrive.
  • -        Cada núcleo funciona de forma nativa a 3.6 GHz y se puede overclockear hasta 4.2 GHz.
  • -        Tecnología de fabricación de 32 nm SOI (Silicon On Insulator) fabricado por GLOBAL FOUNDRIES en Dresden, Alemania.
  • -        Tecnología AMD Turbo Core que aumenta automáticamente el rendimiento del procesador.
  • -        Jerarquía de memoria: L1=128 Kb por núcleo dividido en 64Kb para instrucciones y 64 Kb para datos, L2=1 Mb por núcleo, L3=8 Mb compartida por los 8 núcleos. En total: L1=1Mb, L2=8 Mb, L3= 8Mb.
  • -        Tecnología HyperTransport: hasta 4000 MT/s en full dúplex, o hasta 16 Gb/s ancho de banda de entrada/salida.
  • -        Controlador de memoria integrado de 128 bits que soporta hasta DDR3 a 1866 MHz. Con un ancho de banda de hasta 21 Gb/s en doble canal.
  • -        Trabaja en condiciones de máximo funcionamiento a 61ºC con un consumo de 125 W.
  • -        Cada núcleo de este procesador se llama Bulldozer o Zambezi.

Hasta aquí la información disponible para el público en general, pero distintos sitios de internet que se dedican a hacer comparativas tienen datos tanto de las presentaciones comerciales de AMD como de sus propias observaciones sobre el procesador. Una de las cosas que más ha llamado mi atención es que cuando AMD dice “8 núcleos” hay que prestar mucha atención a las comillas…

¿Qué es un núcleo? De acuerdo a lo que dice AMD, un core es cualquier sistema que tenga sus propios cauces de ejecución para enteros. Y hace muy bien en decir esto, al menos si quiere vender su modelo de procesador Bulldozer basado en 4 módulos compuestos de dos “seminúcleos” cada uno. El esquema real de un módulo del procesador FX-8150 es el del gráfico siguiente.


Aquí podemos ver claramente que el núcleo de cada módulo tiene una unidad de enteros exclusiva pero comparte la de coma flotante y la caché de nivel 2. Eso no se publicitaba en la página oficial.
Esta arquitectura presenta sus ventajas, ya que tiene mayor escalabilidad y predictibilidad que la solución de Intel de dos hilos de ejecución por núcleo (Hyperthread). La impresión general es que es un núcleo más versátil con capacidad de aprovechar muy bien las tareas que puedan repartirse entre varios núcleos pero con un peor rendimiento en general y en particular para aplicaciones monotarea.


En los sistemas operativos actuales, el FX-8150 aparece como 8 procesadores, análogamente un Dual Core de Intel de dos núcleos con Hyperthreading representa cuatro núcleos para el sistema operativo. Sin embargo Windows 7 maneja perfectamente la carga de trabajo con los Hyperthreaded pero para el Bulldozer sólo distribuye tareas entre los módulos, no entre los cores. Con ello la adaptabilidad del FX-8150 se ve seriamente mermada.

Estas y otras circunstancias van a hacer que en los benchmarks el procesador de AMD quede normalmente por detrás de sus principales competidores de Intel y, paradójicamente, que procesadores anteriores de AMD teóricamente inferiores o con menos núcleos (aunque como hemos visto puede que estemos comparando peras con manzanas al corresponder los núcleos a arquitecturas muy distintas en concepto).

De la información comercial de AMD también se puede extraer la siguiente imagen que nos da idea de algunas de las ideas que se han implementado para este procesador:



Las etapas de IF e ID (Instruction Fetch e Instruction Decode) son comunes para ambos núcleos de cada módulo, AMD usa multithreading entrelazado para controlar el identificador de cada instrucción en curso, decidir qué hilo necesita seguir avanzando, y realizar las operaciones de ese hilo. Es capaz de cambiar entre cada hilo a cada ciclo de reloj para compensar la ejecución de ambos hilos.

AMD desliga el predictor de saltos de la etapa IF permitiéndole que se adelante independientemente de cualquier retraso que se pueda producir en el cauce. Esto le permite a AMD, según sus propias palabras, implementar una característica llamada “prediction-directed instruction prefetch” (precarga de instrucciones basada en los resultados de las predicciones) que según ellos aumenta mucho la tasa de acierto y la eficiencia energética.

Existen cientos de páginas de comparativas entre distintos programas usados para hacer el benchmarking y no tiene sentido reproducir todas, ni siquiera un extracto. Puestos a quedarnos cortos y siempre en aras de simplificar y hacer el artículo más interesante y educativo pongo a continuación la que a mí me resulta más interesante: la comparativa para el juego Resident Evil 5 que salió oficialmente en Marzo de 2009.


Los resultados son descorazonadores y mirando por internet el resto de ejemplos, casi sin excepción, abunda en resultados similares. La impresión que me queda después de ver varias comparativas es que el FX-1850 está adelantado a su tiempo y los desarrolladores de sistemas operativos y software multimedia todavía no son capaces de sacar provecho de su arquitectura. Sin embargo desde mi punto de vista AMD ha hecho una apuesta de futuro que si bien puede no salir bien económicamente podría dar una grata sorpresa en los próximos años ya que parece analizar bien las tendencias de las plataformas venideras.



Como último punto indicar que este es un producto que sale para un mercado muy específico en el que prima la relación rendimiento/tiempo en vez del rendimiento puro. Para ese target AMD logra unos precios muy ajustados que hacen su producto más competitivo de lo que podía parecer un principio. A día de hoy su precio ronda los 200 Euros mientras que los que le quedan justo por debajo y por encima en rendimiento de Intel oscilan entre los 210 y los 300 Euros respectivamente.











Bibliografía:

Tema 2.h: Análisis de una arquitectura de GPU; GTX 560Ti


En este artículo vamos a analizar la tarjeta que tengo instalada en mi propio ordenador: Gigabyte NVIDIA GeForce GTX 560 Ti Super OverClock Rev 2 (GV-N560SO-1GI-950), actualmente con los drivers 301.42 de Nvidia.

Las especificaciones completas de mi sistema han cambiado ligeramente respecto al artículo1.d y son ahora: placa base tipo Asus M2N32-SLI Deluxe, procesador AMD Athlon 64 X2 Dual Core 6400+, 8 GB de memoria RAM (4X2 GB) DDR2 800 Corsair Dual Channel y sistema operativo Windows 7 Ultimate Service Pack 1 (64 bits).

Y la puntuación que me otorga Windows 7 en su propia herramienta de diagnóstico es:


A primera vista parece confirmar lo que ya sospechaba: que el cuello de botella de mi sistema se encuentra en el procesador, ya que a los discos duros no les doy tanta importancia para la tarea que más hago en mi ordenador: jugar y programar. Así mismo, parece que mi tarjeta gráfica está muy bien puntuada con un 7,7 sobre 7,9 (aproximadamente un 9,7 en una escala del 1 al 10).

Vayamos ahora con las características de la tarjeta según la información del bundle y la página web del fabricante:

Chipset GeForce GTX 560 Ti
Frecuencia del Core 950 MHz
Shader Clock 1900 MHz
Frecuencia de la Memoria 4580 MHz
Process Technology 40 nm
Memoria 1GB
Bus de Memoria 256 bit
Tipo de Bus PCI-E 2.0
Tipo de Memoria GDDR5
DirectX 11
OpenGL 4.1
PCB Form ATX
Multi View 2
E/S HDMI*1 (by cable), D-sub*1 (by adapter), DVI-I*2, mini HDMI*1
Maximum Digital Resolution 2560x1600
Maximum VGA Resolution 2048x1536
Card size H43mm x L255mm x W139mm
Power requirement Minimum 550W or greater system power supply with one 8-pin and one 6-pin external power connectors

Comentarios adicionales del fabricante:

  1. GIGABYTE WindForce™ 2X cooling design
  2. Support NVIDIA 3D Vision™ and SLI technologies
  3. Features Dual link DVI-I*2 / mini HDMI with HDCP protection

Las diferencias entre la versión básica (derecha), la de este artículo (centro) y otra nueva versión con 448 núcleos CUDA se pueden ver en la siguiente comparativa:


Como siempre, la información que nos da el fabricante de la tarjeta es muy justa y se limita a su implementación sin hablar casi del chip Nvidia, con lo que apenas nos sirve a la hora de elegir un modelo para nuestro sistema. Tendremos que ir a la página de Nvidia o a otras páginas especializadas donde al hacer los análisis nos digan qué se esconde de verdad dentro de la GPU. Y como viene siendo habitual también, en español encontraremos menos información que en las versiones en inglés de las páginas de los fabricantes.

De la web de Nvidia se extrae la siguiente información sobre el chip GTX 560 Ti:

Especificaciones de la GPU:
CUDA Cores 384
Reloj de gráficos (MHz) 822
Reloj del procesador (MHz) 1645
Tasa de relleno de texturas (miles de millones/s) 52.5
Especificaciones de la memoria:
Reloj de la memoria (MHz) 4008
Config. de memoria estándar 1024 MB GDDR5
Interfaz de memoria 256-bit
Ancho de banda de memoria (GB/s) 128.0
Funciones disponibles:
NVIDIA SLI® Ready* 
NVIDIA 3D Vision Surround Ready **
Tecnología NVIDIA PureVideo®***
HD Tecnología NVIDIA PhysX™ 
Tecnología NVIDIA CUDA™ 
Soporte de bus PCIe 2.0 x16
Certificado para Windows 7 
NVIDIA 3D Vision Ready 
Especificaciones térmicas y potencia:
Temperatura máxima de la GPU (en ºC) 99 C
Consumo máximo de la tarjeta gráfica (W) 170 W
Requisitos mínimos de potencia del sistema (W) 500 W
Conectores de alimentación suplementarios 22,86 cm

Del análisis hecho en The Guru of 3D podemos obtener las siguientes características:


El corazón de todas las GTX 560 Ti es el núcleo Fermi GF114 que se compone de 2 GPC (Graphic Processing Clusters), cada uno de ellos con 4 SM (Streaming Multiprocessors) compuestos a su vez de 48 Streaming Processors para hacer un total de 2x4x48=384 “núcleos CUDA”.

En esta imagen vemos la disposición general de la tarjeta, con 8 núcleos de memoria para hacer un total de 1 Gb.


En la siguiente podemos ver el esquema del núcleo GF114:

Y en esta el esquema de cada SM y ampliado el núcleo CUDA:

En cuanto al rendimiento hay numerosas pruebas que se pueden ver en los enlaces de la bibliografía, si bien mi impresión en general es que es una tarjeta que puede con todo, con un consumo de potencia ajustado (que no bajo…) y extremadamente silenciosa.

Como curiosidad incluyo los benchmarks hechos con varias tarjetas en la página Tom's Hardware para el Crysis 2:


Y el valor que saco yo en mi sistema con esos mismos ajustes y habiendo descargado el pack de mejora de DirectX11 y las texturas avanzados, todo al máximo y a 1680x1050:

2012-06-02 22:00:15 - Crysis2
Frames: 2286 - Time: 60000ms - Avg: 38.100 - Min: 29 - Max: 60

2012-06-02 22:02:35 - Crysis2
Frames: 3139 - Time: 60000ms - Avg: 52.317 - Min: 29 - Max: 61

2012-06-02 22:06:42 - Crysis2
Frames: 1618 - Time: 60000ms - Avg: 26.967 - Min: 15 - Max: 34

2012-06-02 22:10:54 - Crysis2
Frames: 1546 - Time: 60000ms - Avg: 25.767 - Min: 13 - Max: 31

En la última prueba bajé el Overclock de la tarjeta a los siguientes valores:
GPU Clock                  855 MHz
Memory Clock                       1031 MHz
Mientras que en el resto eran:
GPU Clock                  950 MHz
Memory Clock                       1145 MHz

Pero me producían corrupción gráfica. En este y en otros juegos he detectado errores, ralentizaciones y corrupción gráfica cuando estoy en valores cercanos a los 900 MHz, así que el Overclock de fábrica no es tan fiable como parecía en la documentación comercial.

Bibliografía: