Logicielsmoto.com

Nous sommes le 31 Jan 2023, 11:15

Heures au format UTC + 1 heure




Poster un nouveau sujet Répondre au sujet  [ 592 messages ]  Aller à la page Précédente  1 ... 34, 35, 36, 37, 38, 39, 40  Suivante
Auteur Message
MessagePosté: 13 Nov 2022, 18:09 
Hors ligne

Inscription: 21 Aoû 2006, 09:06
Messages: 1768
Localisation: Brest
Je crois que je tiens un truc...

On a vu que la routine RunObjects coûte environ 3.6% du temps (https://www.cjoint.com/doc/22_11/LKnnyt ... .html#75D4).

Le profil montre qu'on fait 13095 tours parmi lesquels seulement 3791 fois on tombe sur un objet actif. Donc 71% du temps on ne fait aucun appel de code à executer. La boucle exécutée est alors réduite à
Code:
75D9   E6C4   4   LDB   ,U
75DB   2710   3   BEQ   $75ED

75ED   33C840   5   LEAU  $40,U
75F0   11836FC7   5   CMPU  #$6FC7
75F4   26E3   3   BNE   $75D9
Ca a l'air court et rapide (20 cycles) mais ne rien faire rapidement est un truc à optimiser.

J'ai essayé d'être (trop) malin en essayant de réduire la taille de l'intervalle des objets à balayer. Pour cela il a fallu que je traque dans le code source les accès en écriture à id,U. J'en ai trouvé un peu partout (par des STA) ainsi que des STD ,U. Ca me plaisait moyen car ca me faisait toucher plein de sources, et puis ca foirait parfois (sans doute que j'ai oublié un endroit où on modifie le flag d'un objet).

Ensuite j'ai regardé le code plus haut. Un truc évident (pour moi) est que le CMPU coûte un max de cycle (25 du temps de la boucle), et qu'il ne sera vrai qu'une seule fois. On peut l'éliminer dans quasi tous les tours de boucles en ajoutant une sentinelle non nul en Object_RAM_End. Tant qu'on lit un B nul on sait qu'on est toujours dans le tableau. Plus besoin de vérifier U à chaque tour, mais uniquement dans les 30% des cas où on tombe sur un objet actif (B non nul). C'est super cool. Par contre cela fait ajouter un octet dans les déclarations de tableaux:
Fichier(s) joint(s):
Commentaire: Il faudrait mettre cette sentinelle dans toutes les déclarations de Object_RAM_End à travers les différents tableaux.
image_2022-11-13_181224436.png
image_2022-11-13_181224436.png [ 57.59 Kio | Vu 671 fois ]
C'est le léger prix à payer.

Ensuite on voit un LEAU.. C'est bien, c'est rapide, mais si on pouvait utiliser X à la place on ferait un ABX en 3 cycles seulement. Mais zut est utilisé. Bon je ré-écris la boucle comme suit:
Code:
RunObjects                                  *RunObjects:
; SAM's optimized version: use X to make the empty loop as fast as possible
                                            *    tst.b   (Teleport_flag).w
                                            *    bne.s   RunObjects_End  ; rts
        ldu   #Object_RAM-next_object       *    lea (Object_RAM).w,a0 ; a0=object
        bra   @a
@b      ldx   #Obj_Index_Page
        abx
        lda   ,x                           
        _SetCartPageA               
        aslb                               
                                           
        ldx   #Obj_Index_Address
        abx
        jsr   [,x]                         
@a      leax  ,u                            * we'll use x 'cause it's faster thanks to abx
        ldb   #next_object
@c      abx                                 * quickly loop over unactivated objects
        lda   id,x
        beq   @c
        leau  ,x                            ; copy back x to u
        ldb   id,u                          ; 2 cycles faster than tfr
        cmpu  #Object_RAM_End
        bne   @b
        rts
La boucle est alors réduite à ABX + LDA + BEQ soit 10 cycles seulement au lieu de 20 avant. Alors certes il y a des opérations en plus comme le passage temporaire de U à X et l'init de B pour les ABX, mais cela se passe hors de la boucle. Donc rarement (30% du temps en moyenne sur tout la carte de jeu).

Au final j'obtiens le profil suivant (https://www.cjoint.com/doc/22_11/LKnqLt ... .html#75D5) dans lequel la routine tombe à 1.5% du temps seulement.

On fait toujours rien, mais bien plus vite qu'avant. Ca c'est de l'optim rigolote :bien: (bon la vraie optim serait d'utiliser une liste chainée mais le moteur original de sonic n'est pas prévu pour ca et parcourt le tableau d'objets de la même façon).

