martes, 17 de mayo de 2011

Segmentación, generalidades (Parte II)

La primera parte tocó el tema de la segmentación y su efecto sobre la velocidad y el rendimiento de los procesadores, esta va un poco mas lejos señalando los inconvenientes de dicha segmentación, los problemas con las paradas y técnicas como el multithreading y las combinaciones de ambos. Hay una referencia a un artículo sobre la estructura de P4 mas adelante que aunque está en inglés, les recomendaría revisar para ubicarse en la parte de las etapas del mencionado procesador. Eso, aquí termina esta mini serie, el inicio del original correspondiente lo pueden encontrar aquí. Creo que ya sabían que era de Arstechnica, así pues, provecho!

Introducción
La primera parte de la presente serie cubrió las bases de la segmentación, y concluyó con un debate preliminar sobre como la segmentación incrementa el rendimiento de las aplicaciones. En concreto, la segmentación aumenta la velocidad a la que se completan las instrucciones, con el resultado de que el tiempo global de ejecución de un programa es bajo. O bien, otra manera de decirlo sería que la segmentación permite que el procesador pueda completar más instrucciones en un período determinado de tiempo, con el resultado de que un lote particular de instrucciones (es decir, un programa) se procesa más rápidamente.
El presente artículo cuantifica el aumento de velocidad resultante de la segmentación de manera más precisa, y detalla algunos de los inconvenientes de las segmentaciones muy profundas, como las que se encuentran en el Pentium 4 de Intel.
Nota al lector: Los dos artículos de esta serie están diseñados para ser leído "pegados", por lo que si se sumerge en la siguiente sección y encuentra que está perdido, le podría ayudar volver atrás y revisar el relativamente breve artículo anterior. De hecho, si usted acaba de leer la última página de la Parte I, debe estar listo para comenzar la Parte II.

La aceleración de la segmentación.
En general, la aceleración en la tasa de terminación en comparación con una implementación de un solo ciclo que se obtiene como resultado de la segmentación es idealmente igual al número de etapas de la segmentación. Una segmentación de cuatro etapas produce una aceleración de cuatro veces en comparación con una tasa de terminación de ciclo único, una tubería de cinco etapas obtiene un aumento de velocidad de cinco veces, un rendimiento de segmentación de doce etapas una aceleración de doce veces, y así sucesivamente. Este aumento de velocidad es posible gracias a que mientras mas etapas o segmentos hay en un procesador, mas instrucciones se pueden trabajar en forma simultánea y mas instrucciones se pueden completar en un período determinado de tiempo. Así que cuanto más finamente se puedan dividir las cuatro fases del ciclo de vida de la instrucción, mas hardware usado para implementar estas fases podrá poner a trabajar en un momento dado.
Para volver a nuestra analogía de la línea de montaje, digamos que cada equipo se compone de seis trabajadores, y que cada una de las tareas de una hora de duración que cada equipo lleva a cabo puede ser fácilmente subdivide en dos tareas más cortas, de 30 minutos. Así que podemos duplicar el rendimiento de nuestra fábrica mediante el fraccionamiento de cada equipo en dos equipos especializados mas pequeños de tres trabajadores cada uno, y luego hacemos que cada equipo más pequeño, realice una tarea más corta en una camioneta por 30 minutos.
1.- Etapa 1: Construir el chasis.

  • Equipo 1a: Coloca las piezas del chasis juntas y suelda puntos en las uniones.
  • Equipo 1b: Suelda totalmente las partes del chasis.
2.- Etapa 2: Colocar el motor en el chasis.

  • Equipo 2a: Coloca el motor en el chasis y lo monta en su lugar.
  • Equipo 2b: Conecta el motor a las partes móviles del coche.
3.- Etapa 3: Poner puertas, el capó, y las cubiertas en el chasis.

  • Equipo 3a: Pone las puertas y el capó en el chasis.
  • Equipo 3b: Pone el resto de las cubiertas en el chasis.
4.- Etapa 4: Montar las ruedas.

  • Equipo 4a: Coloca las dos ruedas delanteras.
  • Equipo 4b: Coloca las dos ruedas traseras.
5.- Etapa 5: Pintar el SUV.

  • Equipo 5a: Pinta los lados de la camioneta.
  • Equipo 5b: Pinta la parte superior de la camioneta.
