Runahead es una técnica que permite a un procesador de computadora preprocesar especulativamente instrucciones durante ciclos de falla de caché . Las instrucciones preprocesadas se utilizan para generar prefetchs de instrucciones y flujos de datos ejecutando instrucciones que conducen a fallas de caché (normalmente llamadas cargas de latencia larga ) antes de que ocurran normalmente, ocultando de manera efectiva la latencia de la memoria . En runahead, el procesador utiliza los recursos de ejecución inactivos para calcular las direcciones de las instrucciones y los flujos de datos utilizando la información disponible que es independiente de una falla de caché. Una vez que el procesador ha resuelto la falla de caché inicial, todos los resultados de runahead se descartan y el procesador reanuda la ejecución de manera normal. El caso de uso principal de la técnica es mitigar los efectos del muro de memoria . La técnica también se puede utilizar para otros fines, como precalcular los resultados de las bifurcaciones para lograr una predicción de bifurcaciones altamente precisa . [1]
El principal costo del hardware es un medio para controlar el estado del archivo de registros . Normalmente, los procesadores de ejecución anticipada también contienen una pequeña memoria caché adicional , que permite que las operaciones de almacenamiento anticipado se ejecuten sin modificar la memoria real . Algunas implementaciones también utilizan unidades de aceleración de hardware dedicadas para ejecutar partes específicas de instrucciones preprocesadas. [2] [3]
Runahead se investigó inicialmente en el contexto de un microprocesador en orden; [4] sin embargo, esta técnica se ha extendido para su uso con microprocesadores fuera de orden . [5]
En principio, cualquier evento puede provocar un runahead, aunque normalmente la condición de entrada es una falla en el caché de datos de último nivel que llega al comienzo del buffer de reordenamiento . [5] En un procesador fuera de orden normal, estas instrucciones de carga de latencia tan larga bloquean el retiro de todas las instrucciones más jóvenes hasta que se soluciona la falla y se retira la carga.
Cuando un procesador entra en modo runahead, realiza un control de todos los registros arquitectónicos y registra la dirección de la instrucción de carga que provocó la entrada en runahead. Todas las instrucciones en el pipeline se marcan entonces como runahead. Debido a que el valor devuelto de un error de caché no se puede conocer de antemano, es posible que las instrucciones preprocesadas dependan de datos desconocidos o no válidos . Los registros que contienen dichos datos, o datos que dependen de ellos, se denotan agregando un bit "inválido" o INV a cada registro en el archivo de registros. Las instrucciones que usan o escriben dichos datos no válidos también se marcan con un bit INV. Si la instrucción que inició el runahead fue una carga, se emite un resultado falso y se marca como INV, lo que le permite marcar su registro de destino como INV y salir del pipeline.
En el modo runahead, el procesador continúa ejecutando instrucciones después de la instrucción que inició el runahead. Sin embargo, el runahead se considera un estado especulativo en el que el procesador solo intenta generar datos adicionales y errores de caché de instrucciones que son, en realidad, prefetches. El diseñador puede optar por permitir que el runahead omita instrucciones que no están presentes en la caché de instrucciones con el entendimiento de que la calidad de cualquier prefetch generado se reducirá ya que se desconoce el efecto de las instrucciones faltantes.
Los registros que son el destino de una instrucción que tiene uno o más registros de origen marcados como INV se marcan como INV. Esto permite que el procesador sepa en qué valores de registro se puede confiar (probablemente) durante el modo de ejecución anticipada. Las instrucciones de bifurcación que no se pueden resolver debido a los registros de origen INV simplemente se supone que se predijeron correctamente. En caso de que la bifurcación se haya predicho incorrectamente, el procesador continúa ejecutando instrucciones de ruta incorrecta hasta que llega a un punto independiente de la bifurcación, lo que potencialmente ejecuta cargas de ruta incorrecta que contaminan la caché con entradas de datos inútiles. Los resultados válidos de las instrucciones de bifurcación se pueden guardar para su uso posterior como predicciones altamente precisas durante el funcionamiento normal.
Dado que runahead es un estado especulativo, no se puede permitir que las instrucciones de almacenamiento modifiquen la memoria. Para comunicar los resultados del almacenamiento a las cargas dependientes, se puede utilizar una caché muy pequeña a la que solo acceden las cargas y los errores de runahead, llamada caché runahead . [5] Esta caché es funcionalmente similar a una caché normal, pero contiene bits INV para rastrear qué datos no son válidos. Los almacenes INV establecen el bit INV de su línea de caché de destino correspondiente, mientras que los almacenes válidos restablecen el bit INV de la línea de caché. Cualquier instrucción de carga runahead debe verificar tanto la caché real como la runahead. Si la carga impacta en la caché runahead, descartará el resultado de la caché real y usará los datos de la caché runahead, lo que potencialmente se volverá inválido si la línea de caché se marcó con un bit INV. Debido a que la caché runahead está separada de la jerarquía de memoria , no hay lugar para desalojar los datos antiguos. Por lo tanto, en caso de un conflicto de caché, los datos antiguos simplemente se eliminan de la caché. Tenga en cuenta que debido al tamaño limitado de la memoria caché de ejecución anticipada, no es posible realizar un seguimiento perfecto de los datos INV durante el modo de ejecución anticipada (ya que los datos INV pueden sobrescribirse con datos válidos en un conflicto de caché ). En la práctica, esto no es crucial, ya que se descartan todos los resultados calculados durante el modo de ejecución anticipada.
Al igual que con el inicio de un período de ejecución anticipada, cualquier evento puede, en principio, ser motivo de salida del período de ejecución anticipada. Sin embargo, en el caso de un período de ejecución anticipada iniciado por un error de caché, normalmente se sale de él una vez que se ha solucionado el error de caché.
Cuando el procesador sale del runahead, todas las instrucciones más recientes (incluidas las instrucciones que iniciaron el runahead) se eliminan y se eliminan del pipeline. A continuación, el archivo de registro arquitectónico se restaura desde el punto de control. A continuación, se copia una tabla de alias de registro (RAT) predeterminada en la RAT del frontend y del backend. Por último, el procesador se redirige a la dirección de la instrucción que inició el runahead. A continuación, el procesador reanuda la ejecución en modo normal.
El método más simple para realizar un punto de control del archivo de registro arquitectónico (ARF) es simplemente realizar una copia completa de todo el archivo de registro físico (PRF) (porque el PRF es un superconjunto del ARF) a un archivo de registro de punto de control (CRF) cuando el procesador ingresa al modo de ejecución anticipada. Cuando se sale del modo de ejecución anticipada, el procesador puede realizar una copia completa del CRF al PRF. Sin embargo, hay opciones más eficientes disponibles.
Una forma de eliminar las operaciones de copia es escribir tanto en la PRF como en la CRF durante el funcionamiento normal, pero solo en la PRF en modo de ejecución anticipada. Este enfoque puede eliminar la sobrecarga de puntos de control que de otro modo se produciría al iniciar la ejecución anticipada si se escriben en la CRF y la PRF en paralelo, pero aún requiere que el procesador restaure la PRF cuando se sale de la ejecución anticipada.
Dado que los únicos registros que necesitan puntos de control son los registros arquitectónicos, el CRF solo necesita contener tantos registros como registros arquitectónicos haya, según lo definido por la arquitectura del conjunto de instrucciones . Dado que los procesadores suelen contener muchos más registros físicos que registros arquitectónicos, esto reduce significativamente el tamaño del CRF.
Un enfoque aún más agresivo es confiar únicamente en las rutas de reenvío de operandos de la microarquitectura para proporcionar valores modificados durante el modo de ejecución anticipada. [ cita requerida ] Luego, se establece un "punto de control" en el archivo de registro al deshabilitar las escrituras en el archivo de registro durante la ejecución anticipada.
Si bien el runahead tiene como objetivo aumentar el rendimiento del procesador, el preprocesamiento de instrucciones cuando el procesador de otro modo habría estado inactivo disminuye la eficiencia energética del procesador debido a un aumento en el consumo de energía dinámico . Además, entrar y salir del runahead implica una sobrecarga de rendimiento, ya que la creación de puntos de control de registros y, en particular, el vaciado de la tubería pueden tardar muchos ciclos en completarse. Por lo tanto, no es aconsejable iniciar el runahead en cada oportunidad.
Algunas optimizaciones que mejoran la eficiencia energética del runahead son:
Se ha descubierto que Runahead mejora las tasas de errores leves en los procesadores como efecto secundario. Mientras un procesador está esperando una falla de caché, todo el estado del procesador es vulnerable a errores leves mientras la falla de caché está pendiente. Al continuar la ejecución, Runahead reduce involuntariamente la cantidad de tiempo en que el estado del procesador es vulnerable a errores leves, lo que reduce las tasas de errores leves. [10]