Aller au contenu principal

Budgets de Performance

AppCore maintient un benchmark reproductible entre sous-systèmes afin que les corrections de concurrence et de persistance utilisent les mêmes charges V1.

appcore-dev cert bottlenecks

La commande en profil release écrit builds/certification/bottlenecks.json. Le rapport contient le commit exact, l'état dirty, la toolchain, le système, l'architecture, p50/p95/p99, le débit, le temps total et le pic de mémoire résidente. Il compte aussi les octets demandés au heap Rust, les opérations d'allocation/désallocation, le pic vivant et la rétention par sous-système. Le CI Linux et Windows exécute le même gate et publie l'artefact JSON.

Le RSS reste obligatoire car les compteurs Rust excluent les métadonnées de l'allocator, les bibliothèques natives, les memory mappings, les buffers kernel et la mémoire des devices. La saturation des compteurs échoue fermée. Chaque workload fixe est limité à 64 Mio de delta de heap vivant et 4 Mio de croissance retenue ; le processus complet conserve les plafonds de catastrophe RSS et heap plus larges. La première calibration release Apple M1 a observé un pic vivant de 29 476 637 octets et 139 611 octets de croissance retenue du heap Rust.

Peer RPC rapporte des intervalles d'allocation séparés pour V1, le stream V2, les codecs V2 et les erreurs typées. Le base64 JSON avec scratch fixe et le décodage emprunté ont réduit les octets demandés de 8,75 % sur le workload complet, 7,20 % sur le stream V2 et 21,36 % sur les codecs dans des runs appariés Apple M1. Le pic et le heap retenu ne changent pas; les opérations d'allocation augmentent de 5,44 % et le p99 stream de 1,69 %, donc le rapport conserve ce compromis sans confondre churn et mémoire résidente. Le transfert d'ownership des chunks identity entre encoder, frame et assembler a réduit les octets demandés par le stream de 64 Mio de 1 072 617 252 à 938 399 524 (-12,51 %) et les allocations de 7,39 %, avec +0,22 % au p99 et -0,21 % au RSS de pic du processus. Le workload fixe échoue maintenant au-delà Ce checkpoint d'ownership échouait au-delà de 960 Mio demandés cumulativement. L'attribution par phase a ensuite montré 662 732 479 octets demandés pendant l'encodage. Une sonde fixe d'incompressibilité sur stack a réduit le total du stream de 938 404 175 à 342 886 735 (-63,57 %) et les allocations de 47,83 %. Deux runs de la sonde complète ont amélioré le p99 de 15,38 à 16,14 %, tout en gardant gzip pour les fixtures compressibles. Le gate est maintenant de 384 Mio.

SQLite rapporte des intervalles d'allocation séparés pour startup, append, lecture ponctuelle, construction des fixtures, enqueue outbox, backup et integrity check. L'enqueue de 512 petits records est borné à 2 Mio demandés au heap Rust et 250 ms p99. Le scratch ajusté du BLOB incrémental a réduit les octets demandés par le workload complet de 578 081 344 à 8 251 670 (-98,57 %) et le delta de heap vivant de 1 083 528 à 233 600 octets (-78,44 %) ; l'enqueue a demandé 255 676 octets, sans croissance retenue, et mesuré 141 791 ns p99.

Charges fixes

  • startup manifest-first et dispatch concurrent des commands et queries ;
  • enqueue, lecture et ACK de l'outbox près de 1, 10 et 64 MiB, plus comparaison de matérialisation entre snapshot complet et page bornée sur 256 messages ;
  • contention du routing state Gateway avec 1, 100 et 1 000 tenants, plus une sonde d'indépendance des verrous entre tenants ;
  • 32 échanges HTTP/1.1 séquentiels sur une seule connexion keep-alive acceptée ;
  • encodage, décodage, intégrité et replay JSON/base64 et binaire/natif Peer RPC de 1 KiB à 4 MiB, plus 4 096 round trips de rejet V2 typé ;
  • startup du scheduler et lots bornés de 64 tasks arrivées à échéance.

Les fixtures ne contiennent aucun secret statique. Chaque exécution obtient du matériel secret temporaire depuis la source aléatoire du système d'exploitation.