Pour info sur la position de départ de Sonic je passe ainsi de 87ms/image à 77ms/image. Dis moi si tu observes autant d'augmentation de ton coté (te faut il les fichiers dans un ZIP ou ca ira à partir des infos d'ici).

_________________
Good morning, that's a nice Tnetennba


Haut
 Profil  
Répondre en citant le message  
MessagePosté: 13 Nov 2022, 18:31 
Hors ligne

Inscription: 21 Avr 2019, 21:48
Messages: 419
Localisation: Var
cool !

Pour éviter le cmpu on pourrait même paramétrer l'objet de fin (255) avec comme adresse ... celle de la sortie de boucle :D
C'est donc le jsr [,x] qui ferait la sortie
Il suffirait alors en sortie de boucle d'incrémenter S pour vider le PC (puisqu'on a fait un JSR).

le tableau page/adresse des objets est construit par le builder donc ça demande une petite adaptation de ce coté.

Qu'en penses tu ?

Ps: pas besoin du zip


Haut
 Profil  
Répondre en citant le message  
MessagePosté: 13 Nov 2022, 19:04 
Hors ligne

Inscription: 21 Aoû 2006, 09:06
Messages: 1768
Localisation: Brest
Tu veux dire que la sentinelle que j'ai ajouté aurait comme fonction à executer de sortir de la routine? Ah oui, pourquoi pas. Mais cela ne ferait qu'économiser 5+3 cycles par routine dd'action qui sont en soi relativement plus couteuses. Je ne sais pas si le jeu vaut la chandelle. Il faut experimenter.

_________________
Good morning, that's a nice Tnetennba


Haut
 Profil  
Répondre en citant le message  
MessagePosté: 13 Nov 2022, 19:13 
Hors ligne

Inscription: 21 Avr 2019, 21:48
Messages: 419
Localisation: Var
Le cmpu est joué après chaque appel a un objet instancié.
Oui effectivement ça dépend du nb d’objets.

Il faut que je regarde aussi le dimensionnement des slots, il y en a 44 c’est peut être trop …
Je vais regarder à combien on monte


Haut
 Profil  
Répondre en citant le message  
MessagePosté: 13 Nov 2022, 19:28 
Hors ligne