Después de las modificaciones descritas anteriormente, las diez tripulaciones más pequeñas en nuestra fábrica tendrían ahora un total de diez SUV en curso durante un período de 30 minutos dados. Además, nuestra fábrica puede ahora completar un nuevo SUV cada 30 minutos, una mejora de diez veces más en la tasa de terminación de nuestra primera fábrica de un SUV cada cinco horas. Así segmentando nuestra línea de montaje, incluso más profundamente, hemos puesto aún más de sus trabajadores a trabajar de forma simultánea, lo que aumenta el número de SUVs en los que se puede trabajar en forma simultánea y aumenta el número de camionetas que pueden ser completadas en un plazo determinado de tiempo.
Profundizando la tubería de nuestro procesador de cuatro etapas funciona bajo iguales principios y tiene un efecto similar en las tasas de terminación. Al igual que las cinco etapas en nuestra planta de fabricación de SUV se pueden desagregarse en una secuencia más larga de etapas más especializadas, podemos tomar el proceso de ejecución que cada instrucción atraviesa y dividirla en una serie mayor que solo cuatro etapas discretas. Al dividir la segmentación del procesador de cuatro etapas en una serie más larga de etapas más cortas y más especializadas, podemos poner aún más hardware especializado del procesador a trabajar simultáneamente con más instrucciones y por lo tanto aumentar el número de instrucciones que la tubería completa cada nanosegundo.

En primer lugar, pasamos de un procesador de un solo ciclo a un procesador segmentado, tomando el período de tiempo de cuatro nanosegundos que la instrucción emplea en viajar a través del procesador y dividiéndola en cuatro etapas discretas de segmentos de un nanosegundo de longitud cada uno. Estas cuatro etapas de segmentación discretas corresponde a las cuatro fases del ciclo de vida de una instrucción. Sin embargo, las etapas de segmentación de un procesador no siempre van a corresponder exactamente a las cuatro fases del ciclo de vida de una instrucción. Algunos procesadores tienen una segmentación de cinco etapas, algunos de seis etapas, y muchos tienen tuberías de más de diez o veinte etapas. En tales casos, el diseñador del CPU debe dividir el ciclo de vida de la instrucción en el número deseado de etapas, de tal forma que todas las etapas sean iguales en longitud.
Ahora tomemos el proceso de ejecución de cuatro nanosegundos y dividámoslo en ocho etapas discretas. Debido a que las ocho etapas de segmentación deben ser de exactamente la misma duración para que funcionen correctamente, las ocho etapas deben ser de 4 ns / 8 = 0.5ns de longitud cada una. Ya que estamos trabajando actualmente con un ejemplo idealizado, supongamos que la división del ciclo de vida de cuatro fases del procesador en ocho etapas de segmentos de .5 ns idénticos es un asunto trivial, y que los resultados parecen a lo que puede ver en las figuras PIPELINING .6.1 y PIPELINING.6.2. (En realidad, esta tarea no es trivial e implica una serie de desventajas. Como una concesión a esa realidad, he optado por utilizar las ocho etapas de una tubería en el mundo real, la segmentación de MIPS, en los siguientes diagramas, en lugar de dividir cada una de las cuatro etapas tradicionales en dos.)

Debido a que la segmentación requiere que a cada etapa de la tubería le tome exactamente un ciclo de reloj para completarse, entonces, nuestro ciclo de reloj ahora se puede acortar a 0.5ns para poder adaptarse a las longitudes de las ocho etapas de la tubería. Eche un vistazo a las figuras PIPELINING.6.1 y PIPELINING.6.2 a continuación para ver el impacto que este aumento del número de etapas de la tubería tiene en el número de instrucciones completado por unidad de tiempo.
Figura PIPELINING 6.1: Una segmentación de cuatro etapas
Figura PIPELINING 6.2: Una segmentación de ocho etapas.
Nuestro procesador de un solo ciclo pudo completar una instrucción cada cuatro nanosegundos, para una tasa de finalización de instrucciones de 0,25/ns, y nuestro procesador con una segmentación de cuatro etapas pudo completar una instrucción cada nanosegundo para una tasa de finalización de instrucciones de una instrucción por ns. El procesador de ocho etapas representado arriba mejora a ambos completando una instrucción cada 0.5ns, para una tasa de terminación de dos instrucciones por ns. Tenga en cuenta que debido a que a cada instrucción todavía le toma 4ns ejecutarse, los cuatro primeros nanosegundos del procesador de ocho etapas aún se dedican a llenar la tubería. Pero una vez que la tubería está llena, el procesador puede empezar a completar las instrucciones dos veces más rápido que el procesador de cuatro etapas y ocho veces más rápido que el procesador de un solo ciclo.
Este aumento de ocho veces en la tasa de terminación en comparación con un diseño en un solo ciclo significa que nuestro procesador de ocho etapas puede ejecutar programas mucho más rápido que uno de un solo ciclo o un procesador de cuatro etapas. Pero, ¿el aumento de ocho veces en la tasa de terminación se traduce en una disminución de ocho veces en el tiempo de ejecución del programa? No exactamente.

Tasa de conclusión y tiempo de ejecución del programa.
Si el programa que el procesador de un solo ciclo en la figura PIPELINING.4 está ejecutando consistía de sólo las cuatro instrucciones representadas, entonces, el programa tendría un plazo de ejecución de 16 ns, o 4ns/instrucción x 4 instrucciones. Si el programa consiste en, por ejemplo, siete instrucciones, tendría un plazo de ejecución de programa de 4ns/instrucción x 7 instrucciones = 28 ns. En general, el tiempo de ejecución de un programa es igual a la tasa de terminación de instrucciones del procesador (número de instrucciones completadas por nanosegundo) multiplicada por el número total de instrucciones del programa.

