[PyVigo] Erlang: The Road to the JIT

José Juan Montes jjmontes en gmail.com
Vie Dic 18 21:20:44 CET 2020


Oh, cómo lamento habérmelo perdido.

Jose Juan Montes


El vie, 18 dic 2020 a las 18:57, Jesus Cea (<jcea en jcea.es>) escribió:

> 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 en jcea.es - https://www.jcea.es/    _/_/    _/_/  _/_/    _/_/  _/_/
> Twitter: @jcea                        _/_/    _/_/          _/_/_/_/_/
> jabber / xmpp:jcea en 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
>
> _______________________________________________
> Asociación Python España: https://www.es.python.org/
> Python Vigo: https://www.python-vigo.es/
> Vigo mailing list
> Vigo en lists.es.python.org
> https://lists.es.python.org/listinfo/vigo
>
------------ próxima parte ------------
Se ha borrado un adjunto en formato HTML...
URL: <https://lists.es.python.org/pipermail/vigo/attachments/20201218/37991d07/attachment.htm>


Más información sobre la lista de distribución Vigo