cpu - una - taxonomia de shore
¿Cómo ha afectado la evolución de la arquitectura de la CPU al rendimiento de las llamadas de la función virtual? (1)
El procesador AMD en la era de los primeros gigahercios tenía una penalización de 40 ciclos cada vez que llamabas a una función
Huh ... tan grande ..
Existe un método de "Predicción de rama indirecta", que ayuda a predecir el salto de la función virtual, SI hubo un salto indirecto hace algún tiempo. Todavía hay una penalización por primera y virtualmente mal predicha. función de salto.
El soporte varía desde el simple "pronosticado a la derecha si y solo si la rama indirecta anterior era exactamente igual" a las entradas muy complejas de dos o diez niveles con detección de alternancia periódica de 2-3 direcciones de destino para una sola instrucción jmp indirecta.
Hubo mucha evolución aquí ...
http://arstechnica.com/hardware/news/2006/04/core.ars/7
Presentado por primera vez con el Pentium M: ... predictor de rama indirecta.
El predictor indirecto de rama.
Debido a que las ramas indirectas cargan sus objetivos de sucursales desde un registro, en lugar de tenerlos inmediatamente disponibles como es el caso de las sucursales directas, son notoriamente difíciles de predecir. El predictor de rama indirecta del núcleo es una tabla que almacena información de historial sobre las direcciones de destino preferidas de cada rama indirecta con la que se encuentra el extremo frontal. Por lo tanto, cuando el front-end encuentra una rama indirecta y la predice como tomada, puede pedirle al predictor de rama indirecta que la dirija a la dirección en el BTB que la rama probablemente querrá.
http://www.realworldtech.com/page.cfm?ArticleID=rwt051607033728&p=3
La predicción indirecta de rama se introdujo por primera vez con la microarquitectura Prescott de Intel y más tarde el Pentium M.
entre el 16 y el 50% de todas las predicciones erróneas de las sucursales fueron indirectas (29% en promedio). El valor real de la predicción errónea de rama indirecta es para muchos de los scripts más nuevos o lenguajes de alto nivel, como Ruby, Perl o Python, que utilizan intérpretes. Otros culpables comunes indirectos comunes incluyen funciones virtuales (usadas en C ++) y llamadas a punteros de función.
http://www.realworldtech.com/page.cfm?ArticleID=RWT102808015436&p=5
AMD ha adoptado algunas de estas mejoras; por ejemplo, la adición de matrices de predicción indirecta en Barcelona y procesadores posteriores. Sin embargo, el K8 tiene predictores de ramificación más antiguos y menos precisos que el Core 2.
http://www.agner.org/optimize/microarchitecture.pdf
3.12 Saltos indirectos en procesadores antiguos Los saltos indirectos, las llamadas indirectas y las devoluciones pueden ir a una dirección diferente cada vez. El método de predicción para un salto indirecto o una llamada indirecta es, en procesadores más antiguos que PM y K10, simplemente para predecir que irá al mismo objetivo que la última vez que se ejecutó.
y el mismo pdf, pagina 14
Predicción de salto indirecto Un salto o llamada indirecta es una instrucción de transferencia de control que tiene más de dos objetivos posibles. Un programa C ++ puede generar un salto o llamada indirecta con ... una función virtual. Un salto o llamada indirecta se genera en ensamblaje especificando un registro o una variable de memoria o una matriz indexada como destino de una instrucción de salto o llamada. Muchos procesadores hacen solo una entrada BTB para un salto o llamada indirecta. Esto significa que siempre se predecirá que irá al mismo objetivo que la última vez. A medida que la programación orientada a objetos con clases polimorfas se ha vuelto más común, existe una creciente necesidad de predecir llamadas indirectas con múltiples objetivos. Esto se puede hacer asignando una nueva entrada BTB para cada nuevo destino de salto que se encuentre. El búfer de historial y la tabla de historial de patrones deben tener espacio para más de un bit de información por cada incidente de salto para poder distinguir más de dos posibles objetivos. El PM es el primer procesador x86 en implementar este método. La regla de predicción en p. 12 todavía se aplica con la modificación de que el período máximo teórico que se puede predecir perfectamente es mn, donde m es el número de objetivos diferentes por salto indirecto, porque hay mn posibles subsecuencias de n longitud diferentes. Sin embargo, este máximo teórico no se puede alcanzar si excede el tamaño de la tabla BTB o del historial de patrones.
El manual de Agner tiene una descripción más larga del predictor de ramificación en muchas CPU modernas y la evolución del predictor en el procesador de cada fabricante (x86 / x86_64).
También muchos métodos teóricos de "predicción de rama indirecta" (busque en Google scholar); incluso wiki dijo algunas palabras al respecto http://en.wikipedia.org/wiki/Branch_predictor#Prediction_of_indirect_jumps /
Para los átomos del micro de Agner:
Predicción de ramas indirectas El Atom no tiene patrón de predicción para ramas indirectas según mis pruebas. Se predice que las ramas indirectas irán al mismo objetivo que la última vez.
Entonces, para la potencia baja, la predicción indirecta de ramificación no es tan avanzada. Así lo hace Via Nano:
Se prevé que los saltos indirectos vayan al mismo objetivo que la última vez.
Creo que la tubería más corta de x86 de baja potencia tiene una penalización más baja, 7-20 tics.
Hace años estaba aprendiendo sobre el ensamblador x86, la segmentación de la CPU, las fallas de caché, la predicción de ramificaciones y todo ese jazz.
Fue un cuento de dos mitades. Leí acerca de todas las maravillosas ventajas de las largas tuberías en la reordenación de instrucciones del procesador, la precarga de caché, el intercalado de dependencias, etc.
El inconveniente era que cualquier desviación de la norma era enormemente costosa. Por ejemplo, IIRC, un cierto procesador AMD en la era de los primeros gigahercios tenía una penalización de 40 ciclos cada vez que se activaba una función mediante un puntero (!) Y esto aparentemente era normal.
¡Este no es un número despreciable de "no te preocupes"! Tenga en cuenta que "buen diseño" normalmente significa "factor sus funciones tanto como sea posible" y "codificar semántica en los tipos de datos" que a menudo implica interfaces virtuales.
La compensación es que el código que no realiza tales operaciones puede obtener más de dos instrucciones por ciclo. Estos son números de los que uno quiere preocuparse al escribir código C ++ de alto rendimiento que es pesado en el diseño del objeto y ligero en el procesamiento de números.
Entiendo que la tendencia a largo plazo de CPU-pipeline se ha invertido a medida que entramos en la era de bajo consumo. Aquí está mi pregunta:
¿La última generación de procesadores compatibles con x86 sigue sufriendo multas por llamadas a funciones virtuales, malas predicciones de sucursales, etc.?