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                         _/_/      _/_/_/        _/_/_/
j...@jcea.es - https://www.jcea.es/    _/_/    _/_/  _/_/    _/_/  _/_/
Twitter: @jcea                        _/_/    _/_/          _/_/_/_/_/
jabber / xmpp:j...@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

Attachment: OpenPGP_signature
Description: OpenPGP digital signature

_______________________________________________
Python-es mailing list
Python-es@python.org
https://mail.python.org/mailman/listinfo/python-es

Responder a