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

HAL
open science

# Full stack optimization for streaming applications

Noureddine Tamssaout

► To cite this version:

Noureddine Tamssaout. Full stack optimization for streaming applications. Computer Science [cs]. 2025. hal-05311328v2

HAL Id: hal-05311328

https://inria.hal.science/hal-05311328v2

Submitted on 7 Nov 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
<figure><img src="image_3.png" /></figure>

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

# Full stack optimization for streaming applications

Internship: Inria Centre at the University of Bordeaux

Noureddine TAMSSAOUT

Academic Year 2024 – 2025

Research Unit: Inria Bordeaux

Team(s): TADaaM

Supervisor(s): Mr. Mihail POPOV & Mr. Laércio LIMA PILLA &
Ms. Lana SCRAVAGLIERI & Ms. Diane ORHAN

## Abstract

Achieving efficient execution of streaming applications on modern computing architectures requires the coordinated optimization of parameters across multiple system layers. This work explores the co-optimization of diverse parameter dimensions—spanning both hardware and software levels—to enhance performance and energy efficiency. Leveraging a modular runtime environment and an auto-tuning framework guided by data-driven techniques, we evaluate the impact of various configurations on a representative streaming workload. The study highlights the complex interactions between tuning dimensions and demonstrates the benefits of holistic optimization strategies for streaming applications in SDR.

**Keywords:** High performance computing (HPC), Software-Defined Radio (SDR), Auto-Tuning, Machine Learning, Data Analysis, Performance optimization, Energy efficiency.
# Contents

<table><tr><td>1 Introduction</td><td>3</td></tr><tr><td>2 General Context</td><td>3</td></tr><tr><td>2.1 Problematic</td><td>3</td></tr><tr><td>2.2 Design space exploration</td><td>3</td></tr><tr><td>2.3 Software-defined radio</td><td>7</td></tr><tr><td>3 Methodology</td><td>11</td></tr><tr><td>3.1 Collecting metrics</td><td>11</td></tr><tr><td>3.2 Tunables</td><td>13</td></tr><tr><td>3.3 Workflow</td><td>14</td></tr><tr><td>4 Results</td><td>15</td></tr><tr><td>4.1 Impact of each parameter</td><td>15</td></tr><tr><td>4.2 NUMA Effects</td><td>21</td></tr><tr><td>4.3 BO & RL for DSE</td><td>23</td></tr><tr><td>4.4 Feature Importance</td><td>26</td></tr><tr><td>4.5 Throughput prediction with ML models</td><td>27</td></tr><tr><td>5 Conclusion & perspectives</td><td>29</td></tr><tr><td>6 Acknowledgements</td><td>30</td></tr><tr><td>Bibliography</td><td>31</td></tr></table>
# 1 Introduction

In an increasingly digital world, optimizing applications to fully exploit the capabilities of modern hardware has become a central challenge. Streaming applications, which are widely used in various fields such as telecommunications, signal processing, and embedded systems, require real-time performance while maintaining high energy efficiency. Modern computing architectures with their inherent heterogeneity, NUMA effects (Non-Uniform Memory Access), and complex memory hierarchies combined with intricate software stacks, make achieving such optimization particularly difficult.

My internship at the TADaaM team within the Inria of the University of Bordeaux is directly aligned with this challenge. The TADaaM team focuses on the characterization and optimization of scientific applications running on high-performance computing (HPC) systems. The subject of my internship, entitled "Full Stack Optimization for Streaming Applications", aims to co-optimize software and hardware parameters to improve both performance and energy consumption of streaming applications, with a particular focus on Software-Defined Radio (SDR).

More specifically, my work leverages two main tools: StreamPU, a modular C++ framework for building streaming pipelines, and CORHPEX, an auto-tuning infrastructure powered by machine learning strategies. The goal is to explore, model, and optimize the behavior of SDR pipelines (notably based on the DVB-S2 standard) by adjusting key execution parameters such as processor frequency, thread placement, compilation options and prefetchers.

This study starts by introducing the theoretical aspects and the general context of the internship. It then focuses on the research methodology and the experimental protocol. It concludes with the results.

# 2 General Context

## 2.1 Problematic

Streaming applications are very energy demanding, and ideally, we must ensure a high throughput for a good user experience or just to avoid big delays. The global context of this internship is a multi-objective optimization: Firstly, we are interested in minimizing the energy of our application. Secondly, we are also aiming to maximize the throughput of the streaming application.

The idea here is to use design space exploration (DSE) to find the sweet spot that satisfies these optimizations. Since we have a large space, this is the role of ML (Machine Learning) in our case, it will help us find the optimums without exploring the entire space. For this, we are going to use CORHPEX, a framework designed for DSE, combining ML and auto-tuning for HPC kernels.

We are using StreamPU, a C++11 library made for building streaming applications. It helps developers create and connect small processing units using a clear and simple model. We are going to use it to both collect the performance throughput metrics but also to apply an optimized scheduler or to apply different custom thread mappings. We are explaining the details of the theoretical/technical aspects of these two tools in the next sections.

## 2.2 Design space exploration

**Definition:** It is exploring various parameters useful for many engineering/implementation tasks, whether we aim for prototyping systems or optimizing HPC kernels. The main problems in this field are the large size of the space, it can easily reach millions, if not billions and also the difficulty of evaluating it. So various alternatives are used rather than exhaustive search, like the use of heuristics or ML-based methods (Bayesian optimization, genetic algorithms, reinforcement learning, etc.). The goal is to model
the entire space with a few initial points, in order to find the optimum (maximum or minimum depending on the objective function)[8].

**Methods:** Several methods exist for DSE: they utilize two main concepts "exploration" which is trying to find new possibilities, and "exploitation" which is trying to improve the already best-known options.

- **Bayesian Optimization:** in the context of hyperparameter tuning in DSE, BO is a powerful approach.

The problem of classic approaches like grid search or random search is that they do not consider previous results to select the next points.

In DSE, we often have a huge number of possible designs, and each evaluation (e.g., measuring performance or energy) can be slow or expensive.

Bayesian optimisation builds a mathematical model (usually a probabilistic surrogate like a Gaussian Process) of the design space. It then uses this model to choose the next design to test. This helps find near-optimal designs efficiently, with far fewer actual experiments than brute-force search.

**Acquisition function:** is a method used to decide where to sample next by balancing two goals: exploring areas where the model is uncertain and exploiting areas where the predicted performance is high. One of the most used Acquisition functions is the Upper Confidence Bound (UCB).

$$UCB(x) = \mu(x) + \kappa \cdot \sigma(x)$$

where:

