Aller au contenu

3 · Données et bases de données

Le domaine où le GPU gagne le plus spectaculairement et échoue le plus discrètement, pour la même raison : la capacité mémoire.


3.1 Pourquoi ça marche

Les opérations analytiques de base sont massivement parallèles :

Opération SQL Primitive GPU
WHERE (filtrage) prédicat + compaction de flux (scan)
GROUP BY tri ou table de hachage
SUM, AVG, COUNT réduction segmentée
ORDER BY tri par base
JOIN jointure par hachage ou par tri-fusion

Toutes reposent sur les primitives de la partie 2 : réduction, scan, tri. Et toutes sont limitées par la bande passante mémoire, ce qui joue en faveur du GPU : 3,35 To/s sur H100 contre ~400 Go/s pour un nœud CPU bi-socket.

Un tri par base sur GPU (cub::DeviceRadixSort) atteint la bande passante mémoire. Un GROUP BY sur un milliard de lignes prend moins d'une seconde.


3.2 RAPIDS

La suite NVIDIA d'analyse de données GPU.

import cudf

df = cudf.read_parquet("evenements.parquet")     # lecture directe sur GPU
resultat = (df[df["montant"] > 100]
              .groupby("client")
              .agg({"montant": "sum", "id": "count"})
              .sort_values("montant", ascending=False))

L'API reproduit celle de pandas. Depuis 2023, cudf.pandas accélère du code pandas existant sans modification :

%load_ext cudf.pandas       # dans un notebook
import pandas as pd          # ← devient cudf sous le capot, avec repli CPU

Les autres composants :

Composant Équivalent
cuDF pandas
cuML scikit-learn (forêts, k-means, PCA, régressions, UMAP)
cuGraph NetworkX (PageRank, composantes, plus courts chemins)
cuSpatial GeoPandas
cuVS recherche vectorielle (CAGRA, IVF-PQ, IVF-Flat)

Accélérations typiques : 10× à 50× sur les jointures et agrégations de volumes importants.


3.3 La contrainte qui domine tout

La capacité mémoire est le mur

Un H100 a 80 Go, un B200 192 Go, un MI355X 288 Go. Un serveur d'analyse a couramment 1 à 4 To de RAM.

Si vos données ne tiennent pas en VRAM, tout change : il faut découper, diffuser en flux, ou passer par la mémoire unifiée — et le PCIe (64 Go/s) devient le goulot, soit 52 fois moins que la HBM.

Les réponses possibles :

1. Traitement en flux par morceaux. Découper le fichier, traiter morceau par morceau, agréger. Fonctionne pour les agrégations, mal pour les jointures qui ont besoin de vues globales.

2. Multi-GPU. Dask-cuDF distribue sur plusieurs cartes. 8 × 80 Go = 640 Go utilisables, avec le coût de la communication.

3. GPUDirect Storage. Lecture directe du NVMe vers la VRAM sans passer par la RAM du CPU. Élimine une copie et le goulot du CPU.

4. Compression. Blackwell embarque un moteur de décompression matériel. Les mesures publiées sur 100 Mo :

Format Débit d'entrée Débit de sortie Latence
LZ4 173,2 Go/s 172,6 Go/s 0,608 ms
Bitcomp 154,0 Go/s 462,4 Go/s 0,227 ms
Zstandard 77,5 Go/s 154,9 Go/s 0,677 ms

Source : arXiv:2512.02189. Garder les données compressées en VRAM et les décompresser à la volée multiplie la capacité effective — c'est précisément le but de ce moteur.


3.4 Les bases de données GPU

Plusieurs systèmes utilisent le GPU comme moteur d'exécution principal :

Système Positionnement
HeavyDB (ex-OmniSci/MapD) analytique + géospatial + visualisation
BlazingSQL SQL sur RAPIDS (projet largement absorbé par cuDF)
Kinetica analytique temps réel, géospatial
PG-Strom extension GPU pour PostgreSQL
Theseus / Voltron Data moteur de requêtes distribué GPU, basé sur Arrow

Ils excellent sur : agrégations sur des milliards de lignes, géospatial, séries temporelles, tableaux de bord interactifs.

Ils sont mauvais sur : transactionnel (OLTP), requêtes très sélectives (peu de lignes retournées), jointures dépassant la VRAM, et tout ce qui manipule intensivement des chaînes de caractères.

Le traitement des chaînes est le point faible structurel

Les chaînes de longueur variable impliquent des accès indirects, de la divergence, et des allocations dynamiques — les trois choses que le GPU fait mal.

cuDF les gère avec une représentation en colonnes (offsets + tampon de caractères, format Arrow), ce qui aide beaucoup. Mais une expression régulière sur un milliard de chaînes reste un cas où le GPU n'a pas d'avance décisive.


3.5 La recherche vectorielle

Un cas d'usage devenu majeur avec les systèmes de génération augmentée par récupération (RAG).

Le problème : trouver les \(k\) vecteurs les plus proches d'une requête, parmi des millions ou des milliards, en grande dimension (768 à 4 096).

