optimization - sirve - qué es el cot arba
¿Qué estrategias de despacho de código de operación se usan en intérpretes eficientes? (8)
¿Qué técnicas promueven un despacho de código de operación eficiente para hacer un intérprete rápido? ¿Hay algunas técnicas que solo funcionan bien en el hardware moderno y otras que ya no funcionan bien debido a los avances del hardware? ¿Qué compensaciones se deben hacer entre facilidad de implementación, velocidad y portabilidad?
Me complace que la implementación C de Python finalmente se está moviendo más allá de una simple implementación de switch (opcode) {...}
para el envío de código de operación a subprocesamiento indirecto como una opción de tiempo de compilación, pero estoy menos contento de que les tomó 20 años obtener ahí. Quizás si documentamos estas estrategias en stackoverflow, el siguiente idioma se acelerará más rápido.
Antes de comenzar, verifique a Lua .
Es pequeño (150 Kb), puro ANSI C, funciona en cualquier cosa que tenga el compilador de C. Muy rapido.
Y lo más importante: el código fuente es limpio y legible. Vale la pena echarle un vistazo.
Benchmarking es una buena técnica para hacer cualquier cosa rápida en plataforma (s). Pruebe, refine, pruebe de nuevo, mejore.
No creo que puedas obtener una mejor respuesta. Hay muchas técnicas para hacer intérpretes. Pero te doy un consejo, no hagas concesiones, solo elige lo que realmente necesitas y persigue esos objetivos.
El subproceso indirecto es una estrategia en la que cada implementación de código de operación tiene su propio JMP
para el siguiente código de operación. El parche para el intérprete de Python se ve así:
add:
result = a + b;
goto *opcode_targets[*next_instruction++];
opcode_targets
correlaciona la instrucción en el opcode_targets
del idioma con la ubicación en memoria de la implementación del código de operación. Esto es más rápido porque el predictor de bifurcación del procesador puede hacer una predicción diferente para cada bytecode, en contraste con una instrucción switch
que tiene solo una instrucción de bifurcación.
El compilador debe admitir goto calculado para que esto funcione, lo que significa principalmente gcc.
El enhebrado directo es similar, pero en el enhebrado directo, la matriz de códigos de operación se reemplaza con punteros a las implementaciones de código de operación de esta manera:
goto *next_opcode_target++;
Estas técnicas solo son útiles porque los procesadores modernos se canalizan y deben despejar sus tuberías (lento) en una rama mal predicha. Los diseñadores de procesadores introdujeron la predicción de bifurcación para evitar tener que borrar la canalización con tanta frecuencia, pero la predicción de bifurcación solo funciona para las sucursales que tienen más probabilidades de tomar una ruta particular.
La pregunta es un poco vaga. Pero, parece que estás preguntando por escribir un intérprete.
Los intérpretes suelen utilizar componentes de análisis tradicionales: lexer, analizador sintáctico y árbol de sintaxis abstracta (AST). Esto le permite al diseñador leer e interpretar la sintaxis válida y construir una estructura en árbol de comandos con operadores asociados, parámetros, etc.
Una vez en formato AST, toda la entrada se convierte en token y el intérprete puede comenzar a ejecutar atravesando el árbol.
Hay muchas opciones, pero recientemente utilicé ANTLR como un generador de analizadores que puede construir analizadores en varios idiomas de destino, incluyendo C / C ++ y C #.
Una gran victoria es almacenar el código fuente en una forma intermedia, en lugar de rehacer el análisis léxico y el análisis durante la ejecución.
Esto puede abarcar desde el almacenamiento de los tokens, pasando por el código de estilo Forth y hasta la compilación JIT.
La compilación justo a tiempo es una.
Hay una serie de documentos sobre diferentes tipos de despacho:
M. Anton Ertl y David Gregg, Optimizar la Precisión de Precisión de Ramas Indirectas en Intérpretes de Máquinas Virtuales , en las Actas de la Conferencia SIGPLAN 2003 de ACM sobre Diseño e Implementación de Lenguajes de Programación (PLDI 03), pp. 278-288, San Diego, California, junio de 2003 .
M. Anton Ertl y David Gregg, El comportamiento de los intérpretes de máquinas virtuales eficientes en arquitecturas modernas , en Actas de la 7ª Conferencia Europea de Computación en Paralelo (Europar 2001), pp. 403-412, LNCS 2150, Manchester, agosto de 2001.
Yunhe Shi proporciona un excelente resumen en su tesis de doctorado .
Además, alguien descubrió una nueva técnica hace unos años que es válida ANSI C.
Encontré una publicación de blog sobre la implementación del intérprete de subprocesos que fue útil.
El autor describe el enhebrado basado en etiquetas de GCC y también cómo hacerlo en Visual Studio utilizando el ensamblador en línea.
http://abepralle.wordpress.com/2009/01/25/how-not-to-make-a-virtual-machine-label-based-threading/
Los resultados son interesantes Informa que mejora el rendimiento al 33% cuando usa GCC, pero sorprendentemente la implementación de ensamblaje en línea de Visual Studio es 3 veces más lenta.