Nucleus
Performance & native

Benchmarks

Résultats de benchmark cross-runtime mesurés — une suite de style Geekbench exécutée dans une vraie application desktop Compose sur JVM JIT, GraalVM Native Image, SwiftUI, Tauri et Flutter.

L'exemple benchmark-demo exécute une suite de style Geekbench — 13 kernels CPU, des montées en charge de rendu géométriques et un bench de chargement de liste — à l'intérieur d'une vraie application desktop Compose, puis réimplémente les mêmes kernels à l'identique en SwiftUI, Tauri et Flutter. Chaque variante exécute la même suite sur la même machine, donc les chiffres sont directement comparables. Cette page présente les résultats mesurés.

Contexte

  • Date : 2026-07-16
  • Machine : Apple M4, 10 cœurs, sur secteur, thermiquement stable
  • Toolchains : Oracle GraalVM 25.1.3+9.1 (Java 25.0.3), OpenJDK 26.0.1, daemon Gradle JBR 21
  • Protocole : chaque variante exécute elle-même sa suite (3 warmups écartés, puis best-of-5 sur les kernels CPU). Les exécutions sont strictement séquentielles, une application à la fois ; le pic de RSS est échantillonné pendant chaque exécution. Les self-checks intégrés passent partout.

Les scores composites ne sont comparables qu'au sein d'une suite identique. Chaque valeur ci-dessous provient de la même suite et de la même session machine. CPU et GFX : plus c'est haut, mieux c'est. list, pic de RAM et taille de l'app : plus c'est bas, mieux c'est.

Résumé

Trié par score CPU composite.

#VarianteRuntimeCPUGFXlist (ms)Pic RAMTaille app
1jvm-graalGraalVM 25.0.3 JIT + ProGuard146.71304121.0695 Mo160 Mo
2tauriRust + WebView (WKWebView)142.215013233.0794 Mo †5.6 Mo ‡
3jvm-c2-pgOpenJDK 26 C2 + ProGuard140.41304120.9616 Mo119 Mo
4swiftuiSwift/LLVM + SwiftUI138.71525414.4268 Mo0.34 Mo ‡
5jvm-c2OpenJDK 26 C2 (sans ProGuard)138.51304121.6620 Mo136 Mo
6aot-o3-pgoGraalVM Native -O3 + PGO132.71385917.1269 Mo129 Mo
7aot-o3GraalVM Native -O3 (inféré par ML)100.81385917.1297 Mo174 Mo
8aot-o2GraalVM Native -O286.91123917.2278 Mo150 Mo
9aot-osGraalVM Native optimisé taille (-Os)80.11043317.3326 Mo129 Mo
10flutterDart AOT + Impeller57.31513317.2196 Mo37 Mo

Points clés

  • CPU brut. GraalVM JIT est en tête (146.7). Les baselines LLVM (Tauri 142, SwiftUI 139) et OpenJDK C2 (138–140) sont groupées. GraalVM Native ne rejoint le peloton JVM/LLVM qu'avec le PGO (100.8 → 132.7) ; sans profil, matmul s'effondre (3877 contre 12225 MFLOP/s). -O2 et -Os restent nettement derrière.
  • Le sweet spot du PGO. aot-o3-pgo atteint un CPU proche de la JVM (132.7) avec 2,5× moins de RAM (269 Mo contre 616–695 Mo), un .app compact (129 Mo) et un démarrage rapide. Le coût : le flux PGO (build instrumenté → exécution GUI → rebuild). Le PGO réduit aussi l'image (174 Mo → 129 Mo).
  • RAM. Flutter est le plus léger (196 Mo), devant SwiftUI (268) et GraalVM Native (269–326). Les JVM sont à 616–695 Mo. Tauri est le plus lourd (794 Mo) une fois l'arbre de processus WebKit compté (†).
  • Démarrage / liste. Natif ~17 ms, JVM ~21 ms, SwiftUI 14 ms (le meilleur), Tauri 233 ms (rendu de liste DOM/canvas WebView — un ordre de grandeur plus lent).
  • CPU le plus bas : Flutter (57.3) : raytracer au quart du peloton, matmul/sha/sieve faibles — mais compensé par un rendu de premier plan (GFX 15133).