Pourquoi le GPU convient : c'est un produit matriciel suivi d'une réduction top-\(k\). La recherche exhaustive sur \(N\) vecteurs de dimension \(d\) est une GEMM \(1 \times d \times N\) — exactement ce que fait bien un GPU.

Les index approximatifs :

Index Principe Compromis
Flat exhaustif exact, \(O(N)\)
IVF partition en cellules, ne visiter que les proches rappel/vitesse
IVF-PQ + quantification par produit compression 10-50×
CAGRA graphe de proximité, conçu pour GPU très rapide, mémoire élevée
HNSW graphe hiérarchique référence CPU, moins adapté GPU

CAGRA (dans cuVS et FAISS-GPU) mérite l'attention : c'est un index conçu pour le GPU dès le départ, dont le parcours de graphe est structuré pour rester parallèle — contrairement à HNSW, dont le parcours séquentiel est hostile.

C'est encore un exemple du principe : l'algorithme optimal sur CPU n'est pas l'algorithme optimal sur GPU.


3.6 Le format des données

Un point souvent négligé et déterminant.

Format Adaptation GPU
Apache Arrow excellent — colonnaire, sans copie, c'est le format natif de RAPIDS
Parquet très bon — colonnaire, compressé, lisible directement par cuDF
ORC bon
CSV mauvais — le parsage est séquentiel et irrégulier
JSON mauvais — idem, structure imbriquée
Ligne (row-oriented) mauvais — c'est de l'AoS

La règle

Colonnaire, toujours. Un format colonnaire est un SoA : chaque colonne est un tableau contigu, donc coalescé. Un format par lignes est un AoS, avec la perte de coalescence correspondante.

Corollaire : si votre pipeline lit du CSV, la conversion en Parquet est souvent l'optimisation la plus rentable — avant même de penser au GPU.


Résumé du chapitre

À retenir

  • Les opérations analytiques se ramènent aux primitives GPU : réduction, scan, tri. Toutes limitées par la mémoire, où le GPU a 8× d'avance.
  • RAPIDS (cuDF, cuML, cuGraph, cuVS) reproduit les APIs pandas et scikit-learn. 10-50× sur les gros volumes.
  • La capacité VRAM est le mur. Au-delà, PCIe est 52× plus lent que la HBM.
  • Réponses : traitement par morceaux, multi-GPU (Dask), GPUDirect Storage, et le moteur de décompression matériel de Blackwell (LZ4 à 173 Go/s).
  • Le traitement de chaînes est le point faible structurel.
  • La recherche vectorielle est un bon cas GPU ; CAGRA est un index conçu pour GPU, contrairement à HNSW.
  • Format colonnaire obligatoire : Arrow ou Parquet, jamais CSV ni orienté lignes.

Vérifiez que vous avez compris

Une jointure entre une table de 500 Go et une de 2 Go, sur un H100 (80 Go). Comment procéder ?

C'est le cas classique de la jointure par diffusion (broadcast join) :

  1. charger entièrement la petite table (2 Go) en VRAM et y construire une table de hachage ;
  2. diffuser la grande table par morceaux de ~50 Go, sonder la table de hachage pour chaque morceau, écrire les résultats ;
  3. agréger.

Le facteur limitant devient le débit de lecture depuis le stockage. GPUDirect Storage est ici essentiel : il évite un aller-retour par la RAM du CPU.

Si les deux tables dépassent la VRAM, il faut partitionner les deux par clé de jointure (shuffle) et traiter partition par partition — beaucoup plus coûteux, et c'est là que le GPU perd souvent son avantage.

Pourquoi HNSW, la référence CPU en recherche vectorielle, est-il mal adapté au GPU ?

Parce que son parcours est séquentiel et dépendant des données : on part d'un point d'entrée, on examine ses voisins, on se déplace vers le meilleur, on recommence. Chaque étape dépend de la précédente.

Sur GPU, cela signifie : aucun parallélisme au sein d'une requête, accès mémoire dispersés, divergence maximale entre requêtes qui prennent des chemins différents.

CAGRA restructure le problème : un graphe de degré fixe, où chaque étape examine tous les voisins d'un ensemble de candidats en parallèle. Le parallélisme est dans la largeur de l'exploration, pas dans le nombre de requêtes.

Votre pipeline cuDF est 3× plus lent que pandas sur un fichier de 200 Mo. Normal ?

Oui, très probablement. 200 Mo est trop petit pour amortir :

  • le transfert PCIe (~4 ms) ;
  • le lancement des noyaux ;
  • l'initialisation du contexte CUDA (plusieurs centaines de millisecondes au premier appel).

Le seuil de rentabilité de RAPIDS se situe généralement autour du gigaoctet, et il monte si le pipeline fait beaucoup d'allers-retours vers le CPU.

Vérifiez aussi qu'aucune opération ne retombe silencieusement sur le CPU — c'est fréquent avec cudf.pandas, dont le repli est transparent et donc invisible.


Chapitre suivant : 4 · Signal et image


Sources de ce chapitre