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.
| Composant | Rôle |
|---|---|
| ALU | Opérations entières et arithmétique scalaire (additions, comparaisons, indexation) |
| FPU | Calcul 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 Predictor | Anticipe 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.
| Niveau | Portée | Latence typique | Usage en quant |
|---|---|---|---|
| L1 | Par cœur (I-cache + D-cache, ~32–64 Ko chacun) | ~1 ns | Boucles courtes sur arrays contigus |
| L2 | Par cœur (~256 Ko – 1 Mo) | ~3–4 ns | Réutilisation de données dans une fenêtre glissante |
| L3 / LLC | Partagé entre cœurs (8–384 Mo) | ~10–20 ns | Partage de données entre threads d'un même processus |
| RAM | Système entier | ~50–100 ns | DataFrames 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ément | Description |
|---|---|
| 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 :
| Concept | Description |
|---|---|
| Process | Instance isolée avec sa propre mémoire. Utilisé par |
| 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 |
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
multiprocessingou réécrire en NumPy/Cython/Numba - I/O (lecture fichiers, API) :
threadingsuffit 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_THREADSau nombre de cœurs d'un socket si NUMA
Software Stack
La pile logicielle CPU pour la finance quantitative :
| Couche | Rôle |
|---|---|
| OS Scheduler | Répartit les processus/threads sur les cœurs. L'affinité CPU ( |
| 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 / joblib | Parallé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
| Workload | CPU | GPU |
|---|---|---|
| Ingestion / ETL de données | Privilégié (I/O, parsing, logique métier) | Rarement utile |
| Feature engineering tabulaire | Pandas, Polars — très efficace | cuDF / RAPIDS si dataset énorme |
| Modèles arbres (XGBoost, LightGBM) | Excellent sur CPU, datasets < quelques Go | cuML si disponible et dataset massif |
| Deep learning (LSTM, Transformers) | Trop lent pour l'entraînement | Quasi obligatoire |
| Monte Carlo / simulations | Parallélisable via multiprocessing | GPU si millions de trajectoires indépendantes |
| Backtesting vectorisé | NumPy/Polars sur CPU, souvent suffisant | GPU si matrice très large (milliers d'actifs × années de ticks) |
Points clés pour la finance quantitative
- Choisir le bon parallélisme :
threadingpour l'I/O,multiprocessing/joblibpour le Python pur, BLAS multi-thread pour l'algèbre linéaire. - Limiter OMP_NUM_THREADS : si vous lancez 8 workersjoblibet 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-spyouscalenepour 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.