Actualités

Mojo 1.0 passe en Apache 2.0 sous pavillon Qualcomm : faut-il sortir vos kernels GPU de CUDA ?

Le 18 août 2026, Modular a publié le code du compilateur Mojo et de son outillage sous Apache 2.0 avec exceptions LLVM, une semaine après Mojo 1.0 et trois semaines après la clôture du rachat par Qualcomm. Cet article démonte ce qui est réellement ouvert, ce que garantit (et ne garantit pas) la 1.0, et propose une grille de décision chiffrée face à CUDA et Triton, assortie d'un plan d'évaluation de deux semaines.

| | | 10 min de lecture · par
Illustration d'un flux de compilation de kernels GPU se ramifiant vers plusieurs architectures matérielles

L’ouverture d’un compilateur est rarement un non-événement. Quand elle survient une semaine après la première version stable du langage et trois semaines après le rachat de l’éditeur par un fondeur de silicium, elle mérite une lecture d’ingénieur plutôt qu’un enthousiasme de timeline. Voici ce qui a changé, ce qui n’a pas changé, et comment décider — avec un plan d’évaluation qui n’engage pas votre production.

Ce qui a réellement changé le 18 août

L’ouverture de Mojo s’est faite par couches successives. La bibliothèque standard est passée en open source en 2024, suivie des kernels du runtime MAX. Le compilateur lui-même — la pièce qui contient l’essentiel de la valeur d’ingénierie, l’intégration MLIR, les passes d’optimisation et la génération de code pour les cibles GPU — restait fermé. C’est cette dernière brique qui vient d’être publiée, accompagnée de l’outillage (formateur, LSP, tests) et de la chaîne de build Bazel du monorepo.

La licence retenue est Apache 2.0 avec exceptions LLVM. Ce détail n’est pas cosmétique. L’Apache 2.0 « nue » impose des obligations d’attribution et de notice qui se propagent aux binaires redistribués : dans un contexte de compilateur, cela signifie que tout exécutable contenant des fragments de runtime ou de bibliothèque produits par la chaîne d’outils traîne un fardeau de conformité. L’exception LLVM neutralise précisément ce problème pour le code embarqué par le compilateur dans les artefacts qu’il génère, et clarifie le cas de l’édition de liens statique. Concrètement : vous pouvez distribuer un binaire propriétaire compilé avec Mojo sans devoir joindre les notices Apache de la toolchain. C’est le même arbitrage que celui fait par LLVM lui-même, et c’est la condition sine qua non d’une adoption industrielle.

Reste le périmètre. Trois limites méritent d’être posées noir sur blanc :

  • Les contributions externes au compilateur ne sont pas acceptées à ce stade. Modular annonce une ouverture ultérieure du processus. En clair : le code est lisible, forkable, auditable — il n’est pas co-développé.
  • Un compilateur prébuild reste nécessaire pour certains scénarios de personnalisation de kernels MAX, ce qui complique le bootstrap purement source.
  • Il n’existe pas de fondation indépendante : la marque, le dépôt et la roadmap restent chez Modular, donc chez Qualcomm.

« Open source » n’est pas « développement ouvert ». La distinction change tout pour une analyse de risque.

Le contexte Qualcomm : lire l’annonce en analyste

La chronologie parle d’elle-même : annonce du rachat en juin 2026, clôture le 29 juillet pour environ 3,9 milliards de dollars, Mojo 1.0 les 11-12 août, ouverture du compilateur le 18 août. Trois jalons structurants en trois semaines, sous nouvelle propriété.

L’hypothèse la plus charitable — et la plus probable — est que l’ouverture était planifiée de longue date et que l’acquisition l’a accélérée : un fondeur qui veut faire adopter sa stack logicielle a tout intérêt à lever la barrière de la confiance. L’hypothèse à ne pas écarter est celle du biais de roadmap. Les questions à poser avant d’engager un budget :

  • Qui arbitre les priorités entre backends ? Un bug de génération de code sur Hopper ou sur CDNA sera-t-il traité avec la même urgence qu’un bug sur un accélérateur Qualcomm ?
  • Quelle est la cadence de release réelle, et est-elle publique ?
  • Existe-t-il un engagement écrit sur la neutralité des backends, ou seulement une intention ?