Tiempo de ejecución del programa = tasa de finalización de instrucciones x número de instrucciones de programa.

En el caso de un procesador de un solo ciclo no segmentado, la tasa de finalización de instrucciones (X ns por una instrucción) es simplemente el inverso del tiempo de ejecución de la instrucción (una instrucción por X ns). Con los procesadores segmentados, esto no es así.
Si nos fijamos en la caja de "Instrucciones Completadas" del procesador de cuatro etapas en la figura PIPELINING.5, vemos que un total de cinco instrucciones se han completado en el inicio del noveno nanosegundo. Por el contrario, los procesadores sin "segmentación" completan dos instrucciones al inicio del noveno nanosegundo. Cinco instrucciones completadas en un lapso de ocho nanosegundos obviamente no es una mejora de cuatro veces más sobre dos instrucciones completadas en el mismo período de tiempo, así que ¿qué pasa?

Hay que recordar que al procesador segmentado le tomó cuatro nanosegundos inicialmente llenarse con instrucciones, el procesador con "segmentación" no completó su primera instrucción hasta el final del cuarto nanosegundo. Por lo tanto, completó menos instrucciones en los primeros 8 ns de la ejecución de ese programa de lo que habría completado si la tubería estuviera llena durante los 8 ns.
Cuando el procesador está ejecutando programas que constan de miles de instrucciones, entonces a medida que el número de nanosegundos se extiende hasta los miles el impacto en el tiempo de ejecución del programa de los primeros cuatro nanosegundos, durante los cuales se completa una sola instrucción, comienza a desaparecer y la ventaja del procesador segmentado comienza a acercarse a la marca de las cuatro veces. Por ejemplo, después de 1000 nanosegundos, el procesador sin "pipeline" ha completado 250 instrucciones (1000ns * .25 Instrucciones/ns = 250 instrucciones), mientras que el procesador segmentado ha completado 996 instrucciones ((1000ns - 4ns) / 1 instruccion/ns) una mejora de 3,984 veces.

Lo que acabo de describir con el ejemplo concreto de arriba es la diferencia entre la tasa máxima de finalización teórica de una tubería y su tasa media de terminación en el mundo real. En el ejemplo anterior, La tasa máxima teórica de finalización del procesador de cuatro etapas, es decir, su tasa de finalización en los ciclos, en que su tubería está llena, es una instrucción por ns. Sin embargo, la tasa de finalización promedio del procesador durante sus primeros ocho ns es de 5 instrucciones/8 ns = 0,625 instrucciones/ns. La tasa media de terminación de procesador mejora a medida que pasa más ciclos de reloj con su línea llena, hasta que en 1000 nanosegundos su tasa de terminación promedio es de 996 instrucciones/1000 ns = 0,996 instrucciones/ns.

En este punto, podría ser útil observar el gráfico de la tasa de completamiento promedio de nuestra tubería de cuatro etapas a medida que el número de nanosegundos aumenta:
Gráfico de segmentación 1: Tasa de completamiento promedio para una segmentación de cuatro etapas.
Usted puede ver cómo la tasa de completamiento promedio del procesador queda en cero hasta la marca de los 4 ns, después de lo cual la tubería se llena y el procesador puede comenzar a completar una nueva instrucción en cada nanosegundo, haciendo que la tasa promedio para todo el programa ascienda y, finalmente, se acerque a la tasa de terminación máxima de 1 instrucción/ns.
Así que en conclusión, un procesador con "segmentación" sólo puede acercarse a su tasa de terminación ideal si  puede mantener por largos períodos su línea llena en cada ciclo de reloj.

Rendimiento de instrucciones y demoras de segmentación.
A pesar de lo que pueden haberle llevado a creer las páginas anteriores, la segmentación no es totalmente "gratis". La segmentación añade cierta complejidad a la lógica de control del microprocesador, porque todas estas etapas tienen que mantenerse en sincronía. Aún más importante para nuestra discusión actual, sin embargo, es el hecho de que la segmentación agrega cierta complejidad al diseño de microprocesadores y a las formas en que se evalúa el rendimiento del procesador.
Hasta ahora, hemos hablado sobre el rendimiento del microprocesador sólo en términos de tasa de finalización de instrucciones, o el número de instrucciones que la tubería del procesador puede completar cada nanosegundo. Una métrica de interpretación más común en el mundo real es el rendimiento de instrucciones de una tubería, o el número de instrucciones que el procesador completa en cada ciclo de reloj. Usted podría estar pensando que el rendimiento de instrucción de una tubería debe ser una instrucción/reloj, porque hemos dicho que un procesador con "segmentación" completa una nueva instrucción al final de cada ciclo de reloj en el que la etapa de escritura ha estado activa. Pero nótese cómo la parte destacada de la definición la califica un tanto, ya hemos visto que la etapa de escritura está inactiva durante los ciclos de reloj en los que se llena la tubería, por lo que en esos ciclos de reloj el rendimiento de instrucciones del procesador es de 0 instrucciones/reloj . En cambio, cuando tubería de instrucciones está llena y la etapa de escritura está activa, el procesador segmentado tiene un rendimiento de instrucción de 1 instrucción/reloj.

