<figure><img src="image_1.png" /></figure>

HAL
open science

# Ordonnancement dynamique de chaînes de communication numérique pour la radio logicielle

Pierre-Antoine Creton

► To cite this version:

Pierre-Antoine Creton. Ordonnancement dynamique de chaînes de communication numérique pour la radio logicielle. Université de Bordeaux; Inria. 2025. hal-05224528

HAL Id: hal-05224528

https://inria.hal.science/hal-05224528v1

Submitted on 26 Aug 2025

HAL is a multi-disciplinary open access
archive for the deposit and dissemination of sci-
entific research documents, whether they are pub-
lished or not. The documents may come from
teaching and research institutions in France or
abroad, or from public or private research centers.

L'archive ouverte pluridisciplinaire HAL, est
destinée au dépôt et à la diffusion de documents
scientifiques de niveau recherche, publiés ou non,
émanant des établissements d'enseignement et de
recherche français ou étrangers, des laboratoires
publics ou privés.

<figure><img src="image_2.png" /></figure>

Distributed under a Creative Commons Attribution 4.0 International License
# Rapport de Stage

Ordonnancement dynamique de chaînes de communication numérique pour la
radio logicielle

par Pierre-Antoine CRETON

**Formation :** Licence 3 - Informatique

**Encadrants entreprise :** AUMAGE Olivier, responsable équipe STORM
ORHAN Diane, doctorante – équipe STORM

**Enseignant référent :** VIALARD Anne

**Entreprise d'accueil :** Centre Inria de l'université de Bordeaux
## Présentation du lieu du stage

<figure><img src="image_3.png" /><figcaption>(a) Centre Inria de l'université de Bordeaux</figcaption></figure>

<figure><img src="image_4.png" /><figcaption>(b) Logo de l'Inria</figcaption></figure>

L'Inria ou Inria (Institut National de Recherche en Informatique et Automatique)[1] a été créé le 3 janvier 1967, à Rocquencourt, tout d'abord sous le nom d'IRIA avant de changer pour son nom actuel au début des années 80. Cet établissement public français à caractère scientifique et technologique qui concentre principalement ses recherches sur les mathématiques et l'informatique. Il est placé sous la double tutelle du ministère de l'Enseignement supérieur, de la Recherche et de l'Innovation et du ministère de l'Économie et des Finances. Il existe de nombreux centres Inria en France (Rocquencourt, Bordeaux, Lille, ...) ayant chacun des unités de recherche sur différents domaines. Le centre Inria de l'université de Bordeaux [2] a ouvert ses portes en 2012. Ce centre accueille 22 équipes et travaille en partenariat avec les établissements d'enseignement supérieur, publics et des entreprises dans la région bordelaise ou à l'échelle nationale ou internationale. Ce centre est spécialisé principalement dans trois domaines qui sont :

- Convergence, calcul haute-performance et Big data ;

- Apprentissage automatique ;

- Santé numérique ;

<figure><img src="image_5.png" /><figcaption>FIGURE 2 – Logo de l'équipe STORM</figcaption></figure>

