Preserve formatted NAND boot and Wii Remote pairing, add DMA/SRAM conformance tests and a Wii comparison probe. Keep P1 profiling tools and native update A/B evidence; reject the unhelpful targeted SRAM shortcut.
20 KiB
Protocole P1 — attribuer les ralentissements Wii LLE
Date : 19 septembre 2026. Statut au 22 septembre : capture noyau locale validée ; coût du collecteur, cas PPC et chemin critique Wii non qualifiés. Aucune nouvelle mise à jour n'est lancée par la rédaction de ce document. Il remplace la stratégie « modifier, refaire une mise à jour, comparer les FPS ».
1. Question et règle de décision
Sur les passages réellement lents, déterminer quel travail ou quelle attente retarde la progression de l'émulation, dans quelles fonctions, et pour combien de temps. Le résultat attendu n'est pas « un cœur à 100 % », mais une attribution vérifiable.
Une seule exécution de diagnostic est prévue après qualification du dispositif. Aucun nouveau correctif de performance avant un rapport d'attribution exploitable. Une capture incomplète ne justifie pas un correctif au hasard : on répare le dispositif, et on précise quelle information manque avant d'envisager une capture complémentaire. Une seule cause est ensuite traitée ; la validation porte d'abord sur sa charge locale.
2. Pourquoi A–F ne suffisent pas
- Les instantanés espacés d'environ 10 secondes ne décrivent ni les pics ni leurs piles.
- Les FPS échantillonnés ne sont pas une distribution des temps de frame.
- Un nombre d'accès mémoire ou d'instructions JIT ne mesure pas leur coût CPU.
ARMCore::RunCyclescontient égalementm_bus.AdvanceCycles: son temps inclusif ne doit pas être présenté intégralement comme du calcul ARM.AdvanceCyclesappelle les périphériques, dont OHCI et le réseau : additionner ces temps imbriqués compterait plusieurs fois le même travail.Sampler.cpputiliseSuspendThread/ResumeThread; ses observations historiques ne deviennent pas une référence de temps sans perturbation.- Le lecteur F ne résout pas certaines adresses JIT. Une annotation absente n'est ni zéro travail JIT ni une preuve que tous les autres offsets sont incorrects.
- Les 600–2 700 Mo de journal sont des repères approchés, pas une charge identique.
- La durée entre messages utilisateur n'est pas la durée exacte de la mise à jour.
- Les conditions hôte/serveur diffèrent. F est observé plus lent que E, mais la cause n'est pas isolée. Répéter simplement F avec un autre réglage ne résout pas cela.
3. Geler le scénario, sans toucher aux NAND existantes
Le diagnostic concerne le ralentissement actuel : source actuelle figée correspondant au comportement F, profilage détaillé des accès désactivé, sans nouvelle optimisation. Créer une build de diagnostic propre, non incrémentale, et ne pas remplacer les builds figées D/E/F. Conserver le patch et les empreintes des sources, y compris les fichiers non suivis utilisés, options de compilation, compilateur, EXE, PDB et paramètres. Vérifier l'identité EXE/PDB ; cela ne suffit pas, à elle seule, à valider un lecteur de types.
Utiliser un nouveau profil depuis la graine pré-mise à jour déjà vérifiée :
SHA256 07b2f4bc543cfd4203efc448538505e9d503b2727c16aaff8d8c0b286d8b4f0c.
Conserver les mêmes réglages Wii, réseau NAT, rendu, vitesse 100 %, horloges invitées,
SD et persistance. Noter les différences de chemins et rien d'autre.
Un démarrage du processus n'implique pas un cache disque Windows froid ; ne pas vider
les caches système, changer l'affinité ou désactiver l'antivirus pour fabriquer un résultat.
Relever au départ et pendant la capture : charge des autres processus, CPU logique utilisé, état d'alimentation, fréquence disponible, mémoire/pression de pagination, disque et GPU. Ne pas lancer de compilation, benchmark, hachage massif, nettoyage ou autre test en parallèle. Ne pas fermer des applications utilisateur sans accord. Si un concurrent perturbe une fenêtre, la signaler et mesurer sa contribution plutôt que l'effacer du rapport.
4. Deux couches de mesure sur la même horloge
A. Profil système Windows, indépendant des layouts C++
WPR, Xperf et WPA sont présents sur cette machine ; wpr -profiles a été vérifié.
Employer un profil ETW ciblé, validé avant le test :
- CPU échantillonné avec piles, cible initiale 1 ms, intervalle réellement utilisé consigné ;
- changements de contexte et réveils, pour séparer Running / Ready / Waiting par thread ;
- chargement des modules, événements disque/fichiers, fautes matérielles de pagination ;
- métadonnées d'activité réseau, sans contenu des paquets ;
- fréquence/puissance si disponibles. Une donnée absente reste « indisponible ».
Les vues CPU échantillonné et CPU précis répondent à des questions différentes : localisation du calcul d'une part, ordonnancement/attentes d'autre part. Les combiner, sans confondre une pile d'attente avec une preuve d'attente disque. Documentation Microsoft
Ne plus utiliser de suspension de thread ou d'attachement au débogueur pour chronométrer. Pas de profilage heap complet, trace de chaque accès mémoire, ni capture de paquets par défaut. Filtrer l'analyse sur le PID/TID exact et conserver les processus concurrents pour expliquer le temps Ready. Ne pas supposer que le PID suffit après un redémarrage : enregistrer sa date de création. Aucun arrêt/annulation d'une session ETW tierce ; vérifier les sessions avant démarrage.
B. Télémétrie native légère, versionnée
Publier les compteurs depuis le code qui les possède ; ne plus les déduire d'offsets PDB
via ReadProcessMemory. Un schéma versionné comporte run_id, version, QPC/fréquence,
PID/TID, génération du cœur/rechargement IOS et des compteurs monotones.
L'export asynchrone est borné ; les débordements sont comptés. Aucune écriture de log
synchrone à chaque instruction ou accès. Ne pas ajouter de verrou partagé au chemin mémoire.
Récupérer les données sur leur thread propriétaire, sans lecture C++ concurrente non synchronisée.
- Temps invité écoulé et cycles ARM/PPC, séparés du temps hôte QPC.
- Temps de frames réellement produites : histogramme p50/p95/p99 et longues frames, rapporté au mode vidéo du profil (50 ou 60 Hz). Une médiane de FPS n'est pas ce calcul.
- Agrégats toutes les secondes ; chronologie d'analyse en fenêtres de 250 ms quand les événements le permettent. Marquer les fenêtres qui n'ont pas assez de données.
- JIT : compilations, invalidations, instructions natives/fallback, accès lents existants, entrées en attente et sorties de slice, avec identifiant de génération après reset.
- NAND : lectures/programmes/effacements, transactions, octets et erreurs ; séparer
sérialisation/hash, appels d'écriture,
IOFile::Flushet attente hôte observée. - Réseau : octets/trames hôte reçus, mise en file NAT, remise USB à IOS, occupation maximale et âge des files. Le débit reçu ne prouve pas le débit consommé par IOS.
Les chronomètres de régions fréquentes sont échantillonnés et calibrés, jamais posés sur chaque accès ARM. Les frontières plus rares (rechargement, compilations, gros transferts) peuvent produire des événements. Éviter un échantillonnage périodique aligné sur la boucle invitée ; conserver le taux de sélection et distinguer estimation et total exact.
C. Rendre les échantillons JIT attribuables
Un PDB décrit le C++ compilé, pas automatiquement le code généré à l'exécution. Exporter, à compilation/invalidation, les intervalles d'adresses hôte du JIT ARM et du JIT PPC, dispatcher/trampolines compris, avec QPC et génération ; pour les blocs, indiquer PC invité, ARM/Thumb et identité du mapping. Ne pas extraire ni publier le firmware. Une adresse réutilisée après vidage du cache doit se résoudre selon la date de l'échantillon.
Classer l'IP feuille même si la pile ne traverse pas correctement une transition JIT/C++.
Ne pas inventer de parent de pile manquant. Garder « pile tronquée » et « code non attribué »
visibles ; ajouter une instrumentation ciblée si ces trous empêchent la décision.
Le support Common::JitRegister existant côté PPC est un point d'intégration à examiner,
pas une garantie que le JIT ARM ou l'unwinding Windows sont déjà couverts.
5. Points d'attribution dans ce dépôt
| Domaine | Points à observer | Preuve recherchée |
|---|---|---|
| Ordonnancement ARM | Starlet::RunSlice, ARMCore::RunCycles |
Coût de dispatch, quanta/s, transitions, temps invité/hôte |
| JIT ARM | ARMJitX64::Run, compilation, code généré, helpers |
Part CPU feuille, blocs invités chauds, recompilations |
| Mémoire ARM | ReadMemorySlow, WriteMemorySlow, traduction, bus |
CPU exclusif des helpers et classes d'accès, pas leur seul nombre |
| Périphériques | StarletMemory::AdvanceCycles, DMA, AES/SHA, OHCI/EHCI |
CPU exclusif par fonction ; attente simulée séparée du travail hôte |
| NAND | CommitNANDPages, NANDJournal::Append, IOFile::Flush |
CPU de préparation vs appels fichiers vs attente disque réelle |
| Réseau | SlirpNetwork::Poll, AX88772, remise OHCI |
CPU NAT/USB, files, progression hôte versus progression invitée |
| PPC / rendu | JIT PPC, threads vidéo, présentation | Concurrence réelle et dépendances de l'émulation, pas seulement FPS |
| Hors émulation | Limiteur, audio, logs, collecteur, Windows | Attente voulue, contention, CPU de diagnostic, temps Ready |
Sur un même thread, présenter les temps exclusifs des régions imbriquées.
Présenter aussi leurs temps inclusifs, mais dans une autre colonne, non additionnable.
Ne pas additionner le CPU de plusieurs threads comme une durée murale de mise à jour.
Pour les attentes, suivre la dépendance qui retarde le thread utile ; un thread GPU qui
attend l'émulation n'est pas une cause de ralentissement GPU.
fflush n'est pas une preuve de vidage physique sur disque : le niveau de persistance
actuel reste inchangé et les attentes sont établies par les événements hôte.
6. Qualification obligatoire, sans demander de mise à jour à l'utilisateur
Avant de dire « lance la mise à jour », un contrôle local court doit démontrer :
- EXE/PDB identifiés ; compteur versionné lu correctement ; horloges alignées ; un reset ne produit pas de deltas négatifs ; pas de perte silencieuse d'événements.
- Une boucle JIT connue est correctement attribuée ARM/PPC ; son coût CPU augmente comme prévu. Un cas d'attente connu est classé Waiting, pas « calcul JIT ».
- Les scopes imbriqués d'un test ont des temps exclusifs cohérents, sans double comptage.
- Un cas de journal synthétique et de réseau local, sans service Nintendo, est visible.
- Mesurer le surcoût ON/OFF du dispositif complet sur la même charge locale, dans le même binaire et en ordre alterné. Budget initial : 2 % de temps mural/CPU, bruit affiché. Ce seuil est une règle de projet, pas une garantie d'ETW. S'il est dépassé ou non résolu par le bruit, alléger les fournisseurs/samples avant le test. Le contrôle ne garantit pas le même surcoût sur toutes les phases natives : relever aussi la charge du collecteur.
Pas de nouveau comportement invité, pas de changement de NAT, timers, JIT, NAND ou SVC. Les boucles SVC/polling éventuelles sont d'abord attribuées à du CPU/PC invité ; aucune émulation accélérée d'appel IOS ne découle d'un simple comptage d'instructions.
7. Une capture native, puis analyse hors ligne
- Vérifier réserve disque et absence de test/build actif. Enregistrer le manifeste.
- Armer ETW et la télémétrie avant de lancer le profil isolé ; confirmer une fenêtre visible et des mesures valides. Ne pas se baser sur les messages utilisateur pour armer.
- L'utilisateur lance une seule mise à jour. Garder 10 s de référence avant l'activité. Tout marquage manuel reste approximatif ; les phases sont reconstruites à partir des événements synchronisés, files réseau, travail invité et commits NAND.
- Téléchargement, calcul et installation peuvent se chevaucher : ne pas leur imposer trois phases exclusives artificielles. Une file vide ne prouve pas une attente serveur.
- Garder environ 10 s après la réussite signalée, puis arrêter uniquement la capture. Ne pas arrêter Dolphin, modifier la NAND ou cliquer à la place de l'utilisateur.
- Garde-fous initiaux : 15 min de capture, budget disque 4 Gio et réserve 5 Gio ; le pilote doit arrêter proprement sa capture si une limite approche, conserver le préfixe et déclarer les phases manquantes. Une trace incomplète n'est pas un échec de la mise à jour.
- Vérifier les événements perdus et le coût du profilage. Ne pas charger WPA ni effectuer une grosse analyse/hachage pendant la mesure. Fermer ensuite Dolphin avec l'utilisateur pour les vérifications NAND, comme pour F.
Les traces en mode fichier sont adaptées à ce scénario contrôlé, mais ajoutent des E/S : les distinguer du journal NAND, relever le volume et ne pas supposer leur coût nul. Les pertes d'événements rendent certaines conclusions impossibles ; les vérifier explicitement. Sessions ETW/WPR — Microsoft
8. Rapport exigé avant tout correctif
Analyser la capture entière et, au minimum, trois fenêtres lentes non chevauchantes de 10 s si elles existent, ainsi qu'une fenêtre rapide de la même exécution. Une fenêtre lente est définie avant analyse : vitesse invitée moyenne < 90 % pendant au moins 2 s ; analyser aussi les longues frames indépendamment. Rapporter l'absence de fenêtres admissibles. Comparer des types d'activité similaires ; ne pas comparer une pause réseau à une installation.
Livrer :
- Chronologie superposant vitesse/frames, CPU Running/Ready/Waiting, NAND et files réseau.
- Top fonctions/piles, part CPU exclusive/inclusive, nombre d'échantillons, contexte invité.
- Temps critique perdu en calcul, Ready et attentes expliquées ; catégories inconnues visibles.
- Coût par unité de travail quand disponible : CPU/transaction, CPU/Mio traité, compilations par instruction, etc. Un compteur n'a de sens que pour la même opération/sémantique.
- Liste des observations qui réfutent les autres pistes ; distinguer preuve et hypothèse.
Gates de qualité initiaux : zéro perte sur les flux indispensables à l'intervalle analysé, au moins 95 % des échantillons CPU Dolphin attribués à un domaine, compteurs intègres et coût de collecte qualifié. Ce sont des critères d'analyse, non des promesses de précision. Une pile incomplète peut permettre de classer un domaine sans identifier sa cause interne : on ne valide alors pas un correctif visant une fonction non résolue. Pas de fausse certitude statistique obtenue en traitant des échantillons temporels corrélés comme des essais indépendants.
Un correctif est admissible seulement si :
- La cause apparaît dans plusieurs fenêtres lentes avec une signature explicable.
- Sa part sur le chemin qui retarde l'émulation est chiffrée, avec son incertitude.
- Un cas local représentatif reproduit cette charge ou cette attente.
- Le gain global plausible est estimé avant modification. Par exemple, supprimer tout un poste responsable de 5 % du temps critique ne retire au mieux que 5 % de cette durée.
- Le correctif garde le comportement matériel et passe les tests ciblés/interpréteur.
Décision pratique : si le CPU est dans les helpers, travailler ces helpers ; s'il est dans le code invité, examiner les blocs et le travail IOS ; si Ready domine, étudier la contention hôte ; si les attentes d'E/S dominent, traiter leur dépendance réelle. Si les files NAT sont pleines mais peu consommées, ne pas accuser le serveur ; si elles sont vides, confirmer l'attente avec les échanges/états disponibles ou laisser la cause ouverte. Si aucun poste ne domine, le rapport le dit : on ne fabrique pas un unique responsable.
9. Validation minimale après diagnostic
D'abord une validation locale répétable du poste identifié, résultat invité exact et même charge. Puis une validation native ciblée du scénario corrigé, pas une série de réglages. La trace de diagnostic peut localiser une cause, mais son temps n'est pas automatiquement une référence équitable face à une build sans instrumentation. Pour revendiquer un gain global, conserver un dispositif équivalent et répéter seulement si la variabilité observée empêche la conclusion. Annoncer cette nécessité et sa raison, pas un nouveau test à l'aveugle. L'objectif est de réduire les essais utilisateur ; garantir à l'avance qu'un seul essai prouvera toute causalité serait trompeur.
10. Artefacts et limites
Conserver dans un nouveau répertoire local ignoré : manifeste, capture ETL, télémétrie
versionnée, mapping JIT daté, coût de collecte, tableaux de fenêtres, piles chaudes,
rapport des attentes, événements perdus et décision. Le rapport lisible va dans docs.
Pas de clés NAND, mémoire brute invitée, mots de passe ou contenu réseau dans les exports.
Les ETL peuvent contenir des chemins et noms de processus : conservation locale, pas de push.
État au 22 septembre 2026 : instrumentation opt-in DOLPHIN_PERF_TRACE=1, mapping
temporel JIT ARM/PPC, scopes/counters versionnés, profil WPR ciblé, décodeur ETL et
sonde locale ont été ajoutés. La build isolée passe et la sonde privée a validé
13 contrôles locaux sur 13 sur deux captures, avec zéro perte d'événement.
Sur deux paires alternées, la phase ARM avec trace privée dépasse la phase sans
trace d'environ 1,7 % en moyenne, mais la dispersion est supérieure à cet écart.
Le budget de 2 % n'est donc pas qualifié. Le démarrage/arrêt du logger privé
ajoute environ 0,34 s à ces exécutions courtes ; ce coût ne mesure pas le
surcoût du collecteur WPR pendant une mise à jour Wii.
La session WPR ne démarrait pas dans le jeton Windows de cette tâche
(0xc5585011, droit de profilage système absent). Une capture synthétique
administrateur a depuis produit l'ETL P1-local-004, sans perte. L'analyse
hors ligne, reproductible sous PowerShell 5.1, valide 9 427 échantillons CPU,
694 context-switches, dix ancres QPC alignées à cinq ticks près, et le sommeil
connu effectivement classé Waiting. Le PDB local résout les fonctions C++;
le mapping temporel attribue les IP du JIT ARM. Les 112 événements Xperf
invalides sont des métadonnées ImageID hors du PID cible. Voir
Tools/PerformanceTrace/README.md.
Le lot WPR P1-overhead-001 a terminé ses huit charges synthétiques sans perte
ETW ; seul son calcul final a échoué faute de Python dans le PowerShell
administrateur. Le calcul récupéré hors ligne donne quatre écarts ARM ON/OFF de
+9,7 %, +25,0 %, -0,5 % et +1,0 %, tandis que les quatre bases OFF ont une
étendue de 34,5 %. Cette variabilité interdit d'annoncer un coût fiable du
collecteur ou de qualifier le seuil de 2 %. Le script vérifie maintenant Python
avant toute capture et peut analyser un lot déjà enregistré avec -AnalyzeOnly.
Les traces ON montrent en outre un indexeur C++ hôte (cpptools.exe) actif
pendant chaque essai et des services Dell intermittents. Le profil a été allégé
des piles ReadyThread, tout en conservant leurs événements ; sa nouvelle
version n'est pas encore qualifiée par un lot ON/OFF stable.
Le second lot avec ce profil (P1-overhead-002) a conservé zéro perte ETW mais
36,5 % d'étendue entre bases OFF. L'analyse par processeur montre que la sonde
rapide passe 78,7 % de ses échantillons sur les logiques 0–3 contre 28,9 % pour
la sonde la plus lente ; les temps ARM correspondants sont 7,59 et 10,33 s.
L'ETL identifie un i7-1255U hybride avec SMT sur 0–3. Le lanceur Wii fixait
déjà Dolphin à ces processeurs, mais les sondes OFF/ON ne l'étaient pas.
L'affinité a été ajoutée aux sondes et vérifiée localement (masque 15 observé).
Quatre bases fixées gardent toutefois 8,3 % de dispersion ARM ; elles ne
valident pas encore le seuil initial de 2 %. Il serait trompeur de demander un
troisième lot administrateur sans résoudre cette variabilité résiduelle.
Les événements natifs ne sont pas activés dans les profils utilisateur par défaut.
Une build et une sonde locale réussies ne valident pas le budget de 2 % ni le
comportement d'une mise à jour native. Le vérificateur local conserve
native_update_ready=false tant que les gates PPC, chemin critique natif et
coût du collecteur n'ont pas été validées.
Ne pas demander de nouvel essai utilisateur tant que ces gates ne passent pas.