Juanjo Coello

Software Developer & Perpetual Wannabe
I tweet stuff at @jjcoellov

Primeros pasos con Threading Building Blocks

Hace poco, como tema de una presentación en la Facultad, @jmbarroso y yo estuvimos “jugando” con una librería de paralelización de Intel de la que no tenía ni idea de su existencia y que me dejó francamente sorprendido. Se llama Threading Building Blocks (TBB), lleva algunos años en el mercado y en este post explicaré someramente qué es, para qué sirve, y qué viene a mejorar en el mundo de la paralelización.

TBB - Qué es

TBB es una librería escrita en C++, para programas hechos en este lenguaje (por ahora), que facilita la paralelización de los mismos en procesadores multicore gracias a las funciones y estructuras que provee. Su objetivo es lograr un paralelismo escalable, haciendo uso de C++ estándar, que además abstraiga al programador de los detalles de la plataforma y del manejo de hilos, que exprese el paralelismo de una manera más simple y que realice un mejor aprovechamiento de los recursos de los procesadores.

TBB - Ventajas

TBB permite expresar el paralelismo como Tareas en lugar de Hilos. De esta forma, no es necesaria llevar a cabo manualmente la gestión de los mismos: no más create, join, manage, etc. Dichas tareas son asignadas automáticamente a hilos, haciendo un uso eficiente de los recursos del procesador.

Una característica curiosa es el uso de una técnica denominada task stealing; la librería se encarga de asignar/desasignar tareas entre procesadores de manera transparente al programador, según la carga de trabajo actual, para equilibrar el trabajo de todos. Toda esta “abstracción” permite desarrollar soluciones más simples de alto nivel.

Además, es compatible con otros paquetes de paralelización, por lo que se puede optar por usar algunos componentes de TBB bajo ciertas circunstancias, y usar diferentes soluciones (OpenMP, gestión de hilos manualmente) en otras.

TBB - Contenido

La librería provee soluciones de distinta índole para facilitar la paralelización de las aplicaciones, que se pueden dividir en:

Algoritmos básicos:
• parallel_for
• parallel_reduce
• parallel_scan

Algoritmos avanzados:
• parallel_while
• parallel_do
• pipeline
• parallel_sort

Contenedores:
• concurrent_queue
• concurrent_vector
• concurrent_hash_map

Reserva de memoria escalable:
• scalable_malloc
• scalable_free
• scalable_realloc
• scalable_calloc

Exclusión mutua:
• mutex
• spin_mutex
• queuing_mutex
• spin_rw_mutex
• queuing_rw_mutex
• recursive mutex

Operaciones atómicas
• fetch_and_add
• fetch_and_increment
• fetch_and_decrement
• compare_and_swap
• fetch_and_store

Timing:
• Método thread_save portable para procesar el tiempo transcurrido.

Planificador de tareas
• Acceso directo para controlar la creación y la ejecución de tareas

Instalando TBB.

La última versión estable de la librería para Windows, Linux y Mac se puede encontrar aquí.

La instalación resulta bastante sencilla. En mi caso con la versión para Mac OS, que no diferirá mucho de la disponible para Linux:

Se descomprime el tgz descargado. Yo lo hice en un directorio de mi home donde instalo los frameworks y librerías que utilizo (grails, maven, gradle, mercurial, etc) pero /opt/ podría ser otra ubicación adecuada. También he creado un enlace simbólico “tbb” que apunte a la última versión, para usarlo al referirme a la librería, en vistas a simplemente actualizar el enlace en caso de que siga descargando en el futuro versiones de la librería y quiera cambiar fácilmente entre ellas:

juanjo:bin juanjo$ pwd
/Users/juanjo/bin
juanjo:bin juanjo$ ls -ltr
drwxr-xr-x   4 juanjo  juanjo       136 24 ene 17:21 tbb30_20101215oss
juanjo:bin juanjo$ ln -s tbb30_20101215oss/ tbb
juanjo:bin juanjo$ ls -ltr
drwxr-xr-x   4 juanjo  juanjo       136 24 ene 17:21 tbb30_20101215oss
lrwxr-xr-x   1 juanjo  juanjo        22 24 ene 17:28 tbb -> tbb30_20101215oss/

Es necesario modificar el archivo bin/tbbvars.sh para asignar a la variable TBB30_INSTALL_DIR la ruta al directorio raíz de la librería:

juanjo:tbb juanjo$ pwd
juanjo:bin juanjo$/Users/juanjo/bin/tbb
juanjo:bin juanjo$ cat -n bin/tbbvars.sh

# Threading Building Blocks Home
    30    TBB30_INSTALL_DIR=/Users/juanjo/bin/tbb

Cargamos las variables definidas en el fichero, que se deberá hacer cada vez que se abra una terminal y se desee trabajar con la librería. La alternativa es añadir la línea al fichero ~/.bash_profile para hacerlo automáticamente al cargar sesión:

juanjo:bin juanjo$ source bin/tbbvars.sh

Para probar si todo está configurado correctamente, intentamos compilar y ejecutar uno de los ejemplos incluídos en la distribución:

juanjo:tbb juanjo$ cd examples/GettingStarted/sub_string_finder/
juanjo:sub_string_finder juanjo$ make
g++ -O2 -DNDEBUG  -o sub_string_finder sub_string_finder.cpp -ltbb
g++ -O2 -DNDEBUG  -o sub_string_finder_extended sub_string_finder_extended.cpp -ltbb
g++ -O2 -DNDEBUG  -o sub_string_finder_pretty sub_string_finder_pretty.cpp -ltbb
./sub_string_finder_extended
Done building string.
Done with serial version.
Done with parallel version.
Done validating results.
Serial version ran in 8.01188 seconds
Parallel version ran in 4.1834 seconds
Resulting in a speedup of 1.91516

En efecto, todo funciona, y ya estamos en disposición de empezar a utilizar los componentes que nos provee TBB. De hecho, en el ejemplo que lanzamos se observa una de las bondades: un speedup del 91% que no está nada mal.

En el próximo artículo veremos cómo hacer uso de los componentes incluídos en la librerías, paralelizando un código secuencial y desgranando el código fuente del mismo.

Más información:

• Página Oficial de Threading Building Blocks.