Mon stage s'est effectué au sein de l'équipe STORM [3] (STatic Optimizations - Runtime Methods) dont le responsable est Olivier AUMAGE. Cette équipe rassemble des membres, non pas seulement de l'Inria, mais aussi des établissements partenaires aux alentours comme le CNRS, l'université de Bordeaux et de Bordeaux INP. Cette équipe se focalise sur le parallélisme dans le calcul haute performance (High Performance Computing, HPC en anglais). L'objectif est d'obtenir des performances élevées sur des systèmes multicœurs ou hétérogènes, et en prenant aussi en compte l'efficacité énergétique de celle-ci. Pour remplir cet objectif, l'équipe axe ses recherches sur toutes les phases d'un programme : la compilation, l'exécution et l'analyse de celui-ci. La bibliothèque AFF3CT et son DSEL (Domain-Specific Embedded Language), StreamPU, qui est une bibliothèque fournissant des codages de canal mais aussi qui permet de simuler des chaînes de communications numériques s'inscrivent dans cette approche. Dans ce même cadre, j'ai assisté aux réunions organisées chaque mois entre les membres de l'équipe STORM et de l'équipe CSN de l'IMS (Laboratoire de l'Intégration du Matériau au Système) pour discuter des avancées sur AFF3CT. De plus, durant mon stage, j'ai pu assister à la conférence COMPAS (Conférence francophone d'informatique en Parallélisme, Architecture et Système) 2025 qui a lieu à Bordeaux, du 24 Juin au 27 Juin, ce qui m'a permis de découvrir les différents travaux de doctorants dans ces domaines.
Table des matières

<table><tr><td>1 Introduction</td><td>3</td></tr><tr><td>2 Contexte</td><td>4</td></tr><tr><td>2.1 La radio logicielle</td><td>4</td></tr><tr><td>2.2 Présentation des outils : AFF3CT et StreamPU</td><td>4</td></tr><tr><td>2.3 Ordonnancement statique de chaînes</td><td>6</td></tr><tr><td>3 Proposition</td><td>7</td></tr><tr><td>4 Implémentation</td><td>8</td></tr><tr><td>5 Conclusion</td><td>9</td></tr><tr><td>5.1 Résumé</td><td>9</td></tr><tr><td>5.2 Perspectives</td><td>10</td></tr><tr><td>6 Extra</td><td>11</td></tr></table>
# 1 Introduction

Communiquer avec autrui, échanger des informations, est à la base de toute société. Pendant des siècles, le courrier fut le moyen de communication le plus efficace. Avec le besoin croissant de délivrer l'information plus rapidement sur de longues distances, le télégraphe est apparu au XIXe, suivi du télégramme, permettant alors un échange quasi-instantané à cette époque. Au XXe siècle, sous l'effet des conflits mondiaux, la radio-communication connaît un essor. Poussé par les besoins militaires de communication rapide, sécurisée et sans fil, le développement de ces technologies radio va alors se diffuser dans la société civile. Ces développements technologiques conduisent à la généralisation et à la standardisation des télécommunications sans fil : de la radio à la télévision, puis de la téléphonie aux standards modernes (3G, 4G, 5G, ...). Aujourd'hui, de nombreux standards de communications existent et de nouveaux continuent d'émerger, souvent complexes, ce qui entraîne la complexification de leurs architectures dédiées. Mais la puissance de calcul grandissante des processeurs généralistes ouvre la porte à la radio logicielle (ou SDR, *Software-Defined Radio*, en anglais), qui apporte un système reconfigurable et évolutif.

En effet, les matériels dédiés pour les standards de communications sont conçus pour maximiser leurs performances : débits, latences, efficacités énergétiques, ... Il est donc normal que les processeurs génériques ne rivalisent pas sur l'ensemble de ces aspects. Cependant, cette spécialisation a un coût. Un matériel dédié devient obsolète si le standard pour lequel il a été conçu évolue, ou si de nouveaux standards apparaissent. Alors, il ne répondra plus aux exigences demandées et se révèlera inefficace. Par ailleurs, le matériel dédié souffre aussi d'un manque de flexibilité. Si un défaut est détecté après la fabrication d'un lot, celui-ci devient inutilisable, ce qui entraîne des pertes financières et matérielles. À l'inverse, l'implémentation logicielle des standards de communication sur des processeurs généralistes permet de corriger ce défaut. Une mise à jour logicielle suffit à adapter ou reconfigurer le système. Même si les performances restent généralement inférieures à celles du matériel dédié, elle représente un atout majeur dans le cadre d'évolutions nombreuses et rapides. De plus, grâce à leur capacité de parallélisation, les processeurs généralistes peuvent atteindre des débits de traitement similaires à ceux des architectures dédiées et de leur implémentation matérielle.

C'est dans ce contexte d'évolution rapide des standards de communication et du développement de la radio logicielle comme réponse à cela qu'interviennent la bibliothèque AFF3CT et son support d'exécution StreamPU. AFF3CT[4] (*A Fast Forward Error Correction Toolbox*) est une bibliothèque développée par l'Inria, l'IMS et le LIP6, en C++ dédiée à la simulation et à l'évaluation des performances de chaînes de communication numériques, notamment en matière de codage de canal. StreamPU[5] (ancienne-ment AFF3CT-core) est un DSEL (*Domain-Specific Embedded Language*) pour les applications de type streaming. Également développé en C++, StreamPU est un support d'exécution parallèle pour des chaînes de communication numériques. Il s'appuie sur différentes formes de parallélisation comme le pipelining ou la réplication, mais aussi sur un ordonnancement statique, qui fonctionne efficacement sur des chaînes linéaires. Cependant, l'ordonnancement statique montre ses limites dès que les chaînes ne le sont plus. Cela survient, par exemple, lorsque les tâches ont des durées variables, ou lorsque la chaîne a des conditions ou des boucles. Prenons pour exemple une chaîne de communication dont le comportement varie en fonction du bruit environnant ou de conditions d'exécution : un ordonnancement statique deviendra alors sous-optimal. Il dégradera les performances de celle-ci. Face à ces limites, l'ordonnancement dynamique gagne en intérêt puisqu'il permettrait d'adapter la répartition des ressources en réaction aux changements à l'exécution.

C'est dans ce cadre que s'inscrit le travail effectué dont l'objectif était de développer une approche d'ordonnancement dynamique pour des chaînes de communication numérique dans la radio logicielle. Le rapport s'organise comme suit : la section suivante présente plus en détail la radio logicielle, la modélisation des chaînes de communication numérique et de StreamPU. La troisième section introduit la problématique liée à l'ordonnancement dynamique de chaînes complexes tout en soulignant les limites de l'approche d'un ordonnancement statique. La quatrième section est consacrée à la proposition d'un ordonnancement dynamique sur un cas précis de chaîne de communication, son intégration dans StreamPU, puis à analyser brièvement les résultats obtenus avant de conclure et de parler des perspectives d'évolution possibles.
# 2 Contexte

## 2.1 La radio logicielle

La radio logicielle, ou *Software-Defined Radio* (SDR) propose une approche différente des systèmes de communications radio. Ces derniers reposent principalement sur l'utilisation de matériel dédié, conçu pour maximiser leurs performances. Introduit par Joseph MITOLA dans les années 90 [6], le concept de radio logicielle a pour objectif de remplacer l'implémentation par matériel dédié par des équivalents logiciels qui s'exécuteraient sur des plateformes reconfigurables (processeurs génériques, FPGA, ...).

L'importance de la radio logicielle aujourd'hui est directement liée à la complexification des standards de communication. L'évolution des réseaux mobiles en est une illustration : les premières générations se focalisaient uniquement sur des services fondamentaux comme la voix (1G) ou les messages textes (SMS / 2G). Les standards modernes comme la 5G, quant à eux, doivent gérer ou supporter des services hétérogènes. Ceux-ci incluent le streaming très haut débit, l'Internet des Objets (IoT) qui connecte des millions d'appareils variés (téléphones mobiles aux voitures connectées) avec la garantie d'une faible latence. Toutes ces contraintes rendent la conception de matériel dédié longue, difficile et coûteuse, justifiant le besoin de flexibilité qui est fournie par la radio logicielle.

<figure><img src="image_6.png" /><figcaption>FIGURE 3 – Évolution des réseaux de communication à partir de la 2G.
Source : https://www.tactis.fr/reseaux-cellulaires-mobiles/</figcaption></figure>

Si la complexité croissante des standards est un argument pour la radio logicielle, l'évolution des performances des plateformes matérielles assure la faisabilité de celle-ci. L'augmentation de la puissance de calcul des processeurs généralistes (CPU) en est la principale raison. Grâce à leur capacité de parallélisation sur des architectures multi-cœurs ou hétérogènes, ils peuvent atteindre des débits de traitements obtenus avec des architectures dédiées. Ces performances, associées à leur disponibilité, permettent de rendre la radio logicielle viable pour de nombreuses applications.

Il existe aujourd'hui de nombreuses bibliothèques de radio logicielle qui tirent profit des plateformes matérielles. La plus célèbre est GNU Radio [7], développée en C++, qui possède une interface graphique permettant à l'utilisateur de prototyper et de simuler avec du matériel ou dans un environnement de simulation sans matériel des standards de communication numériques. Il en existe d'autres comme StreamIt ou Array-OL. Mais ces bibliothèques ne supportent pas l'intégralité des encodages de canaux ou ne supportent pas la parallélisation sur des architectures multicoeurs. Les bibliothèques AFF3CT et StreamPU comblent ces défauts.

## 2.2 Présentation des outils : AFF3CT et StreamPU

AFF3CT [4] est une bibliothèque, développée par l'Inria, l'IMS et le LIP6, en C++. Son développement commence par les travaux d'Adrien CASSAGNE durant sa thèse, en se focalisant sur 4 objectifs principaux :

- une hétérogénéité algorithmique;

- la prise en charge de différents algorithmes;

- la portabilité;
— la reproductabilité.

**AFF3CT** permet à ses utilisateurs de simuler des chaînes de communications numériques et d'évaluer leurs performances, notamment en termes de codage de canal (Turbo code, LDPC, ...). Plus précisément, AFF3CT évalue la capacité de correction de familles de codes correcteurs d'erreurs : à l'aide de la méthode Monte-Carlo, des trames sont générées, codées puis bruitées aléatoirement dans le canal. Le récepteur décode alors les trames bruitées. Elles sont comparées aux trames initiales pour déterminer leur BER (*Bit-Error Rate*, ou taux d'erreur par bit) et leur FER (*Frame-Error Rate* ou taux d'erreur par frame). On trace ces courbes de BER/FER en fonction du rapport signal/bruit et les courbes sont comparées aux courbes attendues par la communauté.

<figure><img src="image_7.png" /><figcaption>FIGURE 4 – Schéma d'une chaîne de communication numérique standard.
Source : https://aff3ct.readthedocs.io/en/latest/user/introduction/introduction.html</figcaption></figure>

AFF3CT, en tant que logiciel, est composé de trois bibliothèques :

— AFF3CT, pour la partie simulation, code d'erreurs, ...

— StreamPU, un DSEL et le support d'exécution d'AFF3CT

— MIPP, la bibliothèque qui se focalise sur la vectorisation des opérations

On va s'intéresser plus particulièrement à StreamPU.

<figure><img src="image_8.png" /><figcaption>FIGURE 5 – Une séquence simple dans StreamPU.
Source : https://aff3ct.github.io/streampu/sequence/</figcaption></figure>

StreamPU est un DSEL (*Domain-Specific Embedded Language*) et un support d'exécution. Un DSEL (en français langage dédié) est, comme son nom l'indique, un langage de programmation qui permet de répondre à des besoins spécifiques d'un domaine. Ici, StreamPU est un DSEL qui répond aux besoins spécifiques de la radio logicielle et qui directement implémenté en C++. Il met à disposition de l'utilisateur de nombreux outils pour pouvoir réaliser leur propre chaîne de communication numérique et les exécuter sur des architectures multicoeurs. Il modélise une chaîne de communication comme un graphe de tâches. Pour ce faire, StreamPU a des concepts-clés :

— **Tâche (Task)** : Le concept élémentaire. C'est une fonction qui s'exécute sur le flux de données (le terme flux de données (ou *Dataflow* en anglais désigne aussi la chaîne de communication)). Une tâche
a deux états :

- *Stateless* : La tâche n'a pas d'état interne et n'a pas besoin de conserver des données entre chaque exécution. Elle peut être alors exécutée sur des plusieurs données / trames successives. Elle est donc parallélisable.

- *Stateful* : La tâche a un état interne. Contrairement à une tâche *Stateless*, elle ne peut s'exécuter sur une seule donnée/trame à la fois. Elle est donc séquentielle et ne peut pas être parallélisée. Chaque tâche est liée aux autres tâches par des sockets.

- **Socket** : C'est un point de connexion et un buffer qui permet de lier les tâches. Chaque tâche a au moins un socket, soit entrant, soit sortant. Ils permettent de faire transiter les données.

- **Module** : Un conteneur qui regroupe une ou plusieurs tâches. Il est **Stateful** si l'une des tâches qu'il contient l'est.

- **Sequence** : Un ensemble de tâches liées formant un graphe linéaire. C'est la structure qui permet de construire une chaîne de communication dans StreamPU. Une fois construite, elle ne peut être modifiée durant l'exécution.

StreamPU utilise la réplication des tâches et lorsque la séquence elles apartiennent est *Stateless* pour gagner en performance. Or, lorsqu'on prend comme exemple la figure 5, on remarque que la Sequence ne s'exécute que sur un seul thread. Cela est dû à la présence des tâches *Stateful*. Pour résoudre ce problème, StreamPU a un autre concept-clé : la **Pipeline**.

<figure><img src="image_9.png" /><figcaption>FIGURE 6 – Sequence simple transformée en Pipeline.
Source : https://aff3ct.github.io/steampu/pipeline/</figcaption></figure>

La **Pipeline** est une **Sequence** découpée en un ou plusieurs étages, réplicables ou non et exécutés comme des **Sequence**. En observant la figure 6, on remarque que la **Sequence** de la figure 5, qui s'exécutait sur un thread car non réplicable par la présence de tâches *Stateful* devient une **Pipeline** à 3 étages, avec celui du milieu qui s'exécute sur 3 threads car composé uniquement de tâches *Stateless*. Par conséquent, les performances obtenues seront plus élevées que la première version. StreamPU en combinant la réplication des tâches et le pipelining, maximise les performances des chaînes de communication.

Mais le simple fait d'utiliser les deux techniques de parallélisation ensemble ne garantit pas que les performances soient les plus élevées. La construction des étages de la **Pipeline** constitue une étape importante dans la construction de celle-ci. Si, en reprenant pour exemple la figure 6, la tâche $t_2$ était dans le même étage que la tâche $t_1$, on perdrait le bénéfice de la réplication de celle-ci, ce qui diminuerait les performances globales. Il est donc nécessaire d'ordonnancer les tâches afin de maximiser le débit.

## 2.3 Ordonnancement statique de chaînes

L'ordonnancement, en informatique, est l'action d'ordonner l'exécution des tâches et de leur attribuer les ressources nécessaires (par exemple, un nombre de threads) suivant une contrainte. Cette contrainte peut
être de maximiser le débit, ou inversement minimiser la latence, de minimiser le nombre de ressources utilisées, ... L'ordonnancement de chaîne est très largement étudié dans la littérature scientifique [8], [9] mais l'algorithme d'ordonnancement qui nous intéresse est OTAC [10], puisque c'est cet algorithme qui est utilisé pour ordonnancer les chaînes de communications dans StreamPU.

OTAC, pour *Optimal maximal-packing for TAsk Chains* est un algorithme d'ordonnancement optimal pour des chaînes de tâches. L'objectif de l'algorithme est simple : il ordonnance la chaîne de tâche en créant des étages pour la **Pipeline** dans le but de maximiser le débit de celle-ci en minimisant la période, qui est liée au temps d'exécution de la tâche la plus longue. Pour ce faire, OTAC se repose sur deux fonctions : PROBE et SOLVE. La fonction SOLVE utilise une recherche dichotomique suivant la période pour trouver une solution, c'est-à-dire la répartition en $\{(n, r)\}$, avec *n* le nombre de tâches dans l'étage et *r* le nombre de ressources allouées. PROBE, qui est appelée par SOLVE, pour trouver cette solution, construit les étages en fonction de la borne supérieure de la période et en allouant de manière gloutonne le maximum de tâches dans un étage sans gaspiller de ressources. Or, lorsqu'on regarde la littérature scientifique et OTAC sur l'ordonnancement de chaîne, on remarque deux choses :

- On ordonnance une chaîne, un graphe linéaire

- Ce sont des ordonnancements statiques.

<figure><img src="image_10.png" /><figcaption>FIGURE 7 – Exemple de chaîne de communication non-linéaire.
Source : https://aff3ct.github.io/streampu/tests_bootstrap#switch-case</figcaption></figure>

Et les chaînes de communication ne sont pas toujours des chaînes linéaires. En effet, une chaîne de communication peut contenir des tâches à durées variables, des conditions comme dans la figure 7 qui représente un switch-case ou des boucles. Et ce ne sont plus des graphes linéaires. Ordonnancer des graphes non linéaires est difficile et l'ordonnancement statique risque de poser un problème car on pourrait avoir une dégradation des performances due à une mauvaise répartition des tâches ou des ressources inutilisées ou surexploitées.

## 3 Proposition

L'ordonnancement statique par l'algorithme OTAC, bien qu'optimal pour des chaînes linéaires, n'est pas adapté pour des chaînes non linéaires comme par exemple la figure 7. Un ordonnancement calculé pour un chemin d'exécution deviendrait alors sous-optimal si la chaîne parcourait un autre chemin. Dès lors qu'une chaîne de communication incorpore des éléments tels que des tâches à durées variables, des conditions ou des boucles, la question qui se pose est de savoir comment gérer de telles chaînes tout en conservant des
performances élevées ? La réponse qui est proposée est l'ordonnancement dynamique. L'idée réside dans le passage de l'ordonnancement de la compilation (statique) à l'exécution (dynamique). Un ordonnanceur dynamique pourrait, en temps réel, déterminer selon une politique donnée (baisse de débit, changement de chemin fréquent, ressources inutilisées, ...) de réordonnancer les tâches pour maintenir des performances élevées. Nous allons donc explorer une piste d'implémentation d'ordonnancement dynamique dans StreamPU qui permettrait de supporter des chaînes de communication avec des conditions dans StreamPU.

Notre proposition consiste à développer un mécanisme d'ordonnancement dynamique au sein de StreamPU, qui serait capable de s'adapter aux changements de chemin dans une chaîne de communication avec des modules de contrôle de flux ou à la variabilité de la durée des tâches. En utilisant OTAC comme point de départ, de par son optimalité pour les chaînes linéaires, l'objectif est de permettre à celui-ci de gérer un premier cas de chaîne non linéaire : les chaînes à condition. L'idée ne serait pas de réordonnancer la chaîne à chaque changement de chemin, mais de changer d'ordonnancement statique uniquement lorsqu'un changement de chemin à l'exécution est détecté. Pour ce faire, notre approche se déroule comme ceci :

- Construire les pipelines de chaque chemin exclusif : Avant même de lancer l'exécution de la pipeline du premier chemin qui sera parcouru par la trame, on va construire une pipeline par chemin exclusif, en utilisant OTAC, qui seront conservés afin d'éviter de les recalculer à chaque fois qu'il sera nécessaire de réordonnancer.

- Ré-ordonnancement à la volée : Grâce à l'implémentation d'un nouveau module, il est possible de savoir quel chemin est exécuté. Alors à la fin de l'exécution de la trame, la pipeline active sera échangé par la pipeline du chemin qui sera exécutée.

Cette approche combine alors l'utilisation d'OTAC pour obtenir un ordonnancement statique optimal et permet d'avoir une flexibilité, tout en évitant le coût du re-calcul du ré-ordonnancement. Les sections suivantes détailleront l'implémentation de ces mécanismes et évalueront cette méthode face à l'approche actuelle.

# 4 Implémentation

Pour valider cette approche, nous avons réalisé une preuve de concept en l'intégrant directement dans un cas d'usage déjà existant dans StreamPU. L'implémentation a été réalisée et testée sur le cas d'usage **test-exclusive-paths** qui a été copiée et renommée **test-exclusive-paths-dynamic**. Ce test est représenté par la figure 7.

Avant de passer aux fonctionnement de l'ancienne approche et la nôtre, il faut expliquer ce qu'est un module *Switcher*, qui est le module de contrôle de flux et les tâches *commute* et *select* à l'intérieur de ce module. Le module *Switcher* est un module qui contient les deux tâches *commute* et *select*. Il permet à une séquence d'avoir plusieurs chemins exclusifs. Une tâche *commute* possède deux sockets d'entrées : un socket qui s'occupe de l'aiguillage vers le chemin exclusif pour les données et l'autre socket pour les données entrantes. Elle a alors n sockets de sorties vers chaque chemin exclusif, numérotées de 0 à n-1. Une tâche *select* a n sockets d'entrées (autant que de sockets sortants de la tâche *commute*, étant donné qu'elles font partie du même module) et un seul socket sortant. Si on prend la figure 7 comme exemple, on peut voir la tâche *control* qui fournit le chemin à prendre pour *commute* et la tâche *initializer* qui fournit les données. La tâche *commute* a trois chemins exclusifs donc la tâche *select* a autant de sockets entrants.

<figure><img src="image_11.png" /><figcaption>FIGURE 8 – Schéma des sous-séquences d'une chaîne linéaire dans StreamPU.
Source : https://aff3ct.github.io/streampu/pipelineCtrlFlow/#_tabbed_1_3</figcaption></figure>
<figure><img src="image_12.png" /><figcaption>FIGURE 9 – Schéma des sous-séquences d'une chaîne de chemin exclusif dans StreamPU.
Source : https://aff3ct.github.io/streampu/pipelineCtrlFlow/#_tabbed_1_1</figcaption></figure>

Avant les modifications, la procédure était adaptée uniquement aux chaînes linéaires : la séquence était transmise à l'ordonnanceur qui profilait chaque tâche de la séquence pour ensuite construire la Pipeline grâce à la solution optimale trouvée par OTAC. La Pipeline était exécutée avec une condition d'arrêt suivant le nombre d'exécutions souhaité par l'utilisateur. Néanmoins, cette méthode ne fonctionnait pas pour les chaînes comportant un module de contrôle de flux (Switcher) : StreamPU ne permettait pas de profiler correctement une séquence contenant des tâches commute ou select, car premièrement il y avait dans la fonction profile une vérification pour savoir si la séquence avait un module de contrôle de flux. Si oui, alors cela arrêter le programme. Deuxièmement, si on commentait cette vérification, seulement les tâches de la première sous-séquence était récupérées. Enfin, le programme ne fonctionnait que si tous les modules étaient réplicables.

Après modifications, la Pipeline est construite après une exploration complète du graphe du sous-séquences. Pour chaque chemin exclusif, une Pipeline est construite, à partir des tâches présentes dans chaque sous-séquences (hormis les nœuds de type COMMUTE ou SELECT). Ces Pipeline sont mises en cache avant l'exécution, évitant ainsi de recalculer un ordonnancement à chaque changement de chemin. Avant l'exécution dans la boucle principale, la Pipeline active est choisi en fonction du chemin initial (déterminé via le module Controller avant la création de chaque Pipeline). C'est dans cette boucle que le réordonnancement intervient : Un nouveau module, Finalizer_monitor, qui remplace le module Finalizer, permet cela. Connecté au module Controller, il récupère le chemin pris par la trame en cours. Grâce à une interface présente dans StreamPU, il peut interrompre proprement la Pipeline à la fin de l'exécution de la trame lorsque le chemin pris diffère de celui de la Pipeline actuelle. Lorsqu'un changement est detecté, l'exécution courante est interrompue après que la trame entière soit passée. La Pipeline associée au nouveau chemin est sélectionnée dans le cache et exécutée à son tour jusqu'à la prochaine interruption. Ainsi, le système alterne entre plusieurs Pipeline pré-calculées, selon les branches empruntées par la trame, sans devoir reprofiler et de recalculer un ordonnancement durant l'exécution.

C'est en cela que notre approche peut être intéressante : bien que l'on conserve un ordonnancement statique, on a un comportement dynamique qui peut s'adapter aux branches conditionnelles d'une chaîne de communication. Le système est alors plus flexible sans pour autant que le coût d'exécution augmente dras-tiquement. De plus, là où l'ancienne approche ne pouvait avoir que des modules réplicables, cette approche nous permet d'avoir des modules non réplicables.

# 5 Conclusion

## 5.1 Résumé

Ce stage s'est déroulé dans le cadre de la radio logicielle, où l'utilisation des processeurs généralistes et de leurs architectures multicoeurs offre une grande flexibilité et des débits de traitements équivalents à ceux des matériels dédiés. Néanmoins, les outils comme StreamPU, bien que permettant grâce aux techniques de parallélisation d'obtenir ces débits, montrent des limites avec l'ordonnancement statique lorsque les chaînes de communication ne sont plus linéaires, par exemple avec une structure conditionnelle.
L'objectif était donc de concevoir et d'implémenter une preuve de concept d'un mécanisme d'ordonnancement dynamique sur les chaînes conditionnelles dans StreamPU. Pour ce faire, nous avons proposé une approche hybride : en prévision de devoir recalculer la pipeline à chaque ré-ordonnancement, on pré-calcule l'ordonnancement de chaque chemin exclusif qui est alors mis dans un cache. Une tâche de supervision est intégrée à un nouveau module qui hérite du module Finalizer qui détecte le changement de chemin à l'exécution sur la Pipeline courante et change alors celle-ci par la Pipeline du chemin détecté.

L'évaluation de notre implémentation a montré sa capacité à exécuter des chaînes conditionnelles avec des modules non réplicables, ce qui était impossible avec l'approche statique de base. Bien que cette approche semble introduire un surcoût dans la performance dans le cas entièrement parallélisable, elle confirme la nécessité d'un ordonnancement dynamique pour améliorer les performances de StreamPU.

## 5.2 Perspectives

Dans un premier temps, il serait intéressant d'améliorer le mécanisme de changement de Pipeline. Il introduit peut-être un surcoût dans le temps d'exécution de la Sequence. La politique de réordonnancement pourrait être affinée. Par exemple, un changement de Pipeline pourrait être effectué seulement si un nouveau chemin a été exécuté à un nombre de fois ou s'il y a une chute du débit, ce qui éviterait le changement trop fréquent dans le cas de notre test. L'implémentation d'un nouveau test est aussi important alors.

La prise en charge des autres cas comme les chaînes de communication avec des tâches à durée variable ou des boucles est une perspective à ne pas oublier puisque notre travail s'est concentré sur les chaînes de communication avec des conditions.

Enfin, on utilise toujours l'ordonnancement statique mais d'une manière créative. À plus long terme, il serait nécessaire d'intégrer un ordonnanceur dynamique réellement capable de calculer une nouvelle Pipeline durant l'exécution.
# 6 Extra

During my internship, I worked with **StreamPU** (formerly known as AFF3CT-core), a library written in C++. It is a *Domain-Specific Embedded Language (DSEL)* and a runtime support developed as a part of the AFF3CT software, which specifically designed for streaming applications in the context of software-defined radio (SDR).

It gives to the user a wide range of tools to build their own digital communication chains and to execute them on multicores or heterogeneous architectures. The key tools provided by StreamPU includes :

- **Task**: the fundamental tool of StreamPU. A task is a function that processes a stream of data (also known as *Dataflow*). A task has two states :

- **Stateless**: It has no internal state and can be executed on multiple consecutive data frames. It can be parallelized.

- **Stateful**: It has an internal state between each execution and can only be executed sequentially. It cannot be parallelized.

- **Socket**: a connection point and a buffer which bound tasks together. Each task has either one input or output socket. It delivers data between the tasks.

- **Module**: a container that groups one or more tasks. It is considered stateful if any of his tasks is stateful.

- **Sequence**: A graph of connected tasks. This is the structure used to build a digital communication chain in StreamPU. Once built, it cannot be modified at runtime.

StreamPU uses replication and pipeline parallelism in order to maximise performance. For example, if all tasks in a Sequence are stateless, the Sequence can be replicated and executed in parallel. However, if any of those tasks is stateful, it prevents the replication and forces the Sequence to run on a single thread. To counter this problem, StreamPU uses pipelining with the concept of **Pipeline**. A Pipeline splits a Sequence into stages, each of which can be replicated depending on the nature of its tasks. For example, a stage with only stateless tasks can be executed on multiple threads, which improves throughput.
Références

[1] Contributeurs WIKIPÉDIA. *Institut national de recherche en informatique et en automatique. Wikipedia*. 2025. URL : https://fr.wikipedia.org/wiki/Institut_national_de_recherche_en_informatique_et_en_automatique.

[2] Centre Inria de l'université de Bordeaux. Inria. 2025. URL : https://www.inria.fr/fr/centre-inria-universite-bordeaux.

[3] Team STORM. Équipe STORM - Centre Inria de l'université de Bordeaux. 2025. URL : https://team.inria.fr/storm/.

[4] A. CASSAGNE et al. "AFF3CT : A Fast Forward Error Correction Toolbox!" In : *Elsevier SoftwareX* 10 (oct. 2019), p. 100345. ISSN : 2352-7110. DOI : 10.1016/j.softx.2019.100345.

[5] A. CASSAGNE et al. "StreamPU : A DSEL for High Throughput and Low Latency Software-Defined Radio on Multicore CPUs". In : *Wiley Concurrency and Computation : Practice and Experience (CCPE)* 35.23 (juill. 2023), c7820. DOI : 10.1002/cpe.7820.

[6] J. MITOLA. "Software radios-survey, critical evaluation and future directions". In : [*Proceedings*] NTC-92 : *National Telesystems Conference*. 1992, p. 13/15-13/23. DOI : 10.1109/NTC.1992.267870.

[7] THE GNU RADIO FOUNDATION. *What is GNU Radio?* https://wiki.gnuradio.org/index.php?title=What_is_GNU_Radio%3F. Accessed : 2025-07-10. 2025.

[8] Anne BENOIT et Yves ROBERT. "Complexity Results for Throughput and Latency Optimization of Replicated and Data-parallel Workflows". In : *Algorithmica* 57.4 (août 2010), p. 689-724. ISSN : 0178-4617.

[9] Ali PINAR et Cevdet AYKANAT. "Fast optimal load balancing algorithms for 1D partitioning". In : *Journal of Parallel and Distributed Computing* 64.8 (2004), p. 974-996.

[10] Diane ORHAN et al. "Optimal Scheduling Algorithms for Software-Defined Radio Pipelined and Replicated Task Chains on Multicore Architectures". In : *Journal of Parallel and Distributed Computing* (2025), p. 105106. DOI : 10.1016/j.jpdc.2025.105106. URL : https://hal.science/hal-04228117.