Así como hubo una diferencia entre la tasa máxima teórica de finalización de un procesador y su tasa media de terminación, también hay una diferencia entre el rendimiento máximo teórico de instrucción del procesador y su rendimiento promedio de instrucción.
  1. Rendimiento de instrucción: El número de instrucciones que el procesador termina de ejecutar en cada ciclo de reloj. También verá el rendimiento de instrucción expresado como instrucciones por ciclo de reloj (IPC instructions per clock).
  2. Máximo rendimiento teórico de instrucción: El número máximo teórico de instrucciones que el procesador puede terminar de ejecutar en cada ciclo de reloj. Para los tipos de procesadores simples segmentados y no segmentados descritos hasta ahora, este número es siempre una instrucción por ciclo (1 instrucciones/ciclo o 1 IPC).
  3. Promedio de rendimiento de instrucción: El número promedio de instrucciones por ciclo de reloj (IPC) que el procesador ha completado efectivamente durante un determinado número de ciclos.
El rendimiento de instrucciones de un procesador está íntimamente ligado a su tasa de finalización de instrucciones Mientras mas instrucciones complete el procesador en cada ciclo de reloj, mas instrucciones completará cada nanosegundo. Hablaremos más sobre la relación entre estos dos indicadores en un momento, pero por ahora sólo recuerde que un mayor rendimiento de instrucción se traduce en una tasa mayor de terminación de instrucciones, y por lo tanto, un mejor rendimiento.

Paradas de segmentación.
En el mundo real, la tubería de un procesador encara mas condiciones que sólo las dos descritas hasta el momento es decir, una tubería llena o una tubería que está siendo llenada. A veces, las instrucciones quedan atascadas en una tubería por varios ciclos. Hay una serie de razones por las cuales esto puede ocurrir, pero cuando ocurre, la tubería se dice que está detenida. Cuando la tubería se detiene, o se queda colgada en un determinado momento, todas las instrucciones en las etapas por debajo de la que queda detenida continúan avanzando con normalidad, mientras que la instrucción sólo se encuentra estancada en su etapa y detiene todas las instrucciones detrás de ella. En la figura siguiente, la instrucción naranja se ha estancado durante dos ciclos adicionales en la etapa de obtención de información (fetch). Puesto que la instrucción está paralizada, una nueva brecha se abre delante de ella en la tubería para cada ciclo en que está detenida. Una vez que la instrucción comienza a avanzar a través de la tubería de nuevo, los espacios vacíos en la tubería que se crearon por la detención, espacios que comúnmente se llaman "burbujas de segmentación", viajan a través de la tubería adelante de la instrucción que estaba estancada hasta que finalmente dejna la tubería.
Figura PIPELINING 7: Paradas de segmentación en una segmentación de cuatro etapas.
Las paradas de segmentación, o burbujas, reducen el rendimiento promedio de instrucciones de una tubería, ya que impiden que la segmentación alcance el rendimiento máximo de una instrucción completada por ciclo. En la figura PIPELINING.7 arriba, la instrucción naranja se ha estancado en la fase de fetch durante dos ciclos adicionales, creando dos burbujas que se propagan a través de la tubería. (Una vez más, la burbuja es simplemente una manera de expresar que la etapa de la tubería en la que la burbuja se asienta no está haciendo ningún trabajo durante ese ciclo). Una vez que las instrucciones de abajo de la burbuja se han completado, el procesador no completará instrucciones nuevas hasta que las burbujas se muevan fuera de la tubería. Así que hasta el final de los ciclos de reloj 9 y 10, no se agregan nuevas instrucciones a la caja de "Instrucciones completadas", normalmente, dos nuevas instrucciones se añadirían a la región al final de estos dos ciclos. A causa de las burbujas, sin embargo, el procesador estará dos instrucciones "atrasado" cuando llega el ciclo de reloj numero 11 y comienza a acumular instrucciones completadas de nuevo.