Utilisation des budgets

Les plafonds portables empêchent les régressions sur les runners CI partagés. Ils ne constituent pas une promesse de performance en production. Chaque correction doit préserver V1, fournir un avant/après, ajouter un invariant de comportement et resserrer le budget concerné lorsque le résultat est stable.

La baseline initiale indiquait une concurrence maximale de 1 pour les handlers de commands et queries. AC-001 retire l'exécution des command handlers du mutex partagé du host. Le gate exige maintenant le chevauchement d'au moins quatre workers sur huit ; les tests déterministes exigent l'entrée simultanée des huit workers, préservent une seule exécution pour une clé idempotente identique et vérifient le drainage au shutdown. AC-002 retire aussi l'exécution des query endpoints du mutex du host et applique le même gate de quatre workers sur huit. Son test déterministe gèle le registre et exige le chevauchement des huit appels d'endpoint.

AC-003 remplace la map publique globale des tenants Gateway par un répertoire borné de 32 shards et un verrou par tenant. Le gate conserve le verrou d'écriture d'un tenant tout en exigeant que celui d'un autre tenant reste disponible. Conserver l'ancienne map rétablirait la sérialisation ou dupliquerait l'état mutable ; cette correction reste donc bloquée dans le RC jusqu'au rétablissement de la compatibilité 1.x et l'ancien champ est supprimé.

AC-004 supprime le mutex global des métadonnées de requests en attente. Une map privée et bornée par tenant conserve le channel de réponse, la génération du worker, la deadline et la limite de réponse dans la même entrée. Les tests déterministes exigent le cleanup après réponse, réponse invalide, timeout, annulation, shutdown, remplacement et déconnexion du worker ; une génération stale doit préserver l'entrée actuelle.

AC-005 ajoute un client HTTP réutilisable avec admission par origine, connexions inactives et rétention des origines bornées. Les délais de connexion/admission, de lecture et d'écriture sont indépendants. Seules les réponses entièrement cadrées et analysées reviennent au pool ; tout échec ou toute réponse non réutilisable élimine le socket. Le gate exige les 32 échanges sur la même connexion acceptée. L'adaptateur V1 libre send reste one-shot avec Connection: close.

AC-007 remplace le reload/rewrite complet de l'outbox par le journal append-only V2 explicite dans la version candidate 1.0.2-rc. Les charges de 1/10/64 MiB incluent désormais un petit enqueue incrémental du tail limité à 100 ms p99, tandis que l'ACK est limité à 500 ms p99. La compaction atomique change la génération ; les tests exigent la récupération d'une frame finale incomplète et un échec fermé pour corruption complète, frames dupliquées/réordonnées et versions incompatibles.

AC-011 ajoute des index directs par tenant, Core ID et (cluster_id, core_id). Le gate effectue 16 384 lookups parmi le maximum de 1 024 workers enregistrés et exige au plus 1 ms p99, au moins 10 000 lookups/s et zéro incohérence. Les tests reconnect, disconnect et prune heartbeat exigent qu'une génération stale ne supprime jamais l'entrée actuelle.

AC-018 remplace un thread par exécution du scheduler par un pool fixe et une file bornée. Le gate de 64 tasks exige que la concurrence des callbacks et les noms distincts des threads workers restent dans max_concurrent_tasks, tout en observant au moins un événement borné de saturation de la file. Le travail excédentaire est différé sans consommer de tentatives de retry.

AC-020 ajoute le contrat de télémétrie Gateway de 1.0.2-rc. Le gate conserve 128 séries de capability, agrège huit noms supplémentaires dans une série d'overflow fixe, exécute 4 096 routes instrumentées sans worker disponible et construit 256 snapshots. Il exige zéro route inflight résiduelle, une cardinalité et un overflow exacts, un p99 de route inférieur ou égal à 1 ms et un p99 de snapshot inférieur ou égal à 5 ms. L'exécution propre macOS/aarch64 au commit d'implémentation 31c4fbe a mesuré 1 792 ns p99 pour la route et 5 792 ns p99 pour le snapshot. L'export est une frontière pull explicite du deployment et n'est jamais appelé par le routage.