Inscription: 21 Aoû 2006, 09:06
Messages: 1768
Localisation: Brest
Une autre solution serait d'avoir 2 octets de plus dans chaque slot et que lorsqu'on active un objet on le link aux objets précédemment affichés (et on de retire s'il est effacé). Ainsi la boucle ne tournerait que sur les objets qui ont du vrai code à executer.

_________________
Good morning, that's a nice Tnetennba


Haut
 Profil  
Répondre en citant le message  
MessagePosté: 13 Nov 2022, 19:43 
Hors ligne

Inscription: 21 Avr 2019, 21:48
Messages: 419
Localisation: Var
Ça me paraît le mieux. Il faudra 4 octets pour stocker le précédent et le suivant afin de les lier lors de la suppression d’un objet en milieu de liste. A moins de travailler avec des index 8 bits multiples de la taille d’un objet. Il n’est pas compliqué d’ajouter des variables aux objets. Je regarde ça tout a l’heure.

Par contre ça veut dire modifier tous les endroits où on fait une allocation d’objet … un peu de boulot … je vais peut être mettre en place une macro ou une routine dédiée.


Haut
 Profil  
Répondre en citant le message  
MessagePosté: 13 Nov 2022, 21:04 
Hors ligne

Inscription: 21 Aoû 2006, 09:06
Messages: 1768
Localisation: Brest
Cela vaudrait le coup d'avoir une routine centrale pour allouer un objet. C'est ce qui me manquait pour adapter l'adresse de debut/fin de la zone occupée de la RAM-Objet.

Au fait, les spikes sont curieux par là:
Fichier(s) joint(s):
image_2022-11-13_210712510.png
image_2022-11-13_210712510.png [ 35.35 Kio | Vu 665 fois ]

_________________
Good morning, that's a nice Tnetennba


Haut
 Profil  
Répondre en citant le message  
MessagePosté: 13 Nov 2022, 21:18 
Hors ligne

Inscription: 21 Avr 2019, 21:48
Messages: 419
Localisation: Var
Oui c'est ce que je suis en train de regarder, le flip ne se fait pas sur ceux du haut.
Sur ceux du bas ils devraient être masqués par le sol (une problématique de priorité des tiles qui n'est pas encore implémentée)


Haut
 Profil  
Répondre en citant le message  
MessagePosté: 13 Nov 2022, 22:22 
Hors ligne

Inscription: 21 Aoû 2006, 09:06
Messages: 1768
Localisation: Brest
Punaise, l'animation de tous ces objets va manger pas mal de cycles cpu au total.

_________________
Good morning, that's a nice Tnetennba


Haut
 Profil  
Répondre en citant le message  
MessagePosté: 14 Nov 2022, 00:12 
Hors ligne

Inscription: 21 Avr 2019, 21:48
Messages: 419
Localisation: Var
Bon j'ai trouvé le bug qui fait que les pics ne sont pas affichés à l'envers.
Il s'agit d'un problème dans la génération de l'index des images (coté java).
Je n'avais jamais eu la combinaison image normale + filp Y (sans flip X).


Haut
 Profil  
Répondre en citant le message  
MessagePosté: 14 Nov 2022, 09:59 
Hors ligne

Inscription: 21 Aoû 2006, 09:06
Messages: 1768
Localisation: Brest
Je viens de recompiler. Ca marche! :good:

Question mini optim, j'ai vu que Find_Tile retourne une valeur dans X (avec un LEAX couteux à la fin). Or chaque appel est suivi d'un "LDD ,X". On peut gagner quelques cycles en retirant le LEAX et les LDD et en faisant "LDD D,X" à la place dans Find_Tile.
Fichier(s) joint(s):
image_2022-11-14_100042127.png
image_2022-11-14_100042127.png [ 17.48 Kio | Vu 625 fois ]
Fichier(s) joint(s):
image_2022-11-14_095809806.png
image_2022-11-14_095809806.png [ 13.92 Kio | Vu 625 fois ]
Fichier(s) joint(s):
image_2022-11-14_095742025.png
image_2022-11-14_095742025.png [ 24.94 Kio | Vu 625 fois ]
On peut même factoriser les STD et ANDA qui suivent car ce sont tous les mêmes. Bon c'est des clopinettes, mais fréquemment appellées.

_________________
Good morning, that's a nice Tnetennba


Haut
 Profil  
Répondre en citant le message  
MessagePosté: 14 Nov 2022, 11:19 
Hors ligne

Inscription: 21 Avr 2019, 21:48
Messages: 419
Localisation: Var
oui bien !

De mon coté j'ai écrit les nouvelles routine RunObject, LoadObject et UnloadObject.
Je suis en cours d'application des changements d'appels ... ça va prendre un peu de temps.

Par contre ça fait du bien car je me débarrasse de certaines problématiques :
Avec le système actuel, si on voulait qu'un nouvel objet soit instancié dans la boucle principale actuelle, il fallait rechercher un bloc vide après l'objet courant, même si des blocs étaient disponibles avant dans la liste de slot. C'était potentiellement problématique si l'objet parent se retrouvait en fin de slot ... (on aurait en retour : plus de slot dispo alors qu'on en a de dispo en début de tableau) bref la nouvelle solution est bien meilleure.

Dans le code d'origine de sonic cette recherche de slot disponible est dupliquée de nombreuses fois.
Au moins ici tout sera centralisé ...

La liste d'exécution restera ordonnée par ordre de création des objets.
Si on veut exécuter des objets avant ou après ceux de cette liste dynamique, on a toujours possibilité de le faire manuellement.


Haut
 Profil  
Répondre en citant le message  
MessagePosté: 15 Nov 2022, 00:26 
Hors ligne

Inscription: 21 Avr 2019, 21:48
Messages: 419
Localisation: Var
Bon j'ai implémenté et commit le nouveau système de gestion des objets.
Il reste encore un bug, a priori sur la désallocation.

Seul Sonic2 est à jour, les autres démos sont encore à faire.

J'ai regroupé dans RunObjects2.asm les routines suivantes :

RunObjects
LoadObject_u, LoadObject_x => ajout dans la liste
UnloadObject_u, UnloadObject_x => suppression de la liste

Lorsque l'objet est associé à l'affichage d'une image l'appel de UnloadObject est fait par DeleteObject (qui retire l'image de la liste priorisée d'affichage).
Dans le niveau de jeu, c'est object-manager qui fait l'instanciation (LoadObject) et MarkObjGone qui fait la suppression de l'objet (est fait aussi en direct dans certains objets).

Le résultat est bien celui attendu : avec 44 objets vides au départ on gagne bien les 880 cycles (soit a peu près 1% de perf)

Même s'il reste encore un bug je suis super content d'avoir avancé sur ce sujet, on a qq chose de bien plus optimisé maintenant.
:sol:


Haut
 Profil  
Répondre en citant le message  
MessagePosté: 15 Nov 2022, 10:01 
Hors ligne

Inscription: 21 Aoû 2006, 09:06
Messages: 1768
Localisation: Brest
Super! J'ai récupéré, et profilé sur un parcours de gauche à droite de l'ensemble de la map pendant 32s: https://www.cjoint.com/doc/22_11/LKpiRr ... emmap.html

Plus de trace de RunObjects dans les 10 premiers points "chauds" du code. :good:

En mode idle sur la position de départ le profil est celui-ci: https://www.cjoint.com/doc/22_11/LKpi6v ... emmap.html

Par contre il semble que certains pics clignotent 1 fois quand Sonic passe à leur niveau (et plus après). C'est normal ?
phpBB [video]

_________________
Good morning, that's a nice Tnetennba


Haut
 Profil  
Répondre en citant le message  
MessagePosté: 15 Nov 2022, 10:16 
Hors ligne

Inscription: 21 Avr 2019, 21:48
Messages: 419
Localisation: Var
Comme je l’ai indiqué il reste un bug que je n’ai pas encore eu le temps de débusquer.
Lorsque l’objet n’est pas exécuté dans la boucle principale, il est automatiquement masqué par le gestionnaire d’affichage.
Il doit y avoir un problème dans la gestion de la liste chaînée a l’allocation ou la desallocation.


Haut
 Profil  
Répondre en citant le message  
Afficher les messages postés depuis:  Trier par  
Poster un nouveau sujet Répondre au sujet  [ 592 messages ]  Aller à la page Précédente  1 ... 34, 35, 36, 37, 38, 39, 40  Suivante

Heures au format UTC + 1 heure


Qui est en ligne

Utilisateurs parcourant ce forum: Aucun utilisateur enregistré et 5 invités


Vous ne pouvez pas poster de nouveaux sujets
Vous ne pouvez pas répondre aux sujets
Vous ne pouvez pas éditer vos messages
Vous ne pouvez pas supprimer vos messages
Vous ne pouvez pas joindre des fichiers

Rechercher:
Aller à:  
cron
Développé par phpBB® Forum Software © phpBB Group
Traduction par phpBB-fr.com