Optimización de ejecutables. Caso de estudio: Linuxsampler

vagar
#1 por vagar el 04/11/2009
Una de las ventajas del software libre es que podemos compilarlo nosotros mismos, permitiéndonos optimizar el ejecutable resultante para nuestra máquina.

Hay que tener en cuenta que no es un procedimiento accesible para cualquiera, ya que implica un conocimiento en profundidad de nuestro hardware y cierta familiaridad con cómo funciona un compilador y el tipo de optimizaciones que se pueden realizar.

En cualquier caso la posibilidad está ahí, y si necesitas optimización pero te faltan los conocimientos siempre puedes acudir a tu gurú local o, si te merece la pena, contratar el servicio a alguien que sepa. Ten en cuenta que es un proceso laborioso, que incluye la investigación de las características del hardware concreto y la realización de varias pruebas hasta conseguir la versión más refinada.

En general hay tres tipos de optimización disponibles:

1) Opciones del compilador.
2) Opciones específicas del programa en tiempo de compilación.
3) Opciones específicas del programa en tiempo de ejecución.

Opciones del compilador.

Las distintas distribuciones albergan en sus repositorios ejecutables binarios genéricos que deben funcionar en una gran variedad de microprocesadores, aunque sean de la misma gran familia (i386, x86_64, etc.) Por ello no pueden estar optimizados para las características más específicas de cada procesador concreto (juegos de instrucciones extendidos como SSE, pipelines predictivos, etc.)

Sin embargo los compiladores suelen permitir esa posibilidad, particularmente gcc (programas en C) y g++ (programas en C++). Si miramos la documentación de gcc nos encontraremos con opciones genéricas como -O, opciones relacionadas con la arquitectura como -march, -mtune o -sse, opciones específicas como -funroll-loops...

El uso de las opciones más arcanas requiere bastante conocimiento del tema y una buena dosis de prueba y error, dado que los resultados no siempre son fáciles de determinar a priori (efectos de multiprocesador o multinúcleo, efectos de localidad del código máquina y tasa de fallos de acceso en las cachés de primer y segundo nivel, etc.)

Una forma sencilla de ajustar las opciones del compilador es utilizar las variables de entorno CFLAGS para gcc y CXXFLAGS para g++, que son respetadas por la mayoría de herramientas de compilación automatizada como autotools, scons, cmake, qmake, etc.

Por ejemplo, para una aplicación C++ que utilice autotools, como Linuxsampler, podríamos hacer:

[code]export CXXFLAGS="-march=native"
./configure
make
[/code]

Cuando aparezca el chorro de comandos de compilación notaremos que ahora se añaden nuestras opciones:

[code]g++ -DHAVE_CONFIG_H -I. -I../.. -march=native -pthread -MT liblinuxsamplerdb_la-InstrumentsDb.lo -MD -MP -MF .deps/liblinuxsamplerdb_la-InstrumentsDb.Tpo -c InstrumentsDb.cpp -fPIC -DPIC -o .libs/liblinuxsamplerdb_la-InstrumentsDb.o
[/code]

En el caso concreto de Linuxsampler tenemos la fortuna de que el autor, Christian Schoenebeck, ha aislado parte más intensiva algorítmicamente del programa para permitir hacer pruebas de rendimiento. Estos tests se encuentran en la carpeta "benchmarks". Tenemos que editar el fichero Makefile para poner los CFLAGS que queremos probar, compilamos con make y ejecutamos el programa resultante gigsynth para observar las mediciones que hace. Aclarar, reajustar y repetir hasta conseguir el resultado óptimo. Finalmente compilar la aplicación pasándole a configure los flags que mejor resultado nos han dado en los tests.

Como ejemplo, para el caso concreto de mi máquina las mejores opciones a las que he llegado son:

[code]CXXFLAGS="-O2 -march=pentium-m -ffast-math -funroll-loops -fomit-frame-pointer"
[/code]