Le garde-fou réel, c’est l’Apache 2.0 : le fork est juridiquement possible. Techniquement, il faut être lucide. Forker un compilateur MLIR de cette taille suppose une équipe capable de suivre l’upstream LLVM, de maintenir les backends de génération de code pour au moins deux ISA GPU et d’assurer la sécurité de la chaîne. C’est un investissement de plusieurs ingénieurs à temps plein, pas un plan B pour une équipe de dix personnes. La licence protège l’écosystème ; elle ne protège pas une PME.

Mojo 1.0 : les garanties, et les ruptures à absorber

Après trois ans de ruptures d’API assumées, la 1.0 apporte enfin un contrat. Il faut en lire les termes précisément : le semver s’applique aux API explicitement marquées comme stables, pas à l’intégralité de la surface du langage. Ne sont notamment pas couverts la stabilité de l’ABI et une partie de l’outillage. Autrement dit, vous pouvez raisonnablement figer une dépendance de bibliothèque ; vous ne pouvez pas encore construire un modèle de distribution binaire multi-versions.

La rupture la plus visible pour qui écrit des kernels est le déplacement des API GPU hors de la stdlib, vers le paquet max :

# Mojo 0.x
from gpu import thread_idx, block_idx, barrier
from gpu.host import DeviceContext
from algorithm import vectorize
from layout import Layout, LayoutTensor

# Mojo 1.0
from max.gpu import thread_idx, block_idx, barrier
from max.gpu.host import DeviceContext
from max.algorithm import vectorize
from max.tensor import Layout, LayoutTensor

Le mouvement est cohérent : la stdlib redevient un socle langage, et tout ce qui touche à l’accélération matérielle vit dans MAX, où il peut évoluer à son propre rythme. Pour vos bases de code, c’est un sed bien conçu suivi d’une revue — mais planifiez la revue, certains symboles ont été renommés en même temps qu’ils étaient déplacés.

Le second changement est plus intéressant conceptuellement : Int et UInt ne peuvent plus être passés à un kernel GPU. Il faut désormais des types à largeur fixe.

# Refusé en 1.0 : Int a une largeur dépendante de la cible
fn saxpy(a: Float32, x: UnsafePointer[Float32],
         y: UnsafePointer[Float32], n: Int):
    ...

# Correct : contrat de largeur explicite entre hôte et device
fn saxpy(a: Float32, x: UnsafePointer[Float32],
         y: UnsafePointer[Float32], n: Int32):
    var i = block_idx.x * block_dim.x + thread_idx.x
    if i < UInt32(n):
        y[i] = a * x[i] + y[i]

C’est la bonne décision. Int est un entier de la largeur du pointeur natif ; sur une frontière hôte/device où l’hôte est en 64 bits et où le device peut avoir un modèle différent, un type implicite est une bombe à retardement silencieuse. La contrepartie est un coût de migration réel sur du code existant : chaque signature de kernel, chaque structure partagée et chaque calcul d’index doit être audité. Traitez cela comme une migration de types, pas comme un renommage.

Enfin, ce qui manque encore côté langage doit peser dans votre décision : pas de modèle async arrêté, pas de pattern matching, pas d’unions étiquetées, et le support Windows toujours en chantier. Pour du code de kernel, ces absences sont supportables ; pour écrire l’orchestration applicative autour, beaucoup moins.

Grille de décision : Mojo, Triton ou CUDA ?

Le débat devient enfin chiffrable. Une étude d’Oak Ridge National Laboratory place les kernels Mojo autour de 87 % des performances CUDA sur H100 pour des charges memory-bound, avec une variabilité notable selon les kernels. À titre de comparaison, les chiffres couramment rapportés pour Triton sur charges ML se situent dans une fourchette de 90 à 105 % de CUDA — parfois au-dessus, quand l’autotuning trouve mieux qu’un kernel écrit à la main non optimisé.

Deux précautions d’interprétation. D’abord, « memory-bound » est le régime le plus favorable à un langage de haut niveau : la performance y est dominée par le pattern d’accès mémoire, pas par la capacité du compilateur à saturer les Tensor Cores. Sur du compute-bound dense, l’écart peut se creuser sensiblement. Ensuite, 13 % de perte sur un kernel qui représente 5 % de votre temps d’inférence, c’est du bruit ; sur le kernel d’attention d’un service à 200 GPU, c’est une ligne budgétaire.

