Python 3.10 en macOS 12 (2)

En la primera parte de esta serie de entradas, describí genéricamente el proceso standard a seguir en la compilación del código fuente del intérprete de Python. Inicialmente no prentendí que fuera más de una entrada pero su extensión me hizo reconsiderar el punto. Termino ese post con algunas cosas más.

Creo que el principal interés al llevar a cabo la compilación del intérprete de Python desde sus programas fuente es el poder tener algo especialmente optimizado o personalizado. Sobre esto hay un par de cosas que resaltar.

La primera y más simple, es el hecho de poder constatar que la optimización (o en todo caso la compilación en nuestro equipos) nos proporciona una cierta ventaja (en otras palabras, el que el performance del intérprete sea mayor). Para esto no se requiere tener que establecer todo un entorno de experimentación, mientras sea para una evaluación meramente local y personal el siguiente criterio debe funcionar.

Veamos primero, cómo es que se comporta el intérprete en lo que sería una compilación standard. Recordando los pasos del post previo (obsérvese que para propósitos de esta prueba, no se lleva a cabo la instalación de los productos de la compilación, i.e. se omite el make install). Así, se lleva a cabo la compilación de los programas fuente sin explícitamente indicar optimizaciones (parto de que el ambiente de trabajo ya se encuentra «sucio» por las actividades del post anterior, si no es el caso omitir el make clean):

$ make clean
$ ./configure
$ make
$ make test

siendo los resultados:

...
0:01:16 load avg: 3.88 [421/427] test_queue passed -- running: test_multiprocessing_forkserver (49.9 sec), test_concurrent_futures (44.6 sec)
0:01:18 load avg: 3.88 [422/427] test_timeout passed -- running: test_multiprocessing_forkserver (52.5 sec), test_multiprocessing_spawn (32.1 sec), test_concurrent_futures (47.2 sec)
0:01:31 load avg: 3.37 [423/427] test_logging passed -- running: test_multiprocessing_forkserver (1 min 5 sec), test_signal (31.3 sec), test_multiprocessing_spawn (45.0 sec), test_concurrent_futures (1 min)
0:01:34 load avg: 3.37 [424/427] test_multiprocessing_forkserver passed (1 min 7 sec) -- running: test_signal (33.9 sec), test_multiprocessing_spawn (47.6 sec), test_concurrent_futures (1 min 2 sec)
0:01:43 load avg: 3.08 [425/427] test_signal passed (43.6 sec) -- running: test_multiprocessing_spawn (57.4 sec), test_concurrent_futures (1 min 12 sec)
0:02:04 load avg: 2.97 [426/427] test_multiprocessing_spawn passed (1 min 17 sec) -- running: test_concurrent_futures (1 min 32 sec)
0:02:34 load avg: 5.36 running: test_concurrent_futures (2 min 2 sec)
0:02:53 load avg: 4.26 [427/427] test_concurrent_futures passed (2 min 21 sec)

== Tests result: SUCCESS ==

406 tests OK.

21 tests skipped:
    test_dbm_gnu test_devpoll test_epoll test_gdb test_ioctl test_lzma
    test_msilib test_multiprocessing_fork test_ossaudiodev
    test_smtpnet test_spwd test_ssl test_startfile test_tix test_tk
    test_ttk_guionly test_winconsoleio test_winreg test_winsound
    test_zipfile64 test_zoneinfo

Total duration: 2 min 53 sec
Tests result: SUCCESS
$ 

Ahora, llevando nuevamente estos pasos pero indicando el hacer uso de algunas optimizaciones:

$ make clean
$ ./configure --enable-optimizations $ make $ make test

obtenemos los siguientes resultados (se ha recortado la salida):