AC-021 valide la matrice complète des erreurs typées, le décodage V1 exact et 4 096 round trips encode/décode/validation d'un rejet V2. Le gate exige un p99 d'au plus 1 ms et au moins 1 000 opérations/s. Le run macOS/aarch64 propre à d11befe a mesuré 750 ns p99 et 1 405 708 opérations/s, avec un pic RSS total de 298 672 KiB. Les artefacts CI Linux et Windows restent l'autorité plateforme.

AC-012 remplace la sélection aléatoire par processus par les policies stables FirstAvailable, RoundRobin, LeastInflight, HealthWeighted et Affinity stateless. Le gate enregistre 64 workers, exige exactement quatre sélections round-robin par worker, vérifie les invariants health, capacity et affinity, et exécute 16 384 sélections par policy mesurée. Chaque policy est plafonnée à 1 ms p99 et doit dépasser 10 000 sélections/s. L'exécution finale propre macOS/aarch64 au 7caddc1 a mesuré 17 125 ns p99 pour round-robin, 18 542 ns pour least-inflight et 38 083 ns pour affinity.

AC-013 ajoute 4 096 lookups du registre partagé et trois rounds complets de recovery avec 1, 100 et 1 000 tenants, puis 64 requests réussies dans chaque route fenced locale réelle et route fédérée V2 authentifiée. Le lookup est plafonné à 5 ms p99 et doit dépasser 500/s; le recovery est plafonné à 5 s; la route locale à 50 ms p99 et 100/s; la fédération à 250 ms p99 et 20/s. Le run macOS/aarch64 propre à 7197416 a mesuré au plus 667 ns p99 de lookup, 2,25 ms p99 de recovery, 0,35 ms p99 de route locale et 0,91 ms p99 de route fédérée. Les tests Redis, proxy externe et perte d'owner restent des preuves séparées; les artefacts Linux et Windows restent requis.

AC-014 ajoute une représentation binaire opt-in explicite aux DTO Peer RPC V2 existants tout en préservant les fixtures JSON/base64 exactes et toutes les routes V1. Le gate exige que les octets du body binaire restent à 80 % ou moins du JSON, que le p99 du codec binaire ne dépasse pas celui du JSON et que le buffer borné reste à 90 % ou moins du JSON. Le run macOS/aarch64 propre à 6f3bc38 a mesuré 25 % d'octets body en moins, un p99 codec réduit de 93 % et un buffer réduit de 14 % entre 64 Kio et 4 Mio; le pic RSS total était de 306 448 Kio. L'absence du support binaire échoue sans retry JSON. Les artefacts Linux et Windows restent requis.

AC-015 ajoute des pages outbox bornées par nombre/octets, des stats sans payload, une readiness retry durable et des receipts partiels exacts. Le follower et la CLI Runtime ne matérialisent plus toute la file. L'exécution propre macOS/aarch64 au commit c904e83 a matérialisé 460 684 octets pour une page de sept messages contre 30 021 820 octets pour le snapshot complet de 256 messages, soit 98,46 % de réduction. Le p99 de page était de 71 458 ns contre 1 404 417 ns ; le p99 des stats était de 54 542 ns et le pic RSS total de 244 752 Kio. Le wire peer V1 reste inchangé ; les artefacts Linux et Windows restent requis.

Suivez le benchmark dans AC-022 public et la correction des commands dans AC-001 public. La correction des queries est suivie dans AC-002 public. La correction Gateway est suivie dans AC-003 public. L'ownership des requests en attente est suivi dans AC-004 public. La réutilisation des connexions HTTP est suivie dans AC-005 public. La correction du journal outbox est suivie dans AC-007 public. L'index direct des workers est suivi dans AC-011 public. Le pool fixe du scheduler est suivi dans AC-018 public. La télémétrie Gateway bornée est suivie dans AC-020 public. La sélection bornée des workers est suivie dans AC-012 public. La HA Gateway est suivie dans AC-013 public. Le framing binaire Peer RPC est suivi dans AC-014 public. La pagination outbox bornée est suivie dans AC-015 public. Les artefacts plateforme restants de l'erreur wire typée sont suivis dans AC-021 public.