Aller au contenu principal

StarPU sur Jean Zay

StarPU est une bibliothèque de programmation par tâches pour les architectures hybrides, multicœurs et hétérogènes.

L'utilisateur doit fournir les algorithmes ainsi que les contraintes et StarPU s'occupe pour lui des dépendances des tâches, de la planification hétérogène optimisée, ainsi que des transferts et réplications optimisés des données entre les différents emplacements mémoires.

StarPU peut être utilisé via son API en C/C++/Fortran/Python ou par des pragmas OpenMP.

Liens utiles

Versions disponibles

La librairie est rendue disponible via nos modules. Pour visualiser les versions disponibles, vous pouvez lancer la commande module avail :

$ module avail starpu
starpu/1.3.9-cuda starpu/1.4.2-mpi-cuda-debug
starpu/1.3.9-cuda-debug starpu/1.4.2-mpi-debug
starpu/1.3.9-cuda-debug-simgrid starpu/1.4.4-mpi
starpu/1.3.9-cuda-simgrid

# sortie générée le 25/02/2026
attention

Pour utiliser StarPU sur la partition A100, il est nécessaire de charger préalablement le module arch/a100 pour accéder aux modules compatibles avec cette partition.

Plusieurs variantes sont disponibles :

VariantesDescription
-cudaSupport CUDA
-mpiVersion parallèle
-simgridSimulation d'architectures possible
-debugOptions de débogage activées à la compilation

Compilation d'un code C utilisant StarPU

On définit un code simple qui soumet une tâche à StarPU.

hello_world.c
#include <starpu.h>
#include <stdio.h>

/* Bien respecter la signature de la fonction qui doit être soumise à StarPU */
void cpu_func(void *buffers[], void *cl_arg)
{
printf("Hello world\n");
}

/* On enveloppe la fonction avec des paramètres spécifiques à une tâche StarPU, ce qu'on appelle un "Codelet" */
struct starpu_codelet cl =
{
.cpu_funcs = { cpu_func },
.nbuffers = 0
};


int main(int argc, char *argv[])
{
int ret;

/* Initialisation de StarPU */
ret = starpu_init(NULL);
STARPU_CHECK_RETURN_VALUE(ret, "starpu_init"); /* Vérifie l'état de l'initialisation */

/* Définition d'une tâche StarPU */
struct starpu_task *task = starpu_task_create();
task->cl = &cl; /* On pointe vers le codelet défini plus haut */

/* Soumission de la tâche à StarPU */
ret = starpu_task_submit(task);
STARPU_CHECK_RETURN_VALUE(ret, "starpu_task_submit");
ret = starpu_task_wait_for_all();

/* Termine StarPU */
starpu_shutdown();

return 0;
}

La compilation du code peut se faire à l'aide du Makefile ci-dessous :

Makefile
# Dependent de la version utilisée (voir module load starpu/...)
CFLAGS += $$(pkg-config --cflags starpu-1.3)
LDLIBS += $$(pkg-config --libs starpu-1.3)

all: hello_world

hello_world:
gcc $(CFLAGS) hello_world.c -o hello_world $(LDLIBS)

clean:
rm -f hello_world starpu.log
# compilation
module load starpu/1.3.9-cuda-debug
make

Soumission en mode batch

#!/bin/bash

## JOB INFO
#SBATCH --job-name=starpu_code
#SBATCH --output=%x_%j.out
#SBATCH --error=%x_%j.err

## NODE CONFIGURATION
#SBATCH --nodes=1
#SBATCH --ntasks-per-node=1
#SBATCH --cpus-per-task=10
#SBATCH --partition=cpu_p1
#SBATCH --hint=nomultithread

## JOB ACCOUNTABILITY
#SBATCH --account=xxx@cpu
#SBATCH --partition=cpu_p1
#SBATCH --time=01:00:00

## ENV ACTIVATION
## USE SAME STARPU VERSION AS TO COMPILE!
module purge
module load starpu/1.3.9-cuda-debug

## CODE EXECUTION
make
./my_app

Soumission en batch pour du code multi-nœuds

important

Ici, il faut charger une version parallèle de la librairie (variante -mpi).

#!/bin/bash

## JOB INFO
#SBATCH --job-name=starpu_multi-nodes_code
#SBATCH --output=%x_%j.out
#SBATCH --error=%x_%j.err

## NODE CONFIGURATION
#SBATCH --nodes=2
#SBATCH --ntasks-per-node=4
#SBATCH --cpus-per-task=10
#SBATCH --partition=cpu_p1
#SBATCH --hint=nomultithread

## JOB ACCOUNTABILITY
#SBATCH --account=xxx@cpu
#SBATCH --partition=cpu_p1
#SBATCH --time=01:00:00

## ENV ACTIVATION
## USE SAME STARPU VERSION AS TO COMPILE!
module purge
module load starpu/1.4.2-mpi-debug

## CODE EXECUTION
make
srun ./my_mpi_app

Dans cet exemple :

  • on tourne sur 2 nœuds ;
  • srun lance l'exécutable ./my_mpi_app en parallèle sur 8 tâches (4 tâches par nœud) ;
  • chaque processus/tâche utilise 10 cœurs CPU d'un nœud et se voit donc attribuer 1/4 de la mémoire du nœud ;
  • on utilise le module starpu/1.4.2-mpi-debug qui embarque le support MPI.

Cas d'un code python

important

Ici, il faudra charger préalablement un module Python en plus du module StarPU. Par exemple :

module load python/3.8.8
module load starpu

Exemple de script Python utilisant StarPU :

script.py
import time
import starpu
from starpu.joblib import Parallel, delayed

# Initialise StarPU
starpu.init()

# Définit une fonction qui dure quelques secondes
def huge_task(task_number):
print("Beginning of task : ", task_number, "\n")
c = 0
for i in range(200000000):
c += 1
print("End of task : ", task_number, "\n")
return task_number


start = time.time()
X = [1,2,3,4]
Parallel()(delayed(huge_task)(x) for x in X) # lance plusieurs tâches à StarPU
stop = time.time()
print(stop-start)


# Termine StarPU
starpu.shutdown()

Astuce

Vous pouvez ignorer le binding CPU défini par Slurm en définissant :

export STARPU_WORKERS_GETBIND=0
Attention

Dans ce cas, les instances StarPU se répartiront sur l'ensemble des cœurs disponibles sur le(s) nœud(s), même si vous ne les avez pas réservés via Slurm. Vous risquez donc de perturber le travail d'un autre utilisateur qui partagerait le même nœud et votre travail aura des performances dégradées.

Configurations particulières

Si vous avez besoin d'une compilation avec une configuration très précise (et non disponible depuis nos modules), il est tout à fait possible de compiler StarPU en local. Pour toute demande d'aide, vous pouvez contacter l'assistance à assist@idris.fr.