<div dir="ltr">Oh, cómo lamento habérmelo perdido.<div><br clear="all"><div><div dir="ltr" class="gmail_signature" data-smartmail="gmail_signature">Jose Juan Montes</div></div><br></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">El vie, 18 dic 2020 a las 18:57, Jesus Cea (<<a href="mailto:jcea@jcea.es">jcea@jcea.es</a>>) escribió:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Ya sé que esto es Erlang, pero me parece un artículo interesante y <br>
relevante para la tertulia del martes pasado y la discusión de por qué <br>
CPYTHON no tiene JIT de serie.<br>
<br>
<a href="https://blog.erlang.org/the-road-to-the-jit/" rel="noreferrer" target="_blank">https://blog.erlang.org/the-road-to-the-jit/</a><br>
<br>
Tema "guardas" que comentaba en en la tertulia del martes. Las "guardas" <br>
con comprobaciones que confirman invariantes para ejecutar código <br>
optimizado. Por ejemplo, una invariante podría ser que un tipo concreto <br>
sigue siendo un entero porque antes lo fue.<br>
<br>
Ejemplo:<br>
<br>
Sea el código:<br>
<br>
"""<br>
def suma(n):<br>
     s = 0<br>
     for i in range(n):<br>
         s += i<br>
     return s<br>
"""<br>
<br>
Python 3.9 compila este código al siguiente bytecode:<br>
<br>
"""<br>
 >>> dis.dis(suma)<br>
   2           0 LOAD_CONST               1 (0)<br>
               2 STORE_FAST               1 (s)<br>
<br>
   3           4 LOAD_GLOBAL              0 (range)<br>
               6 LOAD_FAST                0 (n)<br>
               8 CALL_FUNCTION            1<br>
              10 GET_ITER<br>
         >>   12 FOR_ITER                12 (to 26)<br>
              14 STORE_FAST               2 (i)<br>
<br>
   4          16 LOAD_FAST                1 (s)<br>
              18 LOAD_FAST                2 (i)<br>
              20 INPLACE_ADD<br>
              22 STORE_FAST               1 (s)<br>
              24 JUMP_ABSOLUTE           12<br>
<br>
   5     >>   26 LOAD_FAST                1 (s)<br>
              28 RETURN_VALUE<br>
"""<br>
<br>
Aquí se podrían optimizar cosas como reconocer "range", pero <br>
centrándonos en el cuerpo del bucle, se podría reconocer perfectamente <br>
que tanto "s" como "i" son enteros y operar con ellos directamente como <br>
tipos de datos en ensamblador.<br>
<br>
Estudiando el código generado, se puede ver que es muy mejorable. Por <br>
ejemplo, se podría mover la línea 16 a antes del bucle y eliminar las <br>
líneas 22 y 26, manteniendo "s" en el stack en vez de guardarlo en una <br>
variable para cargarlo inmediatamente después. De hecho se podría hasta <br>
eliminar la actualización de "s" en memoria hasta el final del bucle. <br>
También se podría prescindir de guardar el contador del bucle en la <br>
variable "i", eliminando las líneas 14 y 18. ¡El cuerpo del bucle <br>
pasaría de 5 instrucciones a una!. La única complejidad sería la gestión <br>
de excepciones: Si la suma levanta una excepción, habría que reconstruir <br>
las variables "i" y "s".<br>
<br>
La guarda se podría poner en el INPLACE_ADD, pero haciendo inferencia de <br>
tipos trivial se podría compilar a ensamblador todo el cuerpo del bucle, <br>
y la guarda sería simplemente comprobar que ni "i" ni "s" se pasan de <br>
32/64 bits, que sería el tipo básico en ensamblador. Mientras ni "i" ni <br>
"s" se pasen de ese rango, se pueden manejar en registros de ensamblador <br>
y hacer una conversión a tipos Python al terminar el bucle. Si te pasas <br>
del rango, pues simplemente ejecutas el bytecode habitual, algo <br>
transparente para el programa.<br>
<br>
El intérprete de bytecode tiene el siguiente fragmento para ejecutar <br>
"INPLACE_ADD":<br>
<br>
"""<br>
case TARGET(INPLACE_ADD): {<br>
             PyObject *right = POP();<br>
             PyObject *left = TOP();<br>
             PyObject *sum;<br>
             if (PyUnicode_CheckExact(left) && <br>
PyUnicode_CheckExact(right)) {<br>
                 sum = unicode_concatenate(tstate, left, right, f, <br>
next_instr);<br>
                 /* unicode_concatenate consumed the ref to left */<br>
             }<br>
             else {<br>
                 sum = PyNumber_InPlaceAdd(left, right);<br>
                 Py_DECREF(left);<br>
             }<br>
             Py_DECREF(right);<br>
             SET_TOP(sum);<br>
             if (sum == NULL)<br>
                 goto error;<br>
             DISPATCH();<br>
         }<br>
"""<br>
<br>
Se ve una optimización cuando los operandos son unicode, pero en el caso <br>
de números el código es más complejo.<br>
<br>
El problema fundamental de Python es que técnicamente podrías capturar <br>
el "traceback" de otro hilo y examinar sus tipos locales, pero una <br>
solución evidente sería retrasar esa captura hasta que se llega al final <br>
del cuerpo del bucle (no al final del bucle, si no del cuerpo del <br>
bucle). Otro problema es la gestión de excepciones, que habría que <br>
reconstruir el traceback y los valores de variables "optimizadas". Por <br>
lo que sé, los JIT actuales de Python como NUMBA simplemente obvian este <br>
problema, normalmente suponiendo que no hay excepciones.<br>
<br>
-- <br>
Jesús Cea Avión                         _/_/      _/_/_/        _/_/_/<br>
<a href="mailto:jcea@jcea.es" target="_blank">jcea@jcea.es</a> - <a href="https://www.jcea.es/" rel="noreferrer" target="_blank">https://www.jcea.es/</a>    _/_/    _/_/  _/_/    _/_/  _/_/<br>
Twitter: @jcea                        _/_/    _/_/          _/_/_/_/_/<br>
jabber / <a href="mailto:xmpp%3Ajcea@jabber.org" target="_blank">xmpp:jcea@jabber.org</a>  _/_/  _/_/    _/_/          _/_/  _/_/<br>
"Things are not so easy"      _/_/  _/_/    _/_/  _/_/    _/_/  _/_/<br>
"My name is Dump, Core Dump"   _/_/_/        _/_/_/      _/_/  _/_/<br>
"El amor es poner tu felicidad en la felicidad de otro" - Leibniz<br>
<br>
_______________________________________________<br>
Asociación Python España: <a href="https://www.es.python.org/" rel="noreferrer" target="_blank">https://www.es.python.org/</a><br>
Python Vigo: <a href="https://www.python-vigo.es/" rel="noreferrer" target="_blank">https://www.python-vigo.es/</a><br>
Vigo mailing list<br>
<a href="mailto:Vigo@lists.es.python.org" target="_blank">Vigo@lists.es.python.org</a><br>
<a href="https://lists.es.python.org/listinfo/vigo" rel="noreferrer" target="_blank">https://lists.es.python.org/listinfo/vigo</a><br>
</blockquote></div>