[Py-ES] Erlang: The Road to the JIT
Jesus Cea
jcea at jcea.es
Fri Dec 18 18:57:17 CET 2020
Ya sé que esto es Erlang, pero me parece un artículo interesante y
relevante para la tertulia del martes pasado y la discusión de por qué
CPYTHON no tiene JIT de serie.
https://blog.erlang.org/the-road-to-the-jit/
Tema "guardas" que comentaba en en la tertulia del martes. Las "guardas"
con comprobaciones que confirman invariantes para ejecutar código
optimizado. Por ejemplo, una invariante podría ser que un tipo concreto
sigue siendo un entero porque antes lo fue.
Ejemplo:
Sea el código:
"""
def suma(n):
s = 0
for i in range(n):
s += i
return s
"""
Python 3.9 compila este código al siguiente bytecode:
"""
>>> dis.dis(suma)
2 0 LOAD_CONST 1 (0)
2 STORE_FAST 1 (s)
3 4 LOAD_GLOBAL 0 (range)
6 LOAD_FAST 0 (n)
8 CALL_FUNCTION 1
10 GET_ITER
>> 12 FOR_ITER 12 (to 26)
14 STORE_FAST 2 (i)
4 16 LOAD_FAST 1 (s)
18 LOAD_FAST 2 (i)
20 INPLACE_ADD
22 STORE_FAST 1 (s)
24 JUMP_ABSOLUTE 12
5 >> 26 LOAD_FAST 1 (s)
28 RETURN_VALUE
"""
Aquí se podrían optimizar cosas como reconocer "range", pero
centrándonos en el cuerpo del bucle, se podría reconocer perfectamente
que tanto "s" como "i" son enteros y operar con ellos directamente como
tipos de datos en ensamblador.
Estudiando el código generado, se puede ver que es muy mejorable. Por
ejemplo, se podría mover la línea 16 a antes del bucle y eliminar las
líneas 22 y 26, manteniendo "s" en el stack en vez de guardarlo en una
variable para cargarlo inmediatamente después. De hecho se podría hasta
eliminar la actualización de "s" en memoria hasta el final del bucle.
También se podría prescindir de guardar el contador del bucle en la
variable "i", eliminando las líneas 14 y 18. ¡El cuerpo del bucle
pasaría de 5 instrucciones a una!. La única complejidad sería la gestión
de excepciones: Si la suma levanta una excepción, habría que reconstruir
las variables "i" y "s".
La guarda se podría poner en el INPLACE_ADD, pero haciendo inferencia de
tipos trivial se podría compilar a ensamblador todo el cuerpo del bucle,
y la guarda sería simplemente comprobar que ni "i" ni "s" se pasan de
32/64 bits, que sería el tipo básico en ensamblador. Mientras ni "i" ni
"s" se pasen de ese rango, se pueden manejar en registros de ensamblador
y hacer una conversión a tipos Python al terminar el bucle. Si te pasas
del rango, pues simplemente ejecutas el bytecode habitual, algo
transparente para el programa.
El intérprete de bytecode tiene el siguiente fragmento para ejecutar
"INPLACE_ADD":
"""
case TARGET(INPLACE_ADD): {
PyObject *right = POP();
PyObject *left = TOP();
PyObject *sum;
if (PyUnicode_CheckExact(left) &&
PyUnicode_CheckExact(right)) {
sum = unicode_concatenate(tstate, left, right, f,
next_instr);
/* unicode_concatenate consumed the ref to left */
}
else {
sum = PyNumber_InPlaceAdd(left, right);
Py_DECREF(left);
}
Py_DECREF(right);
SET_TOP(sum);
if (sum == NULL)
goto error;
DISPATCH();
}
"""
Se ve una optimización cuando los operandos son unicode, pero en el caso
de números el código es más complejo.
El problema fundamental de Python es que técnicamente podrías capturar
el "traceback" de otro hilo y examinar sus tipos locales, pero una
solución evidente sería retrasar esa captura hasta que se llega al final
del cuerpo del bucle (no al final del bucle, si no del cuerpo del
bucle). Otro problema es la gestión de excepciones, que habría que
reconstruir el traceback y los valores de variables "optimizadas". Por
lo que sé, los JIT actuales de Python como NUMBA simplemente obvian este
problema, normalmente suponiendo que no hay excepciones.
--
Jesús Cea Avión _/_/ _/_/_/ _/_/_/
jcea at jcea.es - https://www.jcea.es/ _/_/ _/_/ _/_/ _/_/ _/_/
Twitter: @jcea _/_/ _/_/ _/_/_/_/_/
jabber / xmpp:jcea at jabber.org _/_/ _/_/ _/_/ _/_/ _/_/
"Things are not so easy" _/_/ _/_/ _/_/ _/_/ _/_/ _/_/
"My name is Dump, Core Dump" _/_/_/ _/_/_/ _/_/ _/_/
"El amor es poner tu felicidad en la felicidad de otro" - Leibniz
-------------- next part --------------
A non-text attachment was scrubbed...
Name: OpenPGP_signature
Type: application/pgp-signature
Size: 495 bytes
Desc: OpenPGP digital signature
URL: <https://lists.es.python.org/pipermail/general/attachments/20201218/c175996b/attachment.bin>
More information about the general
mailing list