CPU

Nota bene : Ce contenu a été généré par IA. Je suis en train de travailler sur cette page pour proposer un contenu personnel et d'une meilleure qualité.

Cette page recense les éléments importants de l'architecture CPU pour la finance quantitative : ingestion de données, feature engineering, backtesting, modèles classiques (arbres, régression, Monte Carlo) et orchestration des pipelines ML. Les détails matériels peuvent différer entre Intel, AMD et ARM (Apple Silicon). L'accent est mis sur l'architecture x86-64 (Intel/AMD), la plus courante en environnement de trading et de recherche quant.

Structure

CPU x86-64
│
├── Compute Core
│   ├── Physical Cores
│   ├── Logical Threads (SMT / Hyper-Threading)
│   ├── ALU / FPU
│   ├── SIMD Units (SSE, AVX, AVX-512)
│   ├── Branch Predictor
│   └── Out-of-Order Execution Engine
│
├── Cache Hierarchy
│   ├── L1 Instruction Cache
│   ├── L1 Data Cache
│   ├── L2 Cache (per core)
│   └── L3 Cache / LLC (shared)
│
├── Memory Subsystem
│   ├── RAM (DDR4 / DDR5)
│   ├── Memory Controllers
│   ├── Memory Channels
│   └── NUMA Nodes
│
├── I/O and Interconnect
│   ├── PCIe Lanes
│   ├── QPI / UPI / Infinity Fabric
│   └── Chipset / I/O Hub
│
├── Execution Model
│   ├── Processes
│   ├── OS Threads
│   ├── Vectorization (SIMD)
│   └── Multi-core Parallelism
│
├── Multi-Socket
│   └── NUMA Topology
│
└── Software Stack
    ├── OS Scheduler
    ├── BLAS (OpenBLAS, MKL)
    ├── NumPy / Pandas
    ├── Polars
    ├── multiprocessing / threading
    ├── joblib
    └── scikit-learn / XGBoost (CPU)

Compute Core

Le cœur de calcul exécute les instructions du programme. Contrairement au GPU (SIMT, milliers de threads légers), le CPU est optimisé pour la latence et les branches conditionnelles complexes — typiques du code Python métier en finance.

Cœurs physiques et threads logiques

Un cœur physique est une unité d'exécution indépendante. Le SMT (Simultaneous Multi-Threading, Hyper-Threading chez Intel) expose deux threads logiques par cœur, partageant les unités d'exécution. En quant, cela aide surtout les workloads mixtes (I/O + calcul), mais pour du calcul pur (NumPy, BLAS), compter les cœurs physiques est souvent plus fiable que le nombre de threads logiques.

ComposantRôle
ALU

Opérations entières et arithmétique scalaire (additions, comparaisons, indexation)

FPUCalcul en virgule flottante (prix, rendements, volatilité, greeks)
SIMD (AVX)

Traitement vectoriel : une instruction opère sur 4–16 valeurs en parallèle (crucial pour NumPy/MKL)

Branch PredictorAnticipe les sauts conditionnels pour limiter les stalls du pipeline
Out-of-Order Execution

Réordonne les instructions indépendantes pour maximiser le débit du cœur

SIMD et vectorisation

Les instructions SSE, AVX et AVX-512 permettent d'exécuter des opérations sur des registres larges (128, 256 ou 512 bits). En pratique, la plupart des bibliothèques scientifiques Python (NumPy, SciPy, scikit-learn via BLAS) exploitent déjà ces instructions sous le capot — d'où l'importance d'installer une build MKL ou OpenBLAS optimisée.

Cache Hierarchy

La hiérarchie de caches compense l'écart de latence entre le CPU et la RAM. En finance quantitative, les accès mémoire non contigus (DataFrames, jointures, groupby) pénalisent fortement les performances.

NiveauPortéeLatence typiqueUsage en quant
L1Par cœur (I-cache + D-cache, ~32–64 Ko chacun)~1 nsBoucles courtes sur arrays contigus
L2Par cœur (~256 Ko – 1 Mo)~3–4 nsRéutilisation de données dans une fenêtre glissante
L3 / LLCPartagé entre cœurs (8–384 Mo)~10–20 nsPartage de données entre threads d'un même processus
RAMSystème entier~50–100 nsDataFrames entiers, historiques de marché, matrices de covariance

Bonnes pratiques : préférer les opérations vectorisées (NumPy, Polars) aux boucles Python ; utiliser des dtypes compacts (float32 vs float64) quand la précision le permet ; éviter les copies inutiles de DataFrames.

Memory Subsystem

La mémoire vive est la ressource la plus critique pour les gros backtests et les matrices de covariance.

ÉlémentDescription
RAM (DDR4/DDR5)

Mémoire principale. Capacité typique : 32–256 Go en workstation quant. Limite la taille des datasets en mémoire.

Memory Channels

Canaux parallèles (dual/quad-channel). Plus de canaux = plus de bande passante mémoire.

NUMA

Non-Uniform Memory Access : sur multi-socket, chaque CPU a une RAM locale. Accéder à la RAM d'un autre socket est plus lent.