Mientras más de estas burbujas se acumulen en la tubería, tanto más lejos estará el procesador de su rendimiento máximo de instrucciones real. En el ejemplo anterior, el procesador debería de haber completado 7 Instrucciones para el momento en que termina el ciclo 10, para un rendimiento de instrucción promedio de 0,7 instrucciones por ciclo de reloj. (Recuerde que el rendimiento máximo de instrucciones posible en condiciones ideales es de una instrucción por ciclo de reloj, pero serían necesarios muchos más ciclos sin burbujas para aproximarse a este máximo.) Pero debido a la parada de segmentación, el procesador solo completa cinco instrucciones en 10 relojes, para un rendimiento de instrucción promedio de 0,5 instrucciones por ciclo de reloj. 0.5 instrucciones por ciclo de reloj es la mitad del rendimiento máximo teórico de instrucción, pero, por supuesto, el procesador dedica varios relojes a llenar la la tubería por lo que no podría haberlo logrado después de 10 relojes, incluso bajo condiciones ideales. Más importante es el hecho de que 0,5 instrucciones por ciclo de reloj es sólo el 71% del rendimiento que se podría haber logrado si no hubieran paradas (es decir, 0,7 instrucciones por ciclo de reloj).
Debido a que las demoras de segmentación reducen el rendimiento promedio de instrucciones del procesador, aumentan la cantidad de tiempo que se tarda en ejecutar el programa actualmente en ejecución. Si el programa en el ejemplo anterior consistía en sólo las siete instrucciones ilustradas, la demora se hubiera traducido en un aumento del tiempo de ejecución del programa del 29%.

Echemos un vistazo a un gráfico que muestra lo que hace esta demora de dos ciclos al rendimiento promedio de instrucciones:
Gráfico PIPELINING 2: Rendimiento de instrucciones promedio para una segmentación de cuatro etapas con una parada de dos ciclos.
El rendimiento promedio de instrucciones de procesador deja de subir y empieza a caer en picada cuando la burbuja llega a la primera etapa de escritura, y no se recupera hasta que las burbujas han dejado la tubería.
Para obtener una imagen aún mejor el impacto que las demoras pueden tener en el rendimiento de instrucción promedio de la segmentación, veamos ahora el impacto que una parada de diez ciclos (a partir de la etapa de fetch del ciclo 18) tendría a lo largo de 100 ciclos en la tubería de cuatro etapas descrita hasta ahora.
Gráfico PIPELINING 3: Rendimiento promedio de instrucciones para una segmentación de cuatro etapas con una parada de diez ciclos. 
Después de que la primera burbuja de la demora llega a la etapa de escritura en el reloj 20 el rendimiento de instrucción promedio deja de aumentar y comienza a disminuir. Por cada reloj en el que hay una burbuja en la etapa de escritura, el rendimiento de instrucción de segmentación es 0 instrucciones/ciclo de reloj por lo que el rendimiento promedio de instrucción para todo el período sigue disminuyendo. Después de que la última burbuja ha salido de la etapa de escritura, entonces, la tubería comienza completar las instrucciones otra vez a un ritmo de una instrucción por ciclo y su rendimiento promedio de instrucción comienza a subir. Y cuando el rendimiento de instrucciones del procesador comienza a subir, también lo hace la tasa de terminación y su rendimiento en los programas.
Un gran porcentaje de las características arquitectónicas de los procesadores que he tratado en los últimos años se han dedicado a la prevención de las paradas de segmentación. La predicción de saltos, en particular, viene a la mente, porque es una herramienta esencial para evitar que el procesador esté bloqueado durante un gran número de ciclos en la fase de obtención de información (fetch).

Latencia de instrucción y paradas de segmentación.
Antes de concluir nuestra discusión sobre las demoras de segmentación, debemos introducir otro término que verá periódicamente durante el resto de este artículo: Latencia de instrucción. La latencia de instrucción es el número de ciclos de reloj que le toma a la instrucción pasar a través de la tubería. Para un procesador de un solo ciclo, todas las instrucciones tienen una latencia de un ciclo de reloj. Por el contrario, para el segmentado simple de cuatro etapas descrito hasta ahora, todas las instrucciones tienen una latencia de cuatro ciclos. Para obtener una imagen visual de esto, observemos nuevamente la instrucción azul en la figura anterior PIPELINING.4, a esta instrucción le toma cuatro ciclos de reloj avanzar, a razón de un ciclo de reloj por etapa, a través de cada una de las cuatro etapas de la tubería. Del mismo modo, las instrucciones tienen una latencia de ocho ciclos en una tubería de ocho etapas, doce ciclos de una tubería de doce etapas, y así sucesivamente.
En los procesadores del mundo real, la latencia de instrucción no es necesariamente un número fijo igual al número de etapas de la tubería. Porque las instrucciones se pueden quedar atascadas en una o varias etapas de una tubería de varios ciclos, cada ciclo adicional que pasan esperando en una etapa de la tubería añade un ciclo más a su latencia. Así que las latencias de instrucciones dadas anteriormente, es decir, cuatro ciclos de una tubería de cuatro etapas, ocho ciclos de una tubería de ocho estados, etc, representan latencias mínimas de instrucción. Las latencias reales de instrucciones en tuberías de cualquier longitud puede ser más largas que la profundidad de la tubería, dependiendo de si la instrucción se detiene o no en una o mas etapas.