$\begin{cases} \mu(x) & \text{is the predicted mean at } x, \\ \sigma(x) & \text{is the predicted standard deviation at } x, \\ \kappa & \text{is a positive parameter controlling exploration vs. exploitation.} \end{cases}$

- **A Gaussian Process (GP)** is a probabilistic model that defines a distribution over functions. It assumes that the function values at any finite set of input points follow a joint Gaussian distribution. This makes GPs useful for regression and Bayesian optimization, where we need both predictions and uncertainty estimates.

Mathematically, we write:

$$f(x) \sim \mathcal{GP}(m(x), k(x, x'))$$

where:

- $m(x)$ is the mean function, representing the expected value of the function at point $x$,

- $k(x, x')$ is the covariance (kernel) function, which defines how similar or correlated the function values are at points $x$ and $x'$.

Using a GP, we can predict the function value at new points and also quantify the uncertainty of these predictions[7].

Figure 1 represents a flowchart that summarizes how BO performs hyperparameter tuning in the context of DSE.
<figure><img src="image_5.png" /><figcaption>Figure 1 – Flowchart of BO[9]</figcaption></figure>

— Reinforcement Learning (RL): Unlike supervised learning, which learns from labeled data, or unsupervised learning, which identifies hidden structures, RL relies on trial-and-error to discover which actions yield higher rewards over time.

In RL, the agent observes a *state* (describing the current situation), selects an *action* based on its *policy* (which can be deterministic or stochastic), and receives a *reward* as feedback. The goal is to learn a policy $\pi$ that maximizes the expected return, often defined as: [6]

$$G_t = R_{t+1} + \gamma R_{t+2} + \gamma^2 R_{t+3} + \dots$$

where $\gamma \in [0, 1]$ is the discount factor balancing immediate and future rewards.

*Markov Decision Process (MDP)*: formally models this interaction as $M = (S, A, P, R, \gamma)$, where $S$ is the state space, $A$ the action space, $P(s'|s, a)$ the transition probability, and $R(s, a)$ the reward function.

*Value functions* help evaluate policies by estimating the expected return: $v_{\pi}(s)$ for states and $q_{\pi}(s, a)$ for state-action pairs. This supports balancing *exploration* (trying new actions) and *exploitation* (using known rewarding actions).

In the context of **Design Space Exploration (DSE)**, RL can be used to intelligently explore large design spaces by guiding the search toward configurations that are likely to perform better, based on cumulative feedback (e.g., performance, energy, or area). Instead of exhaustively evaluating all configurations, RL learns which regions of the design space to prioritize, reducing evaluation cost and time.

Figure 2 shows an RL agent interacting with an environment: it observes a state, takes an action, and receives a reward and new state. In DSE, the agent explores design configurations (states) by making changes (actions) and receives performance metrics (rewards) to learn optimal designs.
<figure><img src="image_6.png" /><figcaption>Figure 2 – Flowchart of RL[3]</figcaption></figure>

**CORHPEX:** stands for Compiler, Runtime, and Hardware Parameters Design Space Exploration, it is a flexible, modular, and extensible framework to explore and optimize HPC applications by tuning compiler, runtime, and hardware parameters[14].

It is based on three important concepts :

1. Exploration goals: concretly, they are our objective functions, in our case they are going to be energy consumption(min) of the system and throughput(max) of the streaming application, but it can also be other metrics in other benchmarks eg. execution time(min).

This is done by a module called aggregator, its function is to collect these metrics, and do statistical calculations on them, eg. mean/med.

2. Design space: CORHPEX, is using TOML files to define the values of each dimension of our parameters.

Table 1 presents the categories of our tunables and their parameters.

<table><caption>Table 1 – Examples of tuning categories and their parameters</caption><thead><tr><td>Category</td><td>Example</td></tr></thead><tbody><tr><td>Compiler flags</td><td>-O1, -O2, -O3, etc.</td></tr><tr><td>Runtime Parameters</td><td>OMP_NUM_THREADS, thread bindings</td></tr><tr><td>Hardware parameters</td><td>Prefetches, Frequencies</td></tr></tbody></table>

3. Choice of the exploration technique (BO, GA)

Figure 3 represents a the general architecture of the CORHPEX's framework.
<figure><img src="image_7.png" /><figcaption>Figure 3 – CORHPEX framework architecture[14]</figcaption></figure>

## 2.3 Software-defined radio

**Definition:** SDR is a wireless communication system where traditional hardware components (like mixers, filters, and modulators) are replaced or controlled by software. Instead of relying on fixed circuits, SDR uses programmable processors (like CPUs, FPGAs, or DSPs) to handle signal processing, making radios more flexible and adaptable[11].

Figure 4 shows the main components of SDR architectures.

- **Antenna:** captures incoming electromagnetic signals (for reception) and transmits outgoing signals (for transmission)

- **RF Front End:** Handles the initial analog signal processing (amplification, filtering, and frequency conversion)

- **ADC (Analog-to-Digital Converter):** Converts the received analog signals from the RF front end into digital signals.

- **DAC (Digital-to-Analog Converter):** Converts processed digital signals back to analog.

- **Generic Hardware & Radio Software:** This is the core of the flexibility in SDR, handling signal processing via software. It is responsible for implementing:

1. Filtering & Equalization

2. Error Correction

3. Adaptive Signal Processing

4. Software-Controlled tuning & Configuration
<figure><img src="image_8.png" /><figcaption>Figure 4 – Software Defined Radio (SDR) architecture[10]</figcaption></figure>

However, SDR architectures are power-intensive and suffer from high latency, thus the importance of using the right parameters.

**DVB-S2:** It is a widely adopted satellite communication standard designed for broadcasting digital TV including HDTV (using H.264 video coding<fnref n="1" />), internet, data collection from remote sites & government/military communications. It offers high efficiency and flexibility for modern satellite transmissions[4].

The standard contains three modules:

- **Transmitter:** its goal is to take the input data(bits) and turn into a radio signal(waveform).

- **The Channel Block:** simulates what happens between the transmitter and receiver. It's essential to test how well the system works when the signal is affected by real-world problems like noise, timing errors, and hardware imperfections.

- **Receiver Block:** once the messy signal arrives, the Receiver Block works hard to clean it up and get the data back.

As the Receiver's module contains the most computationally intensive task, we are using it standard as a benchmark.

Figure 5 shows the components to be modeled and simulated in order to design a DVB-S2 system.

<figure><img src="image_9.png" /><figcaption>Figure 5 – DVB-S2’s components[1]</figcaption></figure>

**StreamPU:** in the context of SDR and streaming applications, we want to process continuous, high-volume streams with a stable computational pattern. So the main challenges are:

<footnote n="1">1. H.264 (AVC) is an advanced video codec that compresses digital video using motion estimation, spatial prediction, and entropy coding to enable high-quality broadcasts at lower bitrates.</footnote>
- Efficient utilization of multicore & heterogeneous CPUs

- High throughput & low latency

- Energy efficiency in real-time processing

So for this, we are going to use *StreamPU* A Domain-Specific Embedded Language (DSL)<fnref n="2" />, embedded in C++, it is based on the Synchronous DataFlow (SDF)<fnref n="3" /> model[5]. So, since in SDR, we are talking about blocs that do specific processing, like in the DVB-S2 (encoding, modulation, filtering), these operations are transformed into chains of tasks.

The processing chain is therefore represented by a list *T* containing *N* tasks $t_i$, $1 \le i \le N$. The tasks are sequential: task $t_i$ receives a frame from $t_{i-1}$, processes it, and then sends it to $t_{i+1}$. Task $t_1$ corresponds to the first task at the beginning of the chain, while task $t_N$ corresponds to the last task at the end of the chain[12].

**The main concepts of StreamPU:** *Tasks/modules* are structured in StreamPU using directed acyclic graphs (DAGs), meaning it is impossible to start at any node and follow a sequence of directed edges that eventually loops back to the starting node.

*Sockets* are typed communication channels that enforce explicit data dependencies between the tasks. Table 2 shows the type of sockets that StreamPU uses.

<table><caption>Table 2 – StreamPU Socket Types[5]</caption><thead><tr><td>Type</td><td>Direction</td><td>Purpose</td></tr></thead><tbody><tr><td>input_socket</td><td>Inbound</td><td>Receives data from predecessor tasks</td></tr><tr><td>output_socket</td><td>Outbound</td><td>Sends data to successor tasks</td></tr><tr><td>forward_socket</td><td>Bidirectional</td><td>Lets a task read and write to the same memory buffer, avoiding unnecessary copies.</td></tr><tr><td>control_socket</td><td>Special</td><td>Handles switcher path selection</td></tr></tbody></table>

*Switcher*: routes data along different paths in the task graph depending on the situation, and it does so dynamically.

Figure 6 represents a simple sequence chain sequence.

<figure><img src="image_10.png" /><figcaption>Figure 6 – Simple chain sequence[5]</figcaption></figure>

<footnote n="2">2. A DSEL is a specialized programming language embedded within a general-purpose language (e.g. C++) to solve problems in a specific domain (e.g. SDR, signal processing, robotics, finance, etc.)</footnote>

<footnote n="3">3. Synchronous Dataflow (SDF) is a computational model used to describe and schedule systems where tasks (called actors or nodes) communicate via deterministic data streams. It is a specialized form of dataflow programming, where execution follows a static, predictable schedule based on fixed data production/consumption rates.</footnote>
# Parallelization Techniques in StreamPU

## Task Replication (Data Parallelism):

- Creates identical copies of stateless tasks across multiple threads

- Enables concurrent processing of independent data frames

- Improves throughput while maintaining data locality (private memory per replica)

- Requires thread-safe implementation or deep copy of module state

## Pipelining (Task Parallelism):

- Decomposes workflow into sequential stages with producer-consumer relationships

- Each stage operates on different data frames concurrently

- Theoretical throughput determined by slowest stage ($T_{pipe} = \max(T_{stage_i})$)

- Implemented via adaptor modules with synchronized buffers

Figure 7 represents an illustration of stage replication.

<figure><img src="image_11.png" /><figcaption>Figure 7 - Stage replication[12]</figcaption></figure>

**OTAC:** In the context of SDR, achieving high efficiency is not only a matter of scaling resources. One of the most important concepts is task scheduling and implementing a good algorithm whose objective functions are to maximize throughput while minimizing the number of cores used.

Two important constraints that must be applied:

1. Stateful tasks cannot be replicated, they are tasks whose execution depends not only on their current input but also on their internal state, which is influenced by previous inputs. This means they retain information across multiple executions, making them unable to be replicated without causing inconsistencies. Examples include tasks that perform operations like cumulative calculations or maintain buffers. In contrast, stateless tasks (like filters) depend solely on their current input and can be replicated for parallel processing[13][5].

2. The overall throughput is dictated by the slowest pipeline stage

OTAC stands for "Optimal maximal-packing for TAsk Chains". It is an optimal scheduling algorithm designed for pipelined and replicated task chains in Software-Defined Radio (SDR) systems, aiming to maximize throughput while minimizing the number of allocated hardware resources.

It is built on two key steps:

### 1. PROBE

- Ensures that:

- The duration of any stage does not exceed the inverse of the throughput $T^{-1}$ (i.e., the maximal allowed stage duration; recall that throughput).

- The number of used cores is as small as possible.
— Tasks are grouped into stages:

— Stateful tasks cannot be replicated (must run on a single core).

— Stateless tasks can be replicated (use multiple cores to reduce stage duration).

## 2. SOLVE

— Uses binary search to efficiently find the best achievable throughput.

— The idea is to:

(a) Define a minimum and maximum possible stage duration.

(b) Test a duration halfway between the current minimum and maximum.

(c) Call `PROBE()`:

— If we can build a valid schedule at this speed using at most *P* cores, we try a faster speed (update the maximum to the current value).

— Otherwise, we try a slower speed (update the minimum to the current value).

# 3 Methodology

In this section, we present how we collect the metrics (energy and throughput), which are the objective functions we want to optimize, we also describe the different tunable parameters, explain the type of architecture we use to run our experiments, and outline the workflow for launching our tests.

## 3.1 Collecting metrics

**Collecting the energy:** To get the data we need for our first objective function, we are relying on LIKWID, (short for “Like I Knew What I’m Doing”). It is a lightweight suite of command-line performance tools designed for Linux on x86 multicore processors; that helps developers analyze, measure, and optimize application performance by offering these commands for example: [15]

CORHPEX uses LIKWID as a wrapper to get energy measurements of our application, and it is done by a python module called `LikwidAggregator.py`. The main functions of this aggregator are to make sure that:

— LIKWID reads the energy counters at the start.

— It runs our application.

— And reads the counters again at the end.

The output is a CSV containing many information, but in our case, we are interested in the average total energy consumption (in Joules), calculated by summing CPU package and DRAM energy measured by LIKWID across multiple runs (meta-repetitions).

We have to sum two energy formulas:

— Energy consumed by each CPU package (socket), denoted as $E_{pkg,i}$ for package *i*.

— Energy consumed by the DRAM (memory subsystem), denoted as $E_{dram}$.

Assuming the system has *N* packages (sockets), in our case we have only two packages, the total CPU package energy $E_{pkg, total}$ is obtained by summing the energy values of all individual packages:

$$E_{pkg, total} = \sum_{i=1}^{N} E_{pkg,i}$$

To obtain the total system energy consumption $E_{total}$ accounting for both CPU packages and DRAM, we sum the total package energy and the DRAM energy:
$$E_{\text{total}} = E_{\text{pkg, total}} + E_{\text{dram}} = \left( \sum_{i=1}^{N} E_{\text{pkg, i}} \right) + E_{\text{dram}}$$

This total energy $E_{\text{total}}$ is then averaged over multiple runs to reduce measurement noise and improve accuracy. (10 meta-repetitions in our case)

**NB:** Each $E_{\text{pkg, i}}$ and $E_{\text{dram}}$ is expressed in joules (J) by LIKWID.

**Collecting the throughput:** To compute the throughput of the RX module in the DVB-S2 receiver using StreamPU, we follow several practical steps guided by how the system processes the data. Throughput is generally defined as the total amount of useful data processed divided by the total processing time:

$$\text{Throughput} = \frac{\text{Total useful data processed}}{\text{Total processing time}}$$

In our context, the useful data corresponds to the number of information bits (before channel coding) that the RX pipeline successfully decodes.

- **What is measured?** In DVB-S2, a frame (codeword) contains $K$ information bits, where $K$ depends on the modulation and coding (MODCOD) used. If we process $N_{\text{frames}}$ frames, the total useful data processed is $N_{\text{frames}} \times K$ bits.

- **StreamPU as the runtime**

StreamPU manages the parallel execution of RX pipeline modules (demodulation, LDPC decoding, etc.), either sequentially or in parallel, based on scheduling strategies either bu using a JSON file to specify our custom mappings or by using OTAC as a scheduler. Each module is implemented as a task in the pipeline.

- **Collecting raw metrics**

We need:

- The number of frames processed ($N_{\text{frames}}$).

- The frame size $K$ (from DVB-S2 standard).

- The total wall-clock time taken to process these frames.

- **Measure execution time**

**Measuring execution time:** We measure the runtime of the RX pipeline using `std::chrono` as follows:

```cpp
auto t_start = std::chrono::steady_clock::now();
// run the RX pipeline
auto t_end = std::chrono::steady_clock::now();
double duration_sec =
    std::chrono::durationCast(std::chrono::duration double>(t_end
    - t_start).count());
```

The variable `duration_sec` captures the total runtime of the RX module in seconds.

- **Compute throughput**

The total useful data in bits:

$$\text{total\_bits} = N_{\text{frames}} \times K$$
Then, throughput in bits per second:

$$throughput_bps = \frac{total\_bits}{duration\_sec}$$

Finally, throughput in megabits per second (Mbps):

$$throughput\_Mbps = \frac{throughput\_bps}{10^6}$$

## Instrumentation and logging

At the end of the RX pipeline, we print:

```
1
std::cout << "Pipeline throughput: " << throughput_Mbps << " Mbps"
<< std::endl;
```

When running experiments with different StreamPU configurations, each run logs its output to files like: `profile_strampu_<config>.txt`.

- **Aggregation and analysis:** We designed a custom aggregator called `StreamPUAggregator` in `CORHPEX`, whose role is to extract the throughput value from output files produced by the StreamPU pipeline. Each output file contains a special marker line:

```
===BEGIN_METRICS_BLOCK==
```

After this marker, the numerical metrics appear on specific lines. The aggregator uses the configuration file (written in TOML) to know which line and which word to extract. In our case, the value of the throughput is in the fifth line at the third column after the marker.

```
[[metrics.strampu]]
```

```
id = "throughput"
```

```
line = 5
```

```
word = 3
```

This method, which is using a marker, fixed line number, and word position is simple and fast, and avoids writing regular expressions.

**NB:** The throughput calculation here focuses on useful information bits, not total channel bits, ensuring the metric reflects the actual data rate from an application perspective.

The throughput is expressed in megabits per second (Mbps).

## 3.2 Tunables

To explore and optimize the trade-offs between performance and energy efficiency, we defined a tunable design space based on low-level hardware settings, runtime configuration, compiler optimizations, and thread mapping strategies. The key parameters are summarized below:

- **Hardware prefetchers:** Modern processors integrate several hardware prefetchers that proactively fetch data into cache hierarchies to mitigate memory access latency. Selectively enabling or disabling these prefetchers can reduce unnecessary memory traffic and cache pollution, potentially improving performance and lowering energy consumption, particularly for memory-bound workloads.

In our case, the prefetcher configuration is represented by a 4-bit value that ranges from `0000` to `1111`. Each bit corresponds to enabling (0) or disabling (1) a specific hardware prefetcher. For example, `0000` means all prefetchers are enabled, while `1111` means all are disabled.

- **Processor frequency:** Varying the CPU operating frequency directly affects computational throughput and power dissipation. Lower frequencies often yield significant energy savings
at the cost of performance, whereas higher frequencies can improve execution time but increase thermal and energy footprints. The exploration aims to identify frequency settings that provide the best trade-off.

- **Thread-level parallelism:** Adjusting the number of threads allows us to tune the degree of parallelism.

- **Mapping policies:** The placement of our PUs in our stages, either contiguously on the same NUMA node or in round-robin across nodes, along with choices like the number of tasks and whether to use one or both NUMA nodes, are different strategies that we will showcase in the results section. These choices matter because NUMA effects mean that local memory accesses have lower latency and higher bandwidth, while remote accesses are slower and can limit data transfer rates. This directly impacts the throughput we observe, as thread placement and data locality together determine how efficiently data flows through the pipeline

- **Compilation flags:** We considered two representative compiler optimizations:

- `-O3`: Enables aggressive high-level optimizations, including loop unrolling, vectorization, and function inlining, aiming to maximize execution speed.

- `-march=native`: Generates code optimized for the microarchitectural features of the compilation host, exploiting specialized instruction sets and hardware capabilities.

While both flags aim to improve performance, `-O3` focuses on general algorithmic transformations, whereas `-march=native` provides architecture-specific enhancements.

## 3.3 Workflow

So, once we have integrated the two tools, CORHPEX and StreamPU, and clearly defined our benchmark, which is the receiver block of the DVB-S2 chain, and once we know which dimensions we are going to explore, our goals are to identify the most performance- and energy-efficient parameters and extract insights about the system usage at large.

We need access to a powerful computing infrastructure in order to run these experiments effectively. In our case, the experiments will be executed on the Grid'5000, which is a large-scale, highly reconfigurable and flexible cluster testbed for experiment-driven research in all areas of computer science, with a particular focus on parallel and distributed computing, including Cloud, HPC, Big Data and AI[2].

**Architecture** Table 3 shows the topology of our machine that we are using to launch our experiences.

<table><caption>Table 3 – Hardware Topology Summary</caption><thead><tr><td>Component</td><td>Package L#0</td><td>Package L#1</td></tr></thead><tbody><tr><td>NUMA Node</td><td>L#0 (93 GB)</td><td>L#1 (94 GB)</td></tr><tr><td>L3 Cache</td><td>22 MB</td><td>22 MB</td></tr><tr><td>Number of Cores</td><td>16</td><td>16</td></tr><tr><td>Threads per Core</td><td>2</td><td>2</td></tr><tr><td>Total Processing Units</td><td>32</td><td>32</td></tr><tr><td>L2 Cache (per core)</td><td>1024 KB</td><td>1024 KB</td></tr><tr><td>L1d Cache (per core)</td><td>32 KB</td><td>32 KB</td></tr><tr><td>L1i Cache (per core)</td><td>32 KB</td><td>32 KB</td></tr></tbody></table>

**Running the experiments** Figure 8 illustrates the workflow of running our experiences on Grid 5000's cluster. First we used oarsub to reserve nodes and gain access, then we used kadeploy for deploying a custom, reproducible experimental environment before launching experiments.
<figure><img src="image_12.png" /><figcaption>Figure 8 – Experimentation Workflow</figcaption></figure>

# 4 Results

In this section, we focus on the results of our experiments. First, we will present the impact on energy consumption and throughput of each parameter dimension while keeping the other dimensions fixed. Next, we will analyze the effects of NUMA by running several scenarios and discussing the observed results. After that, we will apply Bayesian Optimization (BO) and Reinforcement Learning (RL) for design space exploration (DSE). Our interest will then shift to data analysis, where we built a dataset from the experiments conducted during the internship. From this dataset, we will extract the percentage of feature importance. Finally, we will develop several machine learning models to predict throughput based on the collected data.

## 4.1 Impact of each parameter

The first experiments of the internship aimed to understand the impact of each parameter. In these experiments, we fixed two dimensions and varied the third.

We started by varying the number of threads. Figure 9 shows the evolution of total energy consumption when increasing the number of threads from 8 to 64. We observe that increasing the number of threads initially leads to a sharp drop in energy consumption (from around 3100 J to 2750 J), which represents an approximate **reduction of** 11.3%. This is followed by small oscillations and a slight further decrease as the thread count increases. It was observed that with the OTAC scheduler, configurations using 60 and 64 threads consume less energy than configurations with 56, 52, or 48 threads.

One hypothesis is that this difference comes from how the workload is divided into tasks: for example, at 56 threads, the task decomposition includes an extra task compared to 60 and 64 threads, which might explain the higher energy use.

Another possible explanation could be measurement noise during profiling, or temperature effects causing the processor to lower its frequency when it gets hotter.

**NB:** It is important to emphasize that this corresponds to the *total* energy consumption for the program.

**NB:** OTAC actually never uses more than 20 PUs during all the experiments conducted on the RX module of DVB-S2. Even when more resources are available on the system, OTAC automatically adapts and uses only what is strictly required.

**NB:** The number of PUs (processing units) and threads refer to the same concept of parallel workers, described differently in various contexts.
It is interesting to examine whether optimizing performance necessarily leads to optimizing energy consumption. The evaluation shows that this is not the case: to maximize throughput, it is generally beneficial to use the maximum number of threads available. However, to minimize energy consumption, the optimal number of threads can be lower, as adding more threads may increase power consumption more than it reduces execution time.

<figure><img src="image_13.png" /><figcaption>Figure 9 – Energy Consumption vs. Thread (OTAC)</figcaption></figure>

Figure 10 illustrates the throughput (in Mbps) as a function of the number of threads, ranging from 8 to 64. Initially, increasing the number of threads from 8 to 20 leads to a significant increase in throughput. So, the throughput at 20 threads is **2.28 times greater** than the throughput at 8 threads.
<figure><img src="image_14.png" /><figcaption>Figure 10 – Throughput vs. Thread (OTAC)</figcaption></figure>

Figure 11 illustrates the total energy consumption (in Joules) as the frequency (in MHz) is varied, with the number of threads fixed at 20 and prefetchers at 0000 (all activated), even after fixing the number of threads to other values, **2000 MHz** seems to be the sweet spot for our application in term of energy.
<figure><img src="image_15.png" /><figcaption>Figure 11 – Energy Consumption vs. Frequency (OTAC)</figcaption></figure>

Figure 12 displays the throughput (in Mbps) as a function of frequency (in MHz), with the number of threads fixed at 20 and prefetchers at 0000.

Overall, the graph indicates that increasing the CPU frequency directly leads to higher throughput.
<figure><img src="image_16.png" /><figcaption>Figure 12 – Throughput vs. Frequency (OTAC)</figcaption></figure>

Figure 13 presents the energy consumption (in Joules) as a function of the number of threads, comparing two different compilation optimization flags: `-march=native` (red solid line) and `-O3` (green dashed line).

Notably, `-O3` consistently demonstrates lower energy consumption compared to `-march=native` for the same number of threads, particularly as the thread count increases beyond 16. This suggests that the `-O3` optimization level is more energy-efficient for this workload across a wider range of thread counts. The difference in energy consumption between the two optimization levels becomes more pronounced at higher thread counts.

**NB:** In this case, a custom mapping is used instead of OTAC because we want to utilize all processing units (PUs) of the system. This is achieved by defining a custom mapping in a JSON file, which applies:

```
numactl --cpunodebind=0,1 --interleave=all
```

to bind execution to NUMA nodes 0 and 1 and a balanced memory allocation across nodes.
<figure><img src="image_17.png" /><figcaption>Figure 13 – Energy Consumption vs. Number of Threads for Different Compiler Optimization Flags (JSON)</figcaption></figure>

Figure 14 illustrates the throughput (in Mbps) versus the number of threads for two compilation optimization flags: `-march=native` and `-O3`. Both optimizations show a sharp increase in throughput from 8 to 16-20 threads, with `-O3` reaching approximately 28.3 Mbps at 20 threads, slightly higher than `-march=native`'s 26.3 Mbps. Beyond 20 threads, throughput for both continues to rise but at a slower rate. Notably, `-O3` consistently provides slightly higher throughput than `-march=native` across most thread counts in the mid-range. Both curves eventually converge to a similar maximum throughput of around 29.1 Mbps at 60-64 threads, indicating that while both perform well, `-O3` offers a slight performance edge in the intermediate thread counts.
<figure><img src="image_18.png" /><figcaption>Figure 14 – Throughput vs. Number of Threads for Different Compiler Optimization Flags (JSON)</figcaption></figure>

Concerning the best energy/throughput trade-off, we conclude that the configuration with 20 threads, 2000 MHz, and -O3 is the best.

**NB:** Concerning the prefetchers, we observe that prefetchers do not have significant impact, so this application is not sensitive to prefetchers variations. The throughput varied by 0.080 Mbps (from ≈ 28.697 to 28.777 Mbps), while energy consumption varied by 53 Joules (from ≈ 2792 to 2845 Joules).

## 4.2 NUMA Effects

Figure 15 shows energy consumption implications of various CPU and memory binding strategies across increasing thread counts within a NUMA architecture.

NUMA effect refers to the performance variability that occurs in Non-Uniform Memory Access (NUMA) systems when a thread or process accesses memory located on a different NUMA node than the one where it is running.

In a NUMA architecture, the system is divided into multiple nodes (typically corresponding to CPUs or CPU sockets), each with its own local memory. Accessing local memory is faster (lower latency and higher bandwidth) than accessing memory that is local to another node (remote memory).

In this experience, we try to run several cases to showcase NUMA effects, the detail of each scenario is listed below:

- CPU0_Mem0: This scenario uses all the PUs (Processing Units) of NUMA node 0 and exclusively the memory of node 0, thus maximizing local accesses.

- CPU0_Mem1: This scenario uses all the PUs of NUMA node 0 and exclusively the memory of node 1, thus forcing remote accesses. This scenario is performed to evaluate how sensitive our scenarios is to memory numa effects

- CPU_Scatter, mem=interleave: This scenario utilizes all PUs of node 0 and node 1 in a dispersed, round-robin fashion for task assignment (e.g., Stage 0: PU0 (Node 0); Stage 1: PU1 (Node 1); etc.). Memory is interleaved, allowing the operating system to decide which memory
node to use based on an interleave policy. This is done to ease the burden on the memory controller while using all the resources across the entire system.

- **CPU_S scatter**, mem=0: This scenario uses all PUs of node 0 and node 1 in a dispersed, round-robin manner for task assignment (e.g., Stage 0: PU0 (Node 0); Stage 1: PU1 (Node 1); etc.). However, memory usage is explicitly restricted to only the memory of node 0.

- **CPU_Contiguous**, mem=interleave: This scenario utilizes all PUs of node 0 and node 1, but in a contiguous allocation fashion. This implies that PUs from node 0 (even PUs) are filled first, followed by PUs from node 1 (odd PUs). Memory access is interleaved across all available memory nodes. So here we increase thread locality while keeping pressure on memory controller low.

- **OTAC_Contiguous**: This scenario employs the OTAC scheduler by compiling 'dbvbS2' with 'hwloc=off'. This setup aims to use physical indexing to ensure processes/threads remain within the same NUMA node. Additionally, 'numactl' (e.g., '-membind=0' or '-cpunodebind=0') was used as a safety measure to bind to node 0.

- **OTAC_S scatter**: This scenario uses the OTAC scheduler in its classic mode with 'hwloc=on'. This configuration enables a round-robin distribution of tasks/threads across different NUMA nodes.

**Observations:**

- For the custom mapping with JSON, scaling the resources increases the energy consumption.

- Concerning the scenarios where we use only 1 node for calculation but different memory allocation, the scenario where we have the same node for calculation and memory consumes less than one with different memory allocation.

- Whether we are using OTAC, or a custom mapping, staying on the same node consumes less than making round-robin allocations from different NUMA nodes.

<figure><img src="image_19.png" /><figcaption>Figure 15 – Energy Consumption vs. Number of Threads for Different NUMA Binding Scenarios</figcaption></figure>

Figure 16 shows the throughput of various CPU and memory binding strategies across increasing thread counts within a NUMA architecture.
**Observations:**

- OTAC performs better than custom mappings where we applied round-robin distribution across the NUMA nodes, even though our custom JSON configurations used more processing units (PUs). This highlights the importance of having a good scheduler.

- OTAC's philosophy is to use fewer resources while trying to achieve the best performance. This explains why, when we use the entire Node 0 in the JSON configuration, we get a slightly better throughput (5 Mbps) than with OTAC.

- Whether we use OTAC or a custom mapping, keeping all threads on the same NUMA node performs better than distributing them in a round-robin fashion across multiple NUMA nodes.

<figure><img src="image_20.png" /><figcaption>Figure 16 – Throughput vs. Number of Threads for Different NUMA Binding Scenarios</figcaption></figure>

The observations from Figure 15 & Figure 16 highlight that keeping computations and memory allocations on the same NUMA node consistently results in lower energy consumption and better performance compared to distributing workloads across multiple nodes in a round-robin manner.

## 4.3 BO & RL for DSE

Our Design Space Exploration (DSE) is calculated by multiplying the number of possible values for each tunable parameter. Given 16 prefetch values, two flag options, 15 thread settings, and 11 frequency settings, the design space size $D$ is computed as:

$$D = 16 \times 2 \times 15 \times 11 = 5280$$

Figure 17 illustrates the performance-energy trade-offs explored by Bayesian Optimization.

We are interested in the top right corner, it is the best spot because we want to maximize the throughput while minimizing the energy. The majority of the efficient configurations are clustered, achieving high throughput (approximately 32.5 Mbps to 35 Mbps) with energy consumption typically between 3000 J and 3350 J. A secondary cluster indicates less efficient configurations at lower throughputs (20 Mbps) and higher energy costs (3600 J to 3850 J). The plot suggests that Bayesian Optimization effectively identifies high-performance configurations within a specific energy range.
<figure><img src="image_21.png" /><figcaption>Figure 17 – BO for DSE</figcaption></figure>

Table 4 summarizes the most important parameters of the BO algorithm.

<table><caption>Table 4 – Key optimization parameters of BO</caption><thead><tr><td>Parameter</td><td>Value</td><td>Meaning</td></tr></thead><tbody><tr><td>init_points</td><td>70</td><td>Number of initial random explorations</td></tr><tr><td>n_iter</td><td>30</td><td>Number of optimization iterations</td></tr><tr><td>acquisition_func</td><td>ucb (kappa = 3)</td><td>Acquisition function: Upper Confidence Bound</td></tr></tbody></table>

Figure 18 illustrates the results of the RL algorithm, they show a more concentrated exploration of highly energy-efficient configurations. A prominent cluster demonstrates high throughput (approximately 33 Mbps to 35 Mbps) coupled with significantly lower energy consumption, primarily in the 2400 J to 2550 J range.
<figure><img src="image_22.png" /><figcaption>Figure 18 – RL for DSE</figcaption></figure>

Table 5 summarizes the most important parameters of the RL algorithm.

<table><caption>Table 5 – Key reinforcement learning parameters</caption><thead><tr><td>Parameter</td><td>Value</td><td>Meaning</td></tr></thead><tbody><tr><td>n_episodes</td><td>100</td><td>Number of training episodes</td></tr><tr><td>max_steps_perepisode</td><td>200</td><td>Max steps allowed in each episode</td></tr><tr><td>learning_rate</td><td>0.005</td><td>Step size for updating model weights</td></tr><tr><td>batch_size</td><td>16</td><td>Number of samples per training batch</td></tr><tr><td>hidden_size</td><td>64</td><td>Number of neurons in hidden layer</td></tr></tbody></table>

## Comparative Analysis (BO vs. RL):

*Energy Efficiency:* The “RL” algorithm appears to achieve similarly high throughput values (e.g., 32–35 Mbps) while consuming significantly less energy compared to the “bo” algorithm. For instance, the “RL” algorithm reaches high throughput with energy consumption mostly below 2800 Joules, whereas the “bo” algorithm requires 3100–3350 Joules for similar performance. This suggests that the “RL” approach is more energy-efficient. This observation aligns with the target objective used in RL, namely the Energy Delay Product (EDP): a metric that quantifies efficiency by multiplying the energy consumed by the time taken to complete a task.

*Throughput:* Both algorithms achieve peak throughput in a similar range (around 35-36 Mbps). If the sole target was throughput, both seem capable of reaching high values. However, "RL" does so with less energy.

*Spread/Exploration:* Both plots show a distribution of points, indicating different configurations or iterations of the optimization process. The "bo" plot has a cluster of lower throughput/higher energy points that are less desirable, while "RL" also has some lower throughput points but generally seems to find more points in the high throughput, lower energy region.
## 4.4 Feature Importance

After running several experiments, we started thinking about how to utilize the data. We created a dataset by first merging all the experiments and then cleaning the final .csv file. The final dataset contains three columns and 544 rows. The first column represents the parameter configurations based on prefetchers, frequencies, and number of threads. The other columns contain the associated energy consumption and throughput of each configuration.

Since the dataset is medium we used the local machine to train our models, Table 6 showcases the hardware of the PC.

<table><caption>Table 6 – Summary of the system architecture used for ML training</caption><thead><tr><td>Component</td><td>Details</td></tr></thead><tbody><tr><td>CPU model</td><td>Intel(R) Core(TM) i5-10310U CPU @ 1.70GHz</td></tr><tr><td>CPUs</td><td>8 (4 cores × 2 threads), 1 socket</td></tr><tr><td>Frequencies</td><td>Max: 4400 MHz, Min: 400 MHz</td></tr><tr><td>Caches</td><td>L1d: 128 KB ×4, L1i: 128 KB ×4, L2: 1 MB ×4, L3: 6 MB ×1</td></tr><tr><td>RAM</td><td>8 GB</td></tr><tr><td>NUMA nodes</td><td>1 (CPUs 0–7)</td></tr></tbody></table>

In scikit-learn's `RandomForestRegressor`, feature importance is calculated based on the mean decrease in impurity (MDI), also known as Gini importance for classification or variance reduction for regression.

- **Decision Tree Basis**: Random Forests are collections of decision trees.

- **Impurity Decrease**: Each time a feature is used to split a node in a tree, it reduces the impurity (variance for regression) of the data.

- **Weighted Sum**: The impurity reduction from a feature is summed across all nodes where it's used within a tree, often weighted by the samples reaching each node.

- **Ensemble Average**: These sums are then averaged across all trees in the forest.

- **Normalization**: Final scores are normalized to sum to 1, showing relative importance.

Figure 19a is a cumulative plot that highlights that the number of threads is the most influential factor impacting energy consumption, followed by frequencies, with 'prefetchers' having the least relative importance. This indicates that efficient thread management is paramount for controlling energy usage in this system.

Same observations for Figure 19b, just in this case the number of threads are even more important in terms of throughput.

<figure><img src="image_23.png" /><figcaption>(a) Importance of Features for Energy Consumption</figcaption></figure>

<figure><img src="image_24.png" /><figcaption>(b) Importance of Features for Throughput</figcaption></figure>

<caption>Figure 19 – Comparison of Feature Importances</caption>
## 4.5 Throughput prediction with ML models

In this part we want to test several model based on our crated dataset, in order to predec the throughput.

**NB:** In this experiment, we are focusing exclusively on the throughput objective. We initially attempted to build several predictive models for energy consumption; however, these models did not yield satisfactory metric results. We hypothesize that even with a larger dataset, predicting energy consumption remains challenging due to the complex and potentially non-linear relationship between system parameters and energy behavior.

**Data preparation:** The dataset was partitioned into a training set (80%) and a test set (20%). To enhance the robustness of the evaluation, we applied k-fold cross-validation with k = 5 on the training set. This approach ensures a more reliable estimation of the model's generalization performance.

Figure 20 presents a comparison of predicted versus true throughput values for two machine learning models: Gradient Boosting Machine (GBM), which is an ensemble learning method that builds a strong predictive model by sequentially combining multiple weak learners, typically decision trees, and optimizing the residual errors through gradient descent. and Random Forest (RF).

We used R² & RMSE as metrics to evaluate our models.

1. **RMSE (Root Mean Square Error):** A common metric used to measure the difference between values predicted by a model and the values actually observed. It essentially tells you how far off, on average, your predictions are from the true data. RMSE is calculated as the square root of the average of the squared differences between predicted and actual values, and is given by:

$$RMSE = \sqrt{\frac{1}{n} \sum_{i=1}^{n} (y_i - \hat{y}_i)^2}$$

where $y_i$ are the actual values, $\hat{y}_i$ are the predicted values, and n is the number of observations. A lower RMSE indicates better model accuracy.

2. **R² (Coefficient of Determination):** A statistical measure that explains how well the predicted values approximate the actual data. It represents the proportion of variance in the dependent variable that is predictable from the independent variables. The R² value ranges from 0 to 1, where:

- 1 means the model perfectly predicts the data,

- 0 means the model does no better than simply predicting the mean of the observed values.

It is computed as:

$$R^2 = 1 - \frac{\sum_{i=1}^{n} (y_i - \hat{y}_i)^2}{\sum_{i=1}^{n} (y_i - \bar{y})^2}$$

where $\bar{y}$ is the mean of the actual values. A higher R² indicates a better fit.

Both models demonstrate a strong capability in predicting throughput, as summarized below:

### Gradient Boosting Machine (GBM)'s results

- R²: 0.8374

- RMSE: 2.6404

**Note:** A grid search was performed to identify the best hyperparameter configuration within the limited search space, yielding:

Best parameters:

colsample_bytree=0.8, learning_rate=0.1, max_depth=3, n_estimators=100, subsample=0.8
## Random Forest (RF)'s results

- R²: 0.8278

- RMSE: 2.695

Note: Grid search also provided the following best hyperparameters:

### Best parameters:

max_depth=5, minSamples_leaf=1, minSamples_split=2,
n_estimators=100

<figure><img src="image_25.png" /><figcaption>Figure 20 – Throughput Prediction Performance of GBM and Random Forest Models</figcaption></figure>

Figure 21 represents a plot titled "ANN Throughput: True vs Pred." It shows the relationship between "True Throughput (Mbps)" on the x-axis and "Predicted Throughput (Mbps)" on the y-axis, presumably from an Artificial Neural Network (ANN) model.

A dashed red line represents the ideal scenario where predicted values exactly match true values. The blue points with black outlines are individual data points. Most points cluster closely around the red line, indicating that the ANN model generally makes accurate predictions

## ANN's results

- R²: 0.8223

- RMSE: 2.7609

Note: Grid search's results:

### Best parameters:

activation=relu, alpha=0.001, hiddenLayerSizes=(50, 50),
learning_rate=constant, max_iter=500
<figure><img src="image_26.png" /><figcaption>Figure 21 – Throughput Prediction Performance of the ANN</figcaption></figure>

So, all three tested models produced very accurate predictions of the throughput for our specific application.

# 5 Conclusion & perspectives

**Conclusion** The study successfully explored the co-optimization of hardware and software parameters for streaming applications, particularly in Software-Defined Radio (SDR), demonstrating the benefits of holistic optimization strategies for performance and energy efficiency. Leveraging StreamPU and CORHPEX, the research identified key insights into system usage and the significant impact of thread management and frequencies on energy consumption and throughput. For optimal energy/throughput trade-off, a configuration of 20 threads, 2000 MHz, and -O3 proves most effective. Consolidating computations and memory on a single NUMA node significantly reduces energy consumption and enhances performance compared to distributed workloads. The Reinforcement Learning approach excels in identifying superior energy-performance trade-offs by thoroughly exploring the design space. Thread count is the primary determinant of both energy consumption and throughput, followed by frequencies, while prefetchers have minimal impact. All three prediction models accurately forecast throughput for the application.

**Perspectives:** Future work and perspectives arising from this research include:

1. Integrate new tunables like cache sizes or cache policies

2. Conducting evaluations on additional benchmarks.

3. Delving deeper into the memory aspects of optimization.

4. Deploying the methodology on diverse architectural platforms.

5. Generalizing the approach to handle other input characteristics (e.g., input size).

6. Enhancing the generalization capabilities of the models developed.
**6 Acknowledgements**

I want to express my sincere acknowledgements to the internship team: Mihail, Laércio, Lana, and Diane. They were always there to answer my questions and guided me perfectly in both theoretical and practical aspects.

I also want to thank all my teachers in the MSc HPC & Simulation program at the UPVD. They provided us with excellent courses on various interesting topics. A special thanks to Mr. David DEFOUR, who believed in my profile and accepted me into this program.

I would also like to thank all my friends for their support.

I would like to say *tanemirt* to my parents and my brothers for supporting me spiritually throughout my academic years and my life in general.
## References

[1] https://fr.mathworks.com/discovery/dvb-s2.html. Last visit: 15/07/2025.

[2] https://www.grid5000.fr/w/Grid5000:Home. Last visit: 28/07/2025.

[3] https://medium.com/@binaydhakal35/mdp-markov-decision-process-rl-reinforcement-learning-bc85e5d25031. Last visit: 30/07/2025.

[4] A. Cassagne, M. Léonardon, R. Tajan, C. Leroux, C. Jego, O. Aumage, and D. Barthou. A flexible and portable real-time dvb-s2 transceiver using multicore and SIMD cpus. pages 1–5, 08 2021. doi:10.1109/ISTC49272.2021.9594063.

[5] A. Cassagne, R. Tajan, O. Aumage, C. Leroux, D. Barthou, and C. Jego. StreamPu: A dsel for high throughput and low latency software-defined radio on multicore cpus. *Concurrency and Computation: Practice and Experience*, 35, 07 2023. doi:10.1002/cpe.7820.

[6] M. Ghasemi and D. Ebrahimi. Introduction to reinforcement learning, 2024. URL https://arxiv.org/abs/2408.07712.

[7] T. T. Joy, S. Rana, S. Gupta, and S. Venkatesh. Fast hyperparameter tuning using bayesian optimization with directional derivatives. *Knowledge-Based Systems*, 205:106247, 2020. ISSN 0950-7051. doi:https://doi.org/10.1016/j.knosys.2020.106247. URL https://www.sciencedirect.com/science/article/pii/S0950705120304457.

[8] E. Kang, E. Jackson, and W. Schulte. An approach for effective design space exploration. volume 6662, pages 33–54, 03 2010. ISBN 978-3-642-21291-8. doi:10.1007/978-3-642-21292-5_3.

[9] N. Loka, I. Couckuyt, F. Garbuglia, D. Spina, I. Nieuwenhuyse, and T. Dhaene. Bi-objective bayesian optimization of engineering problems with cheap and expensive cost functions. *Engineering with Computers*, 39, 01 2022. doi:10.1007/s00366-021-01573-7.

[10] J. Moskal. *Interfacing a Reasoner with Heterogeneous Self-controlling Software*. PhD thesis, 04 2011.

[11] C. Moy. La radio logicielle : un sujet d'enseignement et un moyen d'enseigner les communications sans fil à l'université. *J3eA*, 21:1008, 06 2022. doi:10.1051/j3ea/20221008.

[12] D. Orhan. Ordonnancement automatique et parallèle du flux de données appliqué à la radio logicielle et notamment au logiciel AFF3CT. Master’s thesis, Université de Bordeaux (UB), France, June 2022. URL https://inria.hal.science/hal-03768106.

[13] D. Orhan, L. Lima Pilla, D. Barthou, A. Cassagne, O. Aumage, R. Tajan, C. Jégo, and C. Leroux. Optimal Scheduling Algorithms for Software-Defined Radio Pipelined and Replicated Task Chains on Multicore Architectures. *Journal of Parallel and Distributed Computing*, page 105106, 2025. doi:10.1016/j.jpdc.2025.105106. URL https://hal.science/hal-04228117.

[14] L. Scravaglieri, A. Anciaux-Sedrakian, O. Aumage, T. Guignon, and M. Popov. Compiler, Runtime, and Hardware Parameters Design Space Exploration. In *IPDPS 2025 - 39th IEEE International Parallel and Distributed Processing Symposium*, Milan, Italy, June 2025. URL https://inria.hal.science/hal-04969854.

[15] J. Treibig, G. Hager, and G. Wellein. Likwid: A lightweight performance-oriented tool suite for x86 multicore environments, 2010. URL https://arxiv.org/abs/1004.4431.