Sur les serveurs multi-socket, le pinning NUMA (numactl, affinité des processus) peut améliorer significativement les performances des calculs parallèles lourds.

I/O and Interconnect

Le CPU orchestre les échanges avec le disque, le réseau et le GPU via PCIe. En pipeline quant typique :

  • Lecture disque → CPU (pandas/Polars) → feature engineering → entraînement GPU ou CPU
  • Le CPU reste le goulot pour l'ingestion de ticks, le parsing CSV/Parquet et la logique métier Python

Les liaisons QPI/UPI (Intel) ou Infinity Fabric (AMD) connectent les cœurs entre eux et vers le contrôleur mémoire.

Execution Model

Le parallélisme CPU en Python repose sur plusieurs niveaux :

ConceptDescription
Process

Instance isolée avec sa propre mémoire. Utilisé par multiprocessing pour contourner le GIL.

OS Thread

Thread système partageant la mémoire du processus. Limité par le GIL en CPython pour le code Python pur.

Vectorization

Parallélisme au sein d'une instruction (SIMD). Activé automatiquement par NumPy/BLAS sur code C/Fortran.

Multi-core

Parallélisme entre cœurs via multiprocessing, joblib, concurrent.futures.

Le GIL et ses implications

Le GIL (Global Interpreter Lock) de CPython empêche l'exécution parallèle de bytecode Python sur plusieurs cœurs. En pratique :

  • Calcul NumPy/BLAS : le GIL est libéré → parallélisme multi-cœur effectif
  • Boucles Python pures : un seul cœur → utiliser multiprocessing ou réécrire en NumPy/Cython/Numba
  • I/O (lecture fichiers, API) : threading suffit car le GIL est libéré pendant l'attente

Exemple : paralléliser un backtest

Chargement…

n_jobs=-1 utilise tous les cœurs disponibles via des processus séparés.

Multi-Socket et NUMA

Sur les serveurs de production (calcul de risque, Monte Carlo massif), on trouve souvent 2–4 sockets CPU. Chaque socket a sa mémoire locale :

  • Placer les workers sur le même socket que leurs données (numactl --cpunodebind)
  • Éviter le false sharing : deux threads modifiant des variables adjacentes dans le cache
  • Pour Polars/NumPy multi-threadés, limiter OMP_NUM_THREADS au nombre de cœurs d'un socket si NUMA

Software Stack

La pile logicielle CPU pour la finance quantitative :

CoucheRôle
OS Scheduler

Répartit les processus/threads sur les cœurs. L'affinité CPU (taskset) peut stabiliser les perfs.

BLAS (MKL, OpenBLAS)

Algèbre linéaire vectorisée (GEMM, dot product). Sous-jacent à NumPy et scikit-learn.

NumPy / Pandas

Calcul numérique et manipulation tabulaire. Cœur de la plupart des pipelines quant.

Polars

DataFrames multi-threadés en Rust. Souvent plus rapide que pandas sur gros volumes.

multiprocessing / joblibParallélisme multi-cœurs au niveau Python pour contourner le GIL.
scikit-learn / XGBoost (CPU)

Modèles classiques (Random Forest, gradient boosting) efficaces sur CPU pour datasets tabulaires.

Vérifier la configuration CPU

Chargement…

Sortie console (exemple)

Architecture : AMD64 Processeur : Intel64 Family 6 Model 183 Cœurs physiques : 32 threads logiques ... openblas64__info: libraries = ['openblas64_', 'openblas64_'] ...

CPU vs GPU en finance quantitative

WorkloadCPUGPU
Ingestion / ETL de donnéesPrivilégié (I/O, parsing, logique métier)Rarement utile
Feature engineering tabulairePandas, Polars — très efficacecuDF / RAPIDS si dataset énorme
Modèles arbres (XGBoost, LightGBM)Excellent sur CPU, datasets < quelques GocuML si disponible et dataset massif
Deep learning (LSTM, Transformers)Trop lent pour l'entraînementQuasi obligatoire
Monte Carlo / simulationsParallélisable via multiprocessingGPU si millions de trajectoires indépendantes
Backtesting vectoriséNumPy/Polars sur CPU, souvent suffisantGPU si matrice très large (milliers d'actifs × années de ticks)

Points clés pour la finance quantitative

  • Choisir le bon parallélisme : threading pour l'I/O, multiprocessing/joblib pour le Python pur, BLAS multi-thread pour l'algèbre linéaire. - Limiter OMP_NUM_THREADS : si vous lancez 8 workers joblib et que chaque worker lance 8 threads BLAS, vous saturez le CPU (oversubscription). - Préférer Polars pour les gros DataFrames et les agrégations complexes. - Profiler avant d'optimiser : cProfile, py-spy ou scalene pour distinguer temps Python vs temps C/BLAS. - RAM : un historique tick-by-tick sur 5000 actions peut dépasser 64 Go — planifier le partitionnement (Parquet par date/symbole) dès le départ. - Le CPU reste central : même dans un pipeline GPU, l'ingestion, le preprocessing et l'orchestration tournent sur CPU.