- Tail Call: una llamada a función que se realiza justo antes de que la función retorne. Cuando ocurre la optimización de Tail Call, se usa la instrucción
jmp para reducir la pila de llamadas.
- Ventajas:
- Reduce el uso de memoria de la pila de O(n) a O(1).
- Elimina el overhead de rendimiento de las llamadas a función, por lo que puede usarse como una estructura eficiente de control iterativo.
Problemas del bucle de intérprete
- Problemas:
- A medida que la función crece y el flujo de control se vuelve más complejo, es más difícil mantener datos importantes en los registros.
- Si se mezclan la ruta rápida y la ruta lenta, la calidad del código se degrada.
Mejora del bucle de intérprete usando Tail Call
- Solución: usar Tail Call para separar cada tarea en funciones pequeñas, y que cada función invoque la siguiente tarea mediante Tail Call.
- Ventajas:
- Permite controlar la asignación de registros.
- Separa la ruta rápida y la ruta lenta para mantener la calidad del código.
- Hace posible optimizar secuencias de instrucciones independientes.
Limitaciones
- Problema cuando hay llamadas que no son Tail Call: si existen llamadas que no son Tail Call, se crean stack frames y los datos se guardan en la pila, lo que degrada el rendimiento.
- Manejo de excepciones complejo: cuando el manejo de excepciones es complejo, aumentan la duplicación de código y la complejidad.
- Problemas de portabilidad: como el atributo
musttail no es un estándar, no todos los compiladores lo soportan.
Resumen de GN⁺
- La optimización de Tail Call juega un papel importante en la mejora del rendimiento y muestra grandes resultados especialmente en el parsing de Protobuf.
- Esta técnica también puede aplicarse a intérpretes de lenguajes principales escritos en C (Python, Ruby, PHP, Lua, etc.).
- El problema de portabilidad del atributo
musttail sigue siendo un reto por resolver.
- Entre los proyectos con funcionalidades similares están el intérprete LuaJIT y wasm3 WebAssembly.
1 comentarios
Opiniones en Hacker News
La propuesta del estándar de C incluye llamadas de cola en la forma
return goto (expression);[[musttail]], esto garantiza la vida útil de los objetos locales y no requiere un análisis de escape amplioPara los entusiastas de Rust, hubo un RFC antiguo para agregar la palabra clave
becomeEn C++, la forma principal en que los intérpretes aceleran la ejecución es usando
gotocalculadogotocalculado o estilo de cola puede reducir la presión sobre el predictor de saltosEl problema de cambiar de contexto usando llamadas de cola requiere funciones que usen la convención de llamadas
Se espera que el atributo
[[musttail]]llegue a GCC, Visual C++ y otros compiladores populares[[musttail]]está en proceso de incorporarse a GCCAl mencionar el soporte en C++, se señala que en C++ casi no hay llamadas de cola
Se preguntan qué ocurre si una función
[[musttail]]de C++ lanza una excepciónSe menciona que los ejemplos simples no necesitan
__attribute__((musttail))para generar buen códigoSe preguntan qué tan rápido sería usar un trampolín para llamar en un bucle externo a un puntero de función que se devuelve
Hay una petición para aclarar un ejemplo de una ruta de excepción envuelta con
[[musttail]][[musttail]]evita la creación de marcos de pila y el volcado de registros