RAM de Tauri — le piège WebView multi-processus (†)

Tauri/WKWebView est multi-processus sur macOS. Le canvas et le JS tournent dans des processus WebKit séparés (com.apple.WebKit.WebContent, .GPU, .Networking), pas dans le binaire de l'app. Le RSS du processus principal seul est de 177 Mo, mais l'empreinte réelle — en sommant l'arbre de processus WebKit — est de 794 Mo, ce qui fait de Tauri la variante la plus lourde en RAM, pas la plus légère. (Sommer les RSS surcompte légèrement les pages partagées de WebKit.framework, donc 794 Mo est une borne haute ; l'écart 177→794 est large et réel.)

Taille de l'app — autonome vs runtime système (‡)

Les variantes autonomes embarquent leur propre runtime, donc leur poids est le .app complet (runtime + Skiko/dylibs + jars/binaire) : JVM (jlink), GraalVM Native, Flutter. SwiftUI et Tauri s'appuient sur le runtime de l'OS — SwiftUI sur le SwiftUI/AppKit système, Tauri sur le WebKit système — donc leurs binaires (0.34 / 5.6 Mo) excluent le moteur fourni par macOS. Les deux classes de taille ne sont pas directement comparables.

Détail CPU par kernel

Débit, plus c'est haut, mieux c'est.

Kerneljvm-graaltaurijvm-c2-pgswiftuijvm-c2aot-o3-pgoaot-o3aot-o2aot-osflutter
mandelbrot4.094.134.333.923.991.983.321.973.273.61
nbody700.6693.2639.6659.4691.3694.7683.0654.8678.3608.7
raytracer17.219.818.919.819.017.515.814.07.04.2
matmul1421716224166901621516724122253877324431053054
blur93.444.559.780.749.291.549.546.636.530.0
sha256332.9442.1361.2360.3361.7326.9296.8294.9268.2192.4
sieve708.5642.3565.9603.6599.9725.9467.2463.2484.4268.6
fft407.8452.7441.5436.9441.1363.9369.6376.3356.8366.9
pi0.090.110.110.110.100.100.090.090.090.08
mandelbrot_mt15.516.515.616.116.114.514.17.512.210.6
raytracer_mt74.581.268.675.067.271.460.249.925.513.7
matmul_mt6208869442640383301363925601131998817255159569731
blur_mt345.0188.4244.1261.7238.3285.9203.5194.4155.140.0

La signature du compilateur Graal (JIT comme AOT+PGO) : fort sur blur/sieve, terne sur fft/sha. La régression PGO connue sur mandelbrot se reproduit (1.98 avec le profil contre 3.32 sans).

Montées en charge de rendu

Charge maximale soutenue à ≥ 55 fps, plus c'est haut, mieux c'est.

VarianteParticulesÉtoilesTextes
swiftui125000181753906
aot-o3 / o3-pgo75000145406102
jvm (×3)50000181756102
flutter50000181759533
aot-o250000116326102
aot-os5000093066102
tauri250001817518618

Reproduire

terminal
cd examples/benchmark-demo

# Matrice JVM + natif (RAM homogène) :
JAVA_HOME=<jbr-21> GRAALVM_HOME=<graalvm-25> JDK_C2_HOME=<jdk-26> \
  ONLY="jvm-c2 jvm-c2-pg jvm-graal aot-os aot-o2 aot-o3 aot-o3-pgo" ./run-all.sh

# ports :
ONLY="swiftui tauri flutter" ./run-all.sh

Les builds natifs doivent tourner avec JAVA_HOME=<graalvm> (la JVM courante doit être GraalVM). Sinon, un JDK Oracle 25 provisionné par Gradle mais sans native-image peut correspondre au spec vendor=ORACLE, version=25 et être sélectionné, faisant échouer la compilation. Chaque variante écrit un JSON de résultats ; l'annexe complète par variante est dans le RESULTS.md de l'exemple.

Et ensuite

  • Aperçu GraalVM — ce que native-image apporte à une app Nucleus.
  • Configuration — configurer le profil PGO derrière le résultat aot-o3-pgo.
  • Cache AOT — le démarrage JDK 25+ sur le chemin JVM.