La mejora es brutal respecto a la versión sin optimizar, del orden del 300%-400% (3-4 veces más rápido, lo que me permitiría tener 3-4 veces más voces del sampler sonando sin que haya cortes). Ojo, que esto no quiere decir que sea 3-4 veces más rápido que la versión empaquetada con la distribución, que normalmente incluirá algunas optimizaciones genéricas de amplia difusión como -O2 o -sse para familia i686, pero probablemente podremos obtener una mejora notable sobre una versión para i686 genérico.

Opciones específicas del programa en tiempo de compilación.

Son opciones que los autores del programa añaden al código y que sólo pueden modificarse al compilar el programa. Normalmente estas opciones están documentadas en algún fichero del directorio fuente como BUILD o INSTALL. En aplicaciones que usan autotools se suelen poder consultar pasando al script configure la opción --help. En nuestro caso de ejemplo, Linuxsampler, hay bastantes. Por brevedad del texto pondremos sólo parte de la salida del comando:

[code]./configure --help
[corte]
--enable-preload-samples
Due to seeking and latency issues with hard drives
we have to cache a small part of samples' head in
RAM (default=32768). The higher this value the
more memory will be occupied for each sample, but
the safer this will be in regards of possible
droputs. A 'good' value depends on the running
system and usage dependant factors.
[corte]
--enable-process-muted-channels
Enable processing of muted channels (default=no).
In that mode all MIDI events in the muted channels
will be processed. This will provide information
about the active voices in the muted channels and
will not discard notes, triggered in mute mode,
when the channel is unmuted. But also will reduce
the efficiency.
[corte][/code]

Para hacer uso de estas opciones hay que pasárselas al comando configure antes de compilar. Por ejemplo:

[code]./configure --enable-preload-samples=65536 --enable-process-muted-channels=no
make
[/code]

Estas opciones implican normalmente un compromiso, lo que ganamos por un lado lo perdemos por otro, así que habrá que decidir si nos compensa. Una vez que se ha compilado el ejecutable ya no se pueden modificar sin volver a compilarlo.


Opciones específicas del programa en tiempo de ejecución.


Son opciones del programa que se pasan al arrancarlo en la línea de comandos, mediante algún tipo de ficheros de configuración o mediante la interfaz de usuario de la aplicación.

En el caso de Linuxsampler un ejemplo es la polifonía máxima reservada, que se ajusta con el siguiente comando LSCP:
[code]
SET VOICES
[/code]

Copyright (c) 2009 Luis Garrido
Artículo publicado bajo licencia Creative Commons by-nc-sa.
e3b1395e9d991754237bae55b9ec3-2819202.png
Subir
OFERTASVer todas
  • beyerdynamic DT-770 Pro
    138 €
    Ver oferta
  • -8%
    Behringer X Air XR18
    645 €
    Ver oferta
  • -21%
    Zoom H4n Pro Black
    158 €
    Ver oferta
monon
#2 por monon el 08/11/2009
Algunas las he usado al compilar tanto Ardour como Jack y Ffado.
Pero no deja de ser una locura saber para que sirven todas las FLAGS y si
su activacion mejorará los resultados.

Ojalá puediese llegar acomprender todas esas opciones.
Subir
Dj_carri
#3 por Dj_carri el 09/11/2009
monon escribió:
Ojalá puediese llegar acomprender todas esas opciones.


Para activar los demás flags y conocer sus beneficios y efectos colaterales, hace falta una carrera. Hay opciones que pueden hacer que el programa funciones de manera incorrecta; por ejemplo, las que tienen que ver con operaciones matemáticas, que se pueden acelerar dando un resultado aproximado, en lugar de uno exacto.

Mi recomendación es poner -O2 ó -O3, que activan la mayoría de las optimizaciones, y -march=native, que optimiza para tu procesador. -O3 es la opción que activa más optimizaciones, pero puede hacer que el tamaño del ejecutable crezca en exceso (aunque para la mayoría, esto no es un problema).
Subir
Hilos similares
Nuevo post

Regístrate o para poder postear en este hilo