Suponiendo que las solicitudes de caché l1 y l2 resultan en una falla, ¿se detiene el procesador hasta que se haya accedido a la memoria principal?
Escuché sobre la idea de cambiar a otro hilo, si es así, ¿qué se usa para despertar el hilo estancado?
computer-architecture
cpu-cache
cpu-pipelines
102948239408
fuente
fuente
Respuestas:
La latencia de la memoria es uno de los problemas fundamentales estudiados en la investigación de arquitectura de computadoras.
Ejecución especulativa
La ejecución especulativa con un problema de instrucción fuera de orden a menudo es capaz de encontrar trabajo útil para completar la latencia durante un hit de caché L1, pero generalmente se queda sin trabajo útil después de 10 o 20 ciclos más o menos. Ha habido varios intentos de aumentar la cantidad de trabajo que se puede hacer durante una falta de latencia larga. Una idea era intentar hacer predicciones de valor (Lipasti, Wilkerson y Shen, (ASPLOS-VII): 138-147, 1996). Esta idea estuvo muy de moda en los círculos de investigación de arquitectura académica durante un tiempo, pero parece no funcionar en la práctica. Un último intento de salvar la predicción del valor del basurero de la historia fue la ejecución runahead(Mutlu, Stark, Wilkerson y Patt (HPCA-9): 129, 2003). En la ejecución de runahead, reconoce que sus predicciones de valor van a estar equivocadas, pero ejecute de forma especulativa de todos modos y luego descarte todo el trabajo basado en la predicción, en la teoría de que al menos comenzará algunas captaciones previas para lo que de otro modo sería caché L2 echa de menos Resulta que el runahead desperdicia tanta energía que simplemente no vale la pena.
Un enfoque final en este sentido, que puede estar obteniendo cierta tracción en la industria, implica crear buffers de pedidos enormemente largos. Las instrucciones se ejecutan especulativamente en función de la predicción de rama, pero no se realiza ninguna predicción de valor. En cambio, todas las instrucciones que dependen de una carga de latencia larga omiten sentarse y esperar en el búfer de reordenamiento. Pero dado que el búfer de reordenamiento es tan grande que puede seguir buscando instrucciones si el predictor de bifurcación está haciendo un trabajo decente, a veces podrá encontrar trabajo útil mucho más tarde en la secuencia de instrucciones. Un artículo de investigación influyente en esta área fueron las tuberías de flujo continuo(Srinivasan, Rajwar, Akkary, Gandhi y Upton (ASPLOS-XI): 107-119, 2004). (A pesar del hecho de que todos los autores son de Intel, creo que la idea obtuvo más tracción en AMD).
Multihilo
El uso de múltiples subprocesos para la tolerancia de latencia tiene una historia mucho más larga, con un éxito mucho mayor en la industria. Todas las versiones exitosas utilizan soporte de hardware para subprocesos múltiples. La versión más simple (y más exitosa) de esto es lo que a menudo se llama FGMT (multihilo de grano fino ) o multihilo intercalado . Cada núcleo de hardware admite contextos de subprocesos múltiples (un contexto es esencialmente el estado del registro, incluidos los registros como el puntero de instrucción y cualquier registro de banderas implícito). En un procesador multihilo de grano fino, cada hilo se procesa en-orden. El procesador realiza un seguimiento de qué subprocesos están detenidos en un error de carga de latencia larga y cuáles están listos para su próxima instrucción y utiliza una estrategia de programación FIFO simple en cada ciclo para elegir qué subproceso listo para ejecutar ese ciclo. Un primer ejemplo de esto a gran escala fueron los procesadores HEP de Burton Smith (Burton Smith diseñó la supercomputadora Tera, que también era un procesador multihilo de grano fino). Pero la idea va mucho más atrás, en la década de 1960, creo.
FGMT es particularmente efectivo en las cargas de trabajo de transmisión. Todas las GPU modernas (unidades de procesamiento de gráficos) son multinúcleo donde cada núcleo es FGMT, y el concepto también se usa ampliamente en otros dominios informáticos. El T1 de Sun también era FMGT multinúcleo, y también lo es el Xeon Phi de Intel (el procesador que a menudo todavía se llama "MIC" y solía llamarse "Larabee").
La idea de subprocesamiento múltiple simultáneo (Tullsen, Eggers y Levy, (ISCA-22): 392-403, 1995) combina el subprocesamiento múltiple de hardware con la ejecución especulativa. El procesador tiene múltiples contextos de subprocesos, pero cada subproceso se ejecuta de forma especulativa y fuera de orden. Un programador más sofisticado puede usar varias heurísticas para obtener el hilo que probablemente tenga un trabajo útil ( Malik, Agarwal, Dhar y Frank, (HPCA-14: 50-61), 2008 ). Cierta gran compañía de semiconductores comenzó a usar el término hyperthreading para multithreading simultáneo, y ese nombre parece ser el más utilizado en estos días.
Problemas de microarquitectura de bajo nivel
Después de releer sus comentarios, me di cuenta de que también está interesado en la señalización que se produce entre el procesador y la memoria. Los cachés modernos generalmente permiten que múltiples fallas se destaquen simultáneamente. Esto se llama caché sin bloqueo (Kroft, (ISCA-8): 81-87, 1981). (Pero el documento es difícil de encontrar en línea, y algo difícil de leer. Respuesta breve: hay mucha contabilidad, pero solo hay que lidiar con ella. La estructura de contabilidad de hardware se llama MSHR (registro de retención de información / estado de falta) ), que es el nombre que Kroft le dio en su artículo de 1981).
fuente
La respuesta corta es: nada, el procesador se detiene.
No hay tantas posibilidades. Cambiar a una tarea diferente no es realmente una opción por dos razones. Esa es una operación costosa, y dado que la tarea actual y otras tareas compiten por el espacio en el caché, cambiar a la otra tarea puede requerir un acceso a la memoria principal, y también puede volver a la tarea original. Además, esto tendría que involucrar al sistema operativo, por lo que el procesador tendría que activar algún tipo de interrupción o trampa ; de hecho, el procesador estaría cambiando a algún código del núcleo.
Mientras el procesador está parado, el temporizador continúa funcionando, por lo que podría haber una interrupción del temporizador o podría haber una interrupción de otros periféricos. Por lo tanto, es más probable que ocurra un cambio de contexto durante un acceso a la memoria principal que durante un acceso a la memoria caché, pero solo porque lleva más tiempo.
No obstante, las computadoras modernas sí incluyen una variedad de técnicas para tratar de reducir el tiempo perdido en el procesador esperando la memoria principal. El estancamiento ocurre, pero solo cuando no se puede evitar.
Una técnica son las recuperaciones especulativas : el procesador intenta adivinar a qué ubicación de memoria se accederá y la recupera en caché antes de tiempo. Por ejemplo, los bucles sobre un bloque de memoria son comunes, por lo que si se han cargado líneas de caché para las direcciones de memoria 0x12340000, 0x12340010 y 0x12340020, puede ser una buena idea cargar la línea para 0x12340030. El compilador puede ayudar generando instrucciones de captación previa que son como cargas, excepto que solo transfieren datos de la memoria principal al caché, no a un registro del procesador.
Otra técnica es la ejecución especulativa . El procesador comienza a ejecutar la siguiente instrucción antes de realizar la carga. Esto sucede naturalmente de todos modos debido a la canalización de instrucciones. Solo las instrucciones que no dependen del valor cargado se pueden ejecutar de esta manera: el procesador debe realizar un análisis de dependencia. Para instrucciones condicionales (por ejemplo, carga r1; bifurcación si r1 ≠ 0), los procesadores emplean heurísticas de predicción de bifurcación para adivinar cuál será el valor. La ejecución especulativa después de una carga puede necesitar ser rebobinada en caso de que la carga desencadene un aborto.
Algunas arquitecturas como Itanium facilitan la ejecución de instrucciones en un orden conveniente al permitir el reordenamiento de instrucciones por defecto: en lugar de consistir en una secuencia de instrucciones elementales que se ejecutan semánticamente una tras otra, los programas consisten en palabras de instrucción muy largas : una sola instrucción incluye muchas operaciones que deben ser ejecutadas en paralelo por diferentes componentes del procesador.
El cambio a otro subproceso ocurre en hyperthreading , que se encuentra en procesadores x86 de gama alta. Esta es una técnica de diseño de hardware: cada núcleo de procesador contiene dos bancos de registros separados (cada uno correspondiente a un contexto de tarea), pero una sola instancia de otros elementos, de modo que puede admitir dos subprocesos de ejecución independientes, pero solo ejecuta de manera efectiva las instrucciones de uno a un momento. Mientras un hilo está parado, el otro hilo continúa. Desde el punto de vista del software, hay dos procesadores independientes; Simplemente sucede que esos procesadores comparten muchos componentes debajo del capó.
El intercambio es un nivel más en la jerarquía de memoria caché: la memoria principal puede verse como una memoria caché para el espacio de intercambio. Con el intercambio, los mecanismos y las relaciones de rendimiento son diferentes. Si una tarea necesita que se carguen datos del intercambio, la instrucción de carga activa una trampa que ejecuta el código del núcleo para asignar una página en la RAM y cargar su contenido desde el disco. Mientras esto sucede, el núcleo puede decidir cambiar a otra tarea.
fuente
La respuesta a esta pregunta variará con la arquitectura en cuestión. Si bien muchas CPU se detendrán (ARM, x86 sin hyperthreading, etc.) porque les lleva demasiado tiempo cambiar los hilos, ese no es el enfoque adoptado por cada arquitectura. En algunas arquitecturas, cada subproceso programado en una CPU tiene su propio archivo de registro independiente, por lo que el procesador simplemente puede ejecutar el trabajo desde un subproceso que no está esperando un acceso a la memoria. Tengo entendido que esto es, hasta cierto punto, lo que hace x86 hyperthreading (usando solo 2 hilos), pero es mucho más común en GPGPUarquitecturas En el caso particular de CUDA, al menos docenas, si no cientos, de urdimbres de hilos generalmente se cargan en un multiprocesador dado en un momento dado, con cada hilo (cientos o miles de ellos) tienen sus propios registros. Esto permite que la arquitectura ejecute una instrucción desde otro subproceso en el siguiente ciclo cuando un subproceso determinado emite un acceso a la memoria. Por lo tanto, siempre que se carguen suficientes subprocesos, los núcleos del procesador nunca estarán inactivos para acceder a la memoria. Consulte las Pautas de rendimiento y la Jerarquía de memoria para obtener más información.
fuente