This article needs additional citations for verification. (January 2014) |
En el ámbito del diseño de unidades centrales de procesamiento (CPU) , los peligros son problemas con el flujo de instrucciones en las microarquitecturas de CPU cuando la siguiente instrucción no se puede ejecutar en el siguiente ciclo de reloj [1] y pueden conducir potencialmente a resultados de cálculo incorrectos. Tres tipos comunes de peligros son los peligros de datos, los peligros estructurales y los peligros de control (peligros de ramificación). [2]
Existen varios métodos utilizados para lidiar con los peligros, incluidos los bloqueos /burbujas en las tuberías, el reenvío de operandos y, en el caso de ejecución fuera de orden , el método de marcador y el algoritmo de Tomasulo .
Las instrucciones en un procesador segmentado se ejecutan en varias etapas, de modo que en un momento dado se procesan varias instrucciones en las distintas etapas de la segmentación, como la obtención y la ejecución. Existen muchas microarquitecturas de segmentación de instrucciones diferentes y las instrucciones pueden ejecutarse fuera de orden . Se produce un riesgo cuando dos o más de estas instrucciones simultáneas (posiblemente fuera de orden) entran en conflicto.
It has been suggested that this section be merged into Data dependency#Types. (Discuss) Proposed since August 2024. |
Los peligros de datos ocurren cuando las instrucciones que presentan dependencia de datos modifican los datos en diferentes etapas de un flujo de trabajo. Ignorar los posibles peligros de datos puede generar condiciones de carrera (también denominadas peligros de carrera). Hay tres situaciones en las que puede ocurrir un peligro de datos:
Lectura tras lectura (RAR) no es un caso de riesgo.
Considere dos instrucciones i1 e i2 , donde i1 aparece antes que i2 en el orden del programa.
( i2 intenta leer una fuente antes de que i1 escriba en ella) Un peligro de datos de lectura después de escritura (RAW) se refiere a una situación en la que una instrucción hace referencia a un resultado que aún no se ha calculado ni recuperado. Esto puede ocurrir porque, aunque una instrucción se ejecuta después de una instrucción anterior, la instrucción anterior se ha procesado solo parcialmente a través del proceso.
Por ejemplo:
i1.R2 < -R5 + R8i2.R4 < -R2 + R8
La primera instrucción calcula un valor que se guardará en el registro R2 y la segunda utilizará este valor para calcular un resultado para el registro R4 . Sin embargo, en una secuencia de comandos , cuando se obtienen los operandos para la segunda operación, los resultados de la primera aún no se han guardado y, por lo tanto, se produce una dependencia de datos.
Se produce una dependencia de datos con la instrucción i2 , ya que depende de la finalización de la instrucción i1 .
( i2 intenta escribir un destino antes de que i1 lo lea ) Un peligro de escritura después de lectura (WAR) representa un problema con la ejecución concurrente.
Por ejemplo:
i1. R4 <- R1 + R5 i2. R5 <- R1 + R2
En cualquier situación con posibilidad de que i2 termine antes que i1 (es decir, con ejecución concurrente), se debe garantizar que el resultado del registro R5 no se almacene antes de que i1 haya tenido la oportunidad de obtener los operandos.
( i2 intenta escribir un operando antes de que i1 lo escriba ) Un peligro de escritura tras escritura (WAW) puede ocurrir en un entorno de ejecución concurrente .
Por ejemplo:
i1.R5 < -R4 + R7i2.R5 < -R1 + R3
La escritura diferida (WB) de i2 debe retrasarse hasta que i1 termine de ejecutarse.
Un riesgo estructural ocurre cuando dos (o más) instrucciones que ya están en proceso necesitan el mismo recurso. El resultado es que la instrucción debe ejecutarse en serie en lugar de en paralelo durante una parte del proceso. Los riesgos estructurales a veces se denominan riesgos de recursos.
Ejemplo: una situación en la que hay varias instrucciones listas para entrar en la fase de ejecución de instrucciones y hay una única ALU (Unidad Aritmética Lógica). Una solución a este problema de recursos es aumentar los recursos disponibles, por ejemplo, tener varios puertos en la memoria principal y varias unidades ALU (Unidad Aritmética Lógica).
El riesgo de control se produce cuando el pipeline toma decisiones erróneas sobre la predicción de ramificaciones y, por lo tanto, introduce instrucciones que posteriormente deben descartarse. El término riesgo de ramificación también se refiere a un riesgo de control.
El burbujeo de la tubería , también denominado rotura de tubería o bloqueo de tubería , es un método para evitar peligros de datos, estructurales y de bifurcación. A medida que se obtienen instrucciones, la lógica de control determina si podría ocurrir/ocurrirá un peligro. Si esto es cierto, entonces la lógica de control no inserta operaciones ( NOP ) en la tubería. Por lo tanto, antes de que se ejecute la siguiente instrucción (que causaría el peligro), la anterior habrá tenido tiempo suficiente para finalizar y evitar el peligro. Si el número de NOP es igual al número de etapas en la tubería, el procesador ha sido despejado de todas las instrucciones y puede continuar sin peligros. Todas las formas de bloqueo introducen un retraso antes de que el procesador pueda reanudar la ejecución.
El vaciado del pipeline ocurre cuando una instrucción de bifurcación salta a una nueva ubicación de memoria, invalidando todas las etapas anteriores del pipeline. Estas etapas anteriores se borran, permitiendo que el pipeline continúe en la nueva instrucción indicada por la bifurcación. [3] [4]
Existen varias soluciones y algoritmos principales que se utilizan para resolver los riesgos de datos:
En el caso de ejecución fuera de orden , el algoritmo utilizado puede ser:
La tarea de eliminar dependencias de datos se puede delegar al compilador, que puede completar una cantidad apropiada de instrucciones NOP entre las instrucciones dependientes para garantizar el funcionamiento correcto o reordenar las instrucciones cuando sea posible.
Por ejemplo, escribir el valor 3 en el registro 1, (que ya contiene un 6), y luego sumar 7 al registro 1 y almacenar el resultado en el registro 2, es decir:
i0: R1 = 6 i1: R1 = 3 i2: R2 = R1 + 7 = 10
Después de la ejecución, el registro 2 debe contener el valor 10. Sin embargo, si i1 (escribir 3 en el registro 1) no sale completamente de la secuencia antes de que i2 comience a ejecutarse, significa que R1 no contiene el valor 3 cuando i2 realiza su adición. En tal caso, i2 suma 7 al valor anterior del registro 1 ( 6 ), y por lo tanto el registro 2 contiene 13 en su lugar, es decir:
i0: R1 = 6 i2: R2 = R1 + 7 = 13 i1: R1 = 3
Este error se produce porque i2 lee el Registro 1 antes de que i1 haya confirmado/almacenado el resultado de su operación de escritura en el Registro 1. Por lo tanto, cuando i2 lee el contenido del Registro 1, el registro 1 todavía contiene 6 , no 3 .
El reenvío (descrito a continuación) ayuda a corregir dichos errores al depender del hecho de que la salida de i1 (que es 3 ) puede ser utilizada por instrucciones posteriores antes de que el valor 3 se confirme o almacene en el Registro 1.
El reenvío aplicado al ejemplo significa que no hay que esperar para confirmar/almacenar la salida de i1 en el Registro 1 (en este ejemplo, la salida es 3 ) antes de poner esa salida a disposición de la instrucción subsiguiente (en este caso, i2). El efecto es que i2 utiliza el valor correcto (el más reciente) del Registro 1: la confirmación/almacenamiento se realizó inmediatamente y no se procesó.
Con el reenvío habilitado, la etapa de Ejecución/Descodificación de Instrucciones (ID/EX) del pipeline ahora tiene dos entradas: el valor leído del registro especificado (en este ejemplo, el valor 6 del Registro 1) y el nuevo valor del Registro 1 (en este ejemplo, este valor es 3 ) que se envía desde la siguiente etapa, Ejecución de Instrucciones/Acceso a Memoria (EX/MEM). Se utiliza una lógica de control agregada para determinar qué entrada utilizar.
Para evitar riesgos de control, las microarquitecturas pueden:
En el caso de que una rama provoque una burbuja en la tubería después de que hayan ingresado instrucciones incorrectas en la tubería, se debe tener cuidado para evitar que cualquiera de las instrucciones cargadas incorrectamente tenga algún efecto en el estado del procesador, excluyendo la energía desperdiciada al procesarlas antes de que se descubra que se cargaron incorrectamente.
La latencia de la memoria es otro factor que los diseñadores deben tener en cuenta, ya que el retraso podría reducir el rendimiento. Los distintos tipos de memoria tienen distintos tiempos de acceso a la memoria. Por lo tanto, al elegir un tipo de memoria adecuado, los diseñadores pueden mejorar el rendimiento de la ruta de datos canalizada. [5]