Límites de la segmentación.
Como podrán imaginar, hay límites prácticos a que tan profundamente se puede segmentar una línea de montaje o un procesador antes de que la aceleración real de la tasa de terminación que ofrece la segmentación comience a ser significativamente menor que el aumento de velocidad ideal que se podría esperar. En el mundo real, las diferentes fases del ciclo de vida de una instrucción no se descomponen fácilmente en un número arbitrariamente alto de etapas más cortas de duración perfectamente iguales. Algunas etapas son inherentemente más complejas y toman más tiempo que otras. Pero debido a que cada etapa en la tubería debe tomar exactamente un ciclo de reloj para completarse, entonces, el pulso de reloj que coordina todas las etapas no puede ser más rápido que la fase mas lenta de la tubería. En otras palabras, la cantidad de tiempo que le toma a la etapa más lenta en la tubería completarse determinará la duración del ciclo de reloj de la CPU y por lo tanto la longitud de cada etapa de la tubería. Esto significa que la etapa más lenta de la tubería pasará trabajando el ciclo completo del reloj, mientras que las etapas más rápidas pasarán parte del ciclo de reloj inactivas. Esto no sólo malgasta recursos, sino que aumenta el tiempo de ejecución general de cada instrucción arrastrando algunas fases del ciclo de vida para tener más tiempo de lo que le llevaría a un procesador no segmentado Todas las otras etapas deberán esperar un poco más de tiempo de cada ciclo, mientras que la etapa más lenta se pone al día.

Así a medida que ud divide la tubería con más precisión a fin de añadir etapas y aumentar el rendimiento, las etapas individuales tienen una longitud menos y menos uniforme y una complejidad también diferente, con el resultado de que el tiempo total de ejecución de la instrucción del procesador de se hace más largo. Debido a esta característica de la segmentación, uno de los retos más difíciles e importantes a los que el diseñador de la CPU se enfrenta es el de equilibrar de la tubería de manera que ninguna etapa tenga que hacer más trabajo que cualquier otra. El diseñador debe distribuir el trabajo de procesamiento de una instrucción de manera uniforme para cada etapa, de manera que ninguna se tome demasiado tiempo y por lo tanto haga mas lenta la tubería.
Usted puede ver la evidencia de este difícil acto de equilibrio con mayor claridad en las etapas drive del Pentium 4 (si quieren detalles referentes al P4, pueden encontrarlos en este artículo, en la segunda página hay una descripción de todas sus etapas ndt), que son etapas, cuyo único propósito es conducir las señales a través del chip. Si Intel no hubiera dado a estos dos períodos de propagación de señales sus dos etapas separadas, entonces, se hubieran tenido que alargar todas las demás etapas de la tubería  debido a los retrasos de propagación de la señal en dos partes de la tubería.

Período de reloj y la tasa de finalización.
Si el tiempo de ciclo de reloj del procesador segmentado, o período de reloj, es más largo que su longitud ideal (es decir, el tiempo de ejecución de la instrucción sin segmentación/profundidad de segmentación), y siempre lo es, entonces la tasa de finalización del procesador sufrirá. Si el rendimiento de instrucción se mantiene fijo, por ejemplo en una instrucción/reloj, luego a medida que el período de reloj aumenta, disminuye la tasa de terminación. Debido a que las nuevas instrucciones pueden ser completadas sólo al final de cada ciclo de reloj, un reloj de ciclo más largo se traduce en menos instrucciones completadas por nanosegundo, que a su vez se traduce en mayores tiempos de ejecución del programa.
Para tener una mejor idea de la relación entre la tasa de finalización, el rendimiento de la instrucción, y el tiempo de ciclo de reloj, veamos nuestra línea de ocho etapas de la figura PIPELINING.8 y aumentemos su tiempo de ciclo de reloj a 1ns en lugar de 0.5ns. A continuación sus nueve primeros nanosegundos de ejecución, se verían de la siguiente manera:
Figura PIPELINING 8: Una segmentación de ocho etapas con un período de reloj de 1 ns.
Como puede ver, el tiempo de ejecución de la instrucción se ha incrementado de un tiempo original de cuatro nanosegundos a un nuevo tiempo de ocho nanosegundos, lo que significa que la tubería de ocho etapas no completa su primera instrucción hasta el final del octavo nanosegundo. Una vez que la tubería está llena, el procesador de la imagen superior comienza completar las instrucciones a un ritmo de una instrucción por nanosegundo. Esta tasa de terminación es la mitad de la tasa de terminación de una segmentación ideal de ocho etapas con un tiempo de ciclo de reloj 0.5ns. También es la misma tasa exacta de finalización que la tasa de terminación de una instrucción/ns de la segmentación ideal de cuatro etapas. En resumen, el tiempo de ciclo de reloj más largo de nuestra nueva segmentación de ocho etapas ha privado a la segmentación más profunda de su ventaja respecto a la tasa de terminación. Además, la tubería de ocho etapas ahora emplea el doble de tiempo en llenarse. Echa un vistazo a lo que este tiempo de ejecución duplicado le hace a la curva media de tasa de finalización de la segmentación de ocho etapas frente a la misma curva de una tubería de cuatro etapas.
Gráfico PIPELINING 4: Tasa media de completamiento de instrucciones para segmentaciones de 4 y 8 etapas con un período de reloj de 1 ns.
Se necesita más tiempo para llenar una tubería más lenta de ocho etapas, lo que significa que su tasa media de terminación y por lo tanto su desempeño subirán más lentamente cuando la tubería se llena por primera vez con las instrucciones. Hay muchas situaciones en que un procesador que ejecuta un programa deberá limpiar su tubería por completo y luego comenzar a rellenarla desde un punto diferente en el flujo de código. En estos casos, este ritmo mas lento de la subida de la tasa de finalización causa un impacto en el rendimiento.