...
0:01:07 load avg: 4.24 [421/427] test_signal passed (43.4 sec) -- running: test_multiprocessing_forkserver (1 min 4 sec)
0:01:10 load avg: 4.06 [422/427] test_multiprocessing_forkserver passed (1 min 7 sec)
0:01:18 load avg: 4.21 [423/427] test_subprocess passed -- running: test_multiprocessing_spawn (34.1 sec), test_concurrent_futures (31.4 sec), test_io (31.0 sec)
/Users/lalo/Downloads/Python-3.10.0/Lib/subprocess.py:1067: ResourceWarning: subprocess 84447 is still running
  _warn("subprocess %s is still running" % self.pid,
ResourceWarning: Enable tracemalloc to get the object allocation traceback
0:01:21 load avg: 3.96 [424/427] test_io passed (34.2 sec) -- running: test_multiprocessing_spawn (37.4 sec), test_concurrent_futures (34.7 sec)0:01:21 load avg: 3.96 [425/427] test_xmlrpc passed -- running: test_multiprocessing_spawn (37.5 sec), test_concurrent_futures (34.8 sec)
0:01:51 load avg: 2.92 running: test_multiprocessing_spawn (1 min 7 sec), test_concurrent_futures (1 min 4 sec)
0:01:59 load avg: 2.76 [426/427] test_multiprocessing_spawn passed (1 min 14 sec) -- running: test_concurrent_futures (1 min 12 sec)
0:02:29 load avg: 2.15 running: test_concurrent_futures (1 min 42 sec)
0:02:59 load avg: 2.19 running: test_concurrent_futures (2 min 12 sec)
0:03:08 load avg: 2.25 [427/427] test_concurrent_futures passed (2 min 21 sec)

== Tests result: SUCCESS ==

406 tests OK.

21 tests skipped:
    test_dbm_gnu test_devpoll test_epoll test_gdb test_ioctl test_lzma
    test_msilib test_multiprocessing_fork test_ossaudiodev
    test_smtpnet test_spwd test_ssl test_startfile test_tix test_tk
    test_ttk_guionly test_winconsoleio test_winreg test_winsound
    test_zipfile64 test_zoneinfo

Total duration: 3 min 8 sec
Tests result: SUCCESS
$

Contrariamente a lo que uno esperaría, las pruebas de la compilación con la bandera para habilitar los procesos de optimización tomaron más tiempo (15 segundos más, que es toda una eternidad para un procesador que se mueve en el reino de los nano segundos). ¿Quiere decir esto que la optimización nos construye al final un intérprete más lento? No necesariamente, si uno observa el listado de las pruebas ejecutadas se observarán diferencias a cuando se procede a hacer uso de algunas optimizaciones.

Otra opción de optimización disponible es --with-lto, con ésta:

$ ./configure --enable-optimizations --with-lto
$ make test
 CC='gcc' LDSHARED='gcc -bundle -undefined dynamic_lookup   -fno-semantic-interposition -flto -Wl,-export_dynamic -g ' OPT='-DNDEBUG -g -fwrapv -O3 -Wall' 	_TCLTK_INCLUDES='' _TCLTK_LIBS='' 	./python.exe -E ./setup.py  build
running build
running build_ext
...
running build_scripts
copying and adjusting /Users/lalo/Downloads/Python-3.10.0/Tools/scripts/pydoc3 -> build/scripts-3.10
copying and adjusting /Users/lalo/Downloads/Python-3.10.0/Tools/scripts/idle3 -> build/scripts-3.10
copying and adjusting /Users/lalo/Downloads/Python-3.10.0/Tools/scripts/2to3 -> build/scripts-3.10
changing mode of build/scripts-3.10/pydoc3 from 644 to 755
changing mode of build/scripts-3.10/idle3 from 644 to 755
changing mode of build/scripts-3.10/2to3 from 644 to 755
renaming build/scripts-3.10/pydoc3 to build/scripts-3.10/pydoc3.10
renaming build/scripts-3.10/idle3 to build/scripts-3.10/idle3.10
renaming build/scripts-3.10/2to3 to build/scripts-3.10/2to3-3.10
./python.exe -E -c 'import sys ; from sysconfig import get_platform ; print("%s-%d.%d" % (get_platform(), *sys.version_info[:2]))' >platform
./python.exe  ./Tools/scripts/run_tests.py 
/Users/lalo/Downloads/Python-3.10.0/python.exe -u -W default -bb -E -m test -r -w -j 0 -u all,-largefile,-audio,-gui
== CPython 3.10.0+ERA.003 (default, Dec 10 2021, 17:53:11) [Clang 13.0.0 (clang-1300.0.29.3)] :: Eduardo Rodriguez Avila's build ::
== macOS-12.0.1-arm64-arm-64bit little-endian
== cwd: /Users/lalo/Downloads/Python-3.10.0/build/test_python_70140æ
== CPU count: 8
== encodings: locale=UTF-8, FS=utf-8
Using random seed 2477546
0:00:00 load avg: 1.97 Run tests in parallel using 10 child processes
0:00:00 load avg: 1.97 [  1/427] test_ttk_guionly skipped (resource denied)
test_ttk_guionly skipped -- Use of the 'gui' resource not enabled
0:00:00 load avg: 1.97 [  2/427] test_netrc passed
0:00:00 load avg: 1.97 [  3/427] test_extcall passed
0:00:00 load avg: 1.97 [  4/427] test_osx_env passed
0:00:00 load avg: 1.97 [  5/427] test_strptime passed
...
0:01:35 load avg: 3.50 [425/427] test_multiprocessing_forkserver passed (1 min 6 sec) -- running: test_concurrent_futures (1 min 35 sec), test_multiprocessing_spawn (30.7 sec)
0:02:05 load avg: 2.54 running: test_concurrent_futures (2 min 5 sec), test_multiprocessing_spawn (1 min)
0:02:19 load avg: 2.15 [426/427] test_multiprocessing_spawn passed (1 min 14 sec) -- running: test_concurrent_futures (2 min 18 sec)
0:02:22 load avg: 2.21 [427/427] test_concurrent_futures passed (2 min 22 sec)

== Tests result: SUCCESS ==

406 tests OK.

21 tests skipped:
    test_dbm_gnu test_devpoll test_epoll test_gdb test_ioctl test_lzma
    test_msilib test_multiprocessing_fork test_ossaudiodev
    test_smtpnet test_spwd test_ssl test_startfile test_tix test_tk
    test_ttk_guionly test_winconsoleio test_winreg test_winsound
    test_zipfile64 test_zoneinfo

Total duration: 2 min 22 sec
Tests result: SUCCESS
$ 

Podemos ver que hay un mucho mejor resultado. Por supuesto, éstas informales pruebas no toman en cuenta que mi computador tiene otras aplicaciones abiertas por lo que lo tiempos mostrados no deben tomarse como definitivos y con reservas.

Un comentario en “Python 3.10 en macOS 12 (2)

Deja una respuesta

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Salir /  Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Salir /  Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Salir /  Cambiar )

Conectando a %s

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.