Situation Recommandation
Kernel critique, parc 100 % NVIDIA, marge de perf inexistante CUDA. Rien ne le remplace sur ce créneau.
Charges ML classiques (attention, fusions element-wise, normalisations) sur NVIDIA Triton. Maturité, écosystème, intégration PyTorch.
Besoin réel de portabilité NVIDIA / AMD / Apple / accélérateurs tiers Mojo mérite l’évaluation. C’est son argument différenciant.
Équipe sans expertise GPU, à monter en compétence Triton d’abord. La courbe est plus douce et les ressources plus nombreuses.
Base HPC scientifique existante en CUDA/HIP, forte Statu quo. Le coût de portage n’est pas amorti par 87 %.

Le coût caché est ailleurs que dans les FLOPS : maturité de l’écosystème de paquets, recrutement (le vivier Mojo est étroit), outils de débogage et de profilage moins riches qu’un ncu mature, intégration CI à construire. Et un point de communication interne : Mojo n’est plus vendu comme un surensemble de Python. Ne promettez pas à votre direction une migration Python indolore ; c’est un langage systèmes distinct, avec ownership et typage strict.

Enfin, la question de lock-in mérite d’être retournée. Sortir de CUDA pour entrer dans un écosystème contrôlé par un autre fondeur n’est un gain que si l’engagement multi-backend est tenu dans la durée. Le test n’est pas la licence : c’est la qualité du backend AMD dans dix-huit mois.

Plan d’évaluation en deux semaines

Une évaluation sérieuse tient en dix jours-homme et ne touche pas la production.

Semaine 1 — mesurer sur votre charge. Buildez le compilateur depuis les sources, ou passez par la configuration prébuild si le temps de build devient un obstacle :

git clone https://github.com/modular/modular
cd modular
# Build complet depuis les sources
bazel build //...
# Alternative : s'appuyer sur un compilateur prébuild
bazel build --config=prebuilt-mojo //...

Portez ensuite un kernel memory-bound représentatif de votre charge réelle. Pas un GEMM de démonstration, pas un benchmark d’éditeur : votre kernel, avec vos tailles de tenseurs et vos patterns d’accès. Mesurez sur votre matériel, avec votre baseline CUDA ou Triton, et instrumentez au niveau du kernel :

# Baseline CUDA/Triton
ncu --set full --kernel-name-base function \
    -o baseline_cuda ./bench_cuda

# Candidat Mojo, mêmes tailles, même GPU
ncu --set full -o candidate_mojo ./bench_mojo

# Comparer : bande passante DRAM atteinte, occupancy, stalls mémoire

Le chiffre qui compte est la bande passante DRAM effective rapportée au pic théorique, pas le temps mural d’un script.

Semaine 2 — éprouver la promesse. Recompilez le même kernel pour une seconde cible matérielle. Chronométrez le temps de portage à la minute près et notez chaque modification nécessaire. C’est la seule mesure honnête de la portabilité : si elle est nulle, l’argument central de Mojo est validé ; si elle demande trois jours de contorsions par cible, vous avez juste changé de dialecte.

Rédigez vos critères de go/no-go avant de commencer — par exemple : perte de performance inférieure à 10 % sur le kernel cible, portage vers la seconde cible en moins d’une journée, aucun blocage de compilation sans contournement documenté. Puis surveillez trois signaux sur six mois : ouverture effective des contributions au compilateur, régularité des releases, et apparition (ou non) d’une gouvernance tierce.

Verdict

Aujourd’hui, Mojo est déjà pertinent pour deux profils. Les équipes dont la contrainte n°1 est la portabilité matérielle — celles qui provisionnent sur AMD parce que les H100 sont indisponibles ou trop chers, celles qui ciblent des accélérateurs non-NVIDIA — ont désormais un candidat crédible, mesurable et auditable. Les équipes de recherche en compilation et en HPC ont, elles, un compilateur MLIR de production sous licence exploitable : c’est un objet d’étude rare.

Pour tous les autres, la réponse raisonnable est « à revoir dans un an ». Le contrat de stabilité de la 1.0 ne couvre pas encore l’ABI, les contributions externes au compilateur restent fermées, et l’écosystème de paquets ne soutient pas la comparaison avec celui de Python ou de Triton. Le vrai jalon à guetter n’est ni la licence ni le prochain benchmark : c’est le jour où un correctif de génération de code proposé par un contributeur externe, sur un backend non-Qualcomm, sera mergé dans les mêmes délais qu’un correctif interne. Ce jour-là, la question du fondeur cessera de se poser.

Commentaires (0)

Veuillez vous connecter pour laisser un commentaire.

Se connecter

Pas encore de commentaires. Soyez le premier à commenter !