Cómputo superescalar y segmentación.
El cómputo superescalar permite a un microprocesador aumentar el número de instrucciones por ciclo de reloj que completa mas allá de 1 instrucción/reloj. Recordemos que una instrucción/reloj fue el máximo rendimiento de instrucción teórica para un procesador con "segmentación" como describimos anteriormente. Debido a que una máquina superescalar puede tener múltiples instrucciones en múltiples etapas de escritura en cada ciclo de reloj, la máquina superescalar puede completar múltiples instrucciones por ciclo. Si adaptamos a nuestros diagramas de tubería anterior para representar dos vías de ejecución superescalar, se vería de la siguiente manera:
Figura PIPELINING 11: Ejecución superescalar y segmentación combinadas.
En la figura anterior, dos instrucciones se agregan al cuadro de "Instrucciones completadas" en cada ciclo una vez que la tubería está llena. Cuanto más unidades ALU tenga un procesador operando en paralelo, mas instrucciones podrá añadir a ese cuadro en cada ciclo. Así, la informática superescalar nos permite aumentar la tasa de IPC de un procesador añadiendo más hardware. Hay algunos límites prácticos de cuantas instrucciones se pueden ejecutar en paralelo, por lo que el procesador no siempre llega a la tasa de terminación ideal de dos instrucciones por ciclo de reloj. A veces, el procesador no puede encontrar dos instrucciones a ejecutar en paralelo en un ciclo particular, lo que significa que se debe insertar una burbuja de segmentación en una de las tuberías de ese ciclo, con lo que la tasa de terminación desciende.

Segmentación y multithreading simultáneos.
Mantener la tasa media de terminación del procesador en una maquina superescalar segmentada consiste en encontrar maneras de programar instrucciones para ejecutar en paralelo en cada ciclo. Pero debido a que el flujo de código está diseñado para ser secuencial, existen algunos límites inherentes a la cantidad de paralelismo que el procesador puede extraer de el.
Una de las maneras en que los últimos procesadores de Intel, IBM y AMD resuelven este problema es mediante la inclusión de soporte para múltiples hilos simultáneos (también conocido como hyperthreading o "SMT") en sus procesadores y luego pedir el programador y/o compilador que hagan el flujo de código tan explícitamente paralelo como sea posible. Sólo las aplicaciones multitarea, puede sacar el máximo provecho del SMT y el multithreading sólo puede hacerse por la parte que diseña la aplicación.

El diseño de aplicaciones multhreading implica la identificación de partes de una aplicación que se pueden dividir en tareas discretas e independientes, y la asignación de estas tareas a hilos separados de ejecución. Este proceso de múltithreading de una aplicación de hecho convierte un único flujo de código secuencial en un conjunto de dos o más secuencias relacionadas con el código que puede ejecutarse en paralelo. Y cuando dos hilos de ejecución concurrentes forman parte del mismo programa, entonces, la tasa de finalización media del programa aumentará debido a que más de sus instrucciones se completarán en cada ciclo. En este sentido, SMT puede aumentar la tasa de finalización media de un programa porque le permite aprovechar mejor el hardware superescalar.
Figura PIPELINING 12: Diseño de aplicaciones multihilos.
Mediante el diseño de la secuencia de código desde el principio como un conjunto de pequeños flujos de código ejecutándose simultáneamente, parte de la carga de extraer el paralelismo a nivel de instrucción se mueve desde el procesador al programador/compilador. Tenga en cuenta que los compiladores son muy pobres en tal paralelización, de manera que generalmente corresponde a los programadores diseñar la aplicación para que se pueda dividir en varios subprocesos.
No todas las aplicaciones se prestan a una implementación multiproceso. En tales casos, SMT ofrece pocas ventajas. En realidad en un momento hablaremos de porque esto es así. Por ahora, vamos a ver de otra manera en que SMT puede mejorar el rendimiento de la aplicación.

SMT no sólo mejora el rendimiento de las aplicaciones mediante el aumento de la tasa de finalización promedio de una aplicación multiproceso, en condiciones normales (es decir, todas las instrucciones se encuentran en la memoria caché L1), sino que también puede evitar que la tasa de terminación llegue a cero como consecuencia de fallos (miss) de caché y latencias de la memoria . Cuando el procesador está ejecutando dos hilos simultáneamente, y uno de los hilos se detiene en la etapa del fetch (es decir, hay un error de cache (cache miss) por lo que el hilo debe traer instrucciones o datos de la memoria principal), el procesador puede continuar ejecutando normalmente el hilo que no se estancó. En un procesador sin SMT, las burbujas de segmentación afloran por debajo de la instrucción estancada y se propagan en el núcleo de ejecución, matando la tasa de finalización promedio de la aplicación. El procesador SMT, por el contrario, puede programar las instrucciones del hilo no estancado para que se ejecuten en dichas franjas de tiempo disponibles en la segmentación.
Si los dos hilos en el escenario anterior pertenecen a la misma aplicación, entonces, SMT impide que la tasa de conclusión de la aplicación multihilo caiga a cero durante la duración de la parada al continuar la ejecución de código de un hilo no estancado. Esto ayuda a mantener la tasa media de completamiento elevada y a reducir el tiempo necesario para ejecutar la aplicación. Por otro lado, si los dos hilos son de aplicaciones separadas de hilo simple, la tasa de finalización de la aplicación con el hilo estancado se reducirá a cero, mientras que la tasa de terminación para la aplicación con el hilo no estancado se mantiene igual o puede mejorar. En los casos en que la tasa de completamiento de la aplicación que no se estancó mejora, es debido a que el hilo estancado ya no consume recursos de procesador que el hilo no estancado necesite acceder.

Al final, lo más probable es que dos aplicaciones de hilo simple se ejecutarán un poco más lento en un procesador SMT, en función de los tipos de aplicaciones y otras condiciones, ya que pueden enfrentarse entre sí por los recursos compartidos (memoria caché, por ejemplo, unidades de ejecución, colas de entradas, etc.) La mayoría de los diseños SMT utilizan una variedad de técnicas para minimizar estos enfrentamientos y sus efectos, pero siempre es un factor.

Conclusiones
Al final, las ganancias de rendimiento generadas por la segmentación dependerán de dos cosas:
  1. Las paradas en la segmentación deben ser evitadas. Como hemos visto anteriormente, las paradas en la segmentación causan que la tasa de completamiento y el rendimiento del procesador disminuyan.
  2. Los llenados de segmentación se deben evitar a toda costa. Llenar la tubería del procesador tiene un grave efecto sobre la tasa de terminación y el rendimiento. Esto es especialmente cierto cuando una tubería es muy larga, pero tiene una velocidad de reloj que es comparable a la de un procesador con una tubería más corta.
Los buffers profundos que componen la ventana de instrucciones del Pentium 4, tienen como objetivo la eliminación de las paradas de segmentación. Una vez más, el Pentium 4 paga un precio relativamente alto en términos de seguimiento de instrucciones y sobrecarga de búffers a fin de evitar que las paradasacaben con el rendimiento.
Como he descrito en artículos anteriores, el Pentium 4 y Prescott gastan un montón de recursos en la predicción de saltos con el fin de eliminar los llenados innecesarios de la tubería. Los llenados de segmentación son extremadamente letales para el funcionamiento de una máquina hypersegmentada, especialmente cuando la velocidad del reloj no es lo suficientemente alta como para compensar, por lo que Prescott especialmente paga un costo bastante elevado en transistores y consumo de energía para su elaborada lógica de predicción de saltos.

Por otra parte, Prescott tiene que escalar a una frecuencia significativamente mayor que la de los Pentium 4 si se trata de ejecutar mejor un código poco predecible y con muchos saltos. A su ritmo de reloj actual relativamente bajo, Prescott va a atravesar un tiempo muy duro con cualquier otra cosa que no sea código sin saltos y mas previsible (por ejemplo, multimedia y aplicaciones de juegos). A medida que Intel intenta exprimir un año o dos de Prescott, se puede esperar a verlo combinado con una cantidad extremadamente grande de caché en el chip. Esta caché ayudará con el código de enteros ramificado, como el que se encuentra en aplicaciones de servidor.
También debe quedar claro en este punto porque Prescott está en tantos problemas que Intel dio un giro a la compañía y se embarcó en un curso muy diferente que incluye tuberías superficiales y diseños multinúcleo. Como he demostrado anteriormente, la escalada de frecuencia es crítica si una máquina muy segmentada debe tener un buen desempeño, y la escalada de frecuencias es exactamente a lo que todas las empresas del microprocesadores se enfrentan por problemas relacionados con la alimentación en la transición a 90nm. De hecho, los problemas de escaladas de frecuencia podría decirse que son el talón de Aquiles de un diseño hypersegmentado, y los problemas que impiden esta escalada, son como la proverbial flecha envenenada en el talón de Prescott.
Descargar versión en PDF aquí