Posté le 25/09/2016 19:17
Planète Casio v4.3 © créé par Neuronix et Muelsaco 2004 - 2024 | Il y a 135 connectés | Nous contacter | Qui sommes-nous ? | Licences et remerciements
Planète Casio est un site communautaire non affilié à Casio. Toute reproduction de Planète Casio, même partielle, est interdite.
Les programmes et autres publications présentes sur Planète Casio restent la propriété de leurs auteurs et peuvent être soumis à des licences ou copyrights.
CASIO est une marque déposée par CASIO Computer Co., Ltd
Citer : Posté le 25/09/2016 19:30 | #
Et même "On calc" le calcul pourri est plus rapide de 1% C'est faible, mais ça reste quand même plus rapide...
Citer : Posté le 25/09/2016 19:31 | #
De toute façon, les flottants sur des systèmes embedded, ça a toujours été le yolo absolu.
Mon blog ⋅ Mes autres projets
Citer : Posté le 26/09/2016 12:47 | #
Tu compiles avec quoi ? Parce que GCC est très très fort au niveau de l'optimisation du code (bien plus que toi )
Citer : Posté le 26/09/2016 18:15 | #
Avec le sdk
Citer : Posté le 26/09/2016 21:29 | #
Vérifie que c'est pas un problème de conversions. Si tu peux m'isoler le code assembleur de ces deux calculs, je devrais pouvoir en dire quelque chose
Citer : Posté le 26/09/2016 22:27 | #
Tu parles de conversion float to int et inversement ?
Je vais regarder si je peux isoler l'assembleur
Citer : Posté le 27/09/2016 15:37 | #
C'est ça. En principe la division est extrêmement lente (70 cycles pour la division entière, sans doute bien plus pour la flottante étant donné qu'il n'y a pas de FPU -- faudra que je mesure ça avec gint), fuyez-la autant que possible (en comparaison la multiplication c'est 3 à 5 cycles en entier donc voilà quoi).
Pendant que j'y pense, il y a une non-explication plus fondamentale ; la première formule équivaut (optimisation triviale) à
Il n'y a pas plus de divisions à calculer (toujours 3) donc la nouvelle formule peut ne rien apporter (il faut stocker une variable, etc).
Citer : Posté le 27/09/2016 17:45 | #
En effet ça serait bien que tu mesures le nombre de cylce proco pour chaque opération, y compris les conversions et tout, ça permetrait de mieux se rendre compte.
Pour l'assembleur ça donne ça
000008F0 D313 MOV.L L588+2,R3 ; __itos
000008F2 6403 MOV R0,R4
000008F4 E019 MOV #25,R0
000008F6 430B JSR @R3
000008F8 00EC MOV.B @(R0,R14),R0
000008FA 2F06 MOV.L R0,@-R15
000008FC 51FB MOV.L @(44,R15),R1
000008FE D211 MOV.L L588+6,R2 ; __divs
00000900 420B JSR @R2
00000902 6043 MOV R4,R0
00000904 D310 MOV.L L588+10,R3 ; __adds
00000906 61F3 MOV R15,R1
00000908 7148 ADD #72,R1
0000090A 430B JSR @R3
0000090C 6112 MOV.L @R1,R1
0000090E D30D MOV.L L588+6,R3 ; __divs
00000910 430B JSR @R3
00000912 61F6 MOV.L @R15+,R1
00000914 D20D MOV.L L588+14,R2 ; __stoi
00000916 420B JSR @R2
00000918 0009 NOP
0000091A 6403 MOV R0,R4
//////////////
Render3DOp 220 int ty = wy * current_wall->texture_height / point1.z / (wy / point1.z + (1-wy) / point0.z);
000008B8 D31C MOV.L L589+4,R3 ; __itos
000008BA E019 MOV #25,R0
000008BC 430B JSR @R3
000008BE 00EC MOV.B @(R0,R14),R0
000008C0 D21C MOV.L L589+12,R2 ; __muls
000008C2 420B JSR @R2
000008C4 6143 MOV R4,R1
000008C6 63F3 MOV R15,R3
000008C8 D219 MOV.L L589+8,R2 ; __divs
000008CA 6103 MOV R0,R1
000008CC 7378 ADD #120,R3
000008CE 6532 MOV.L @R3,R5
000008D0 420B JSR @R2
000008D2 6053 MOV R5,R0
000008D4 2F06 MOV.L R0,@-R15
000008D6 6143 MOV R4,R1
000008D8 D315 MOV.L L589+8,R3 ; __divs
000008DA 430B JSR @R3
000008DC 6053 MOV R5,R0
000008DE 2F06 MOV.L R0,@-R15
000008E0 D115 MOV.L L589+16,R1 ; H'3F800000
000008E2 D216 MOV.L L589+20,R2 ; __subs
000008E4 420B JSR @R2
000008E6 6043 MOV R4,R0
000008E8 D311 MOV.L L589+8,R3 ; __divs
000008EA 6103 MOV R0,R1
000008EC 901C MOV.W L589,R0 ; H'008C
000008EE 430B JSR @R3
000008F0 00FE MOV.L @(R0,R15),R0
000008F2 D313 MOV.L L589+24,R3 ; __adds
000008F4 430B JSR @R3
000008F6 61F6 MOV.L @R15+,R1
000008F8 D20D MOV.L L589+8,R2 ; __divs
000008FA 420B JSR @R2
000008FC 61F6 MOV.L @R15+,R1
000008FE D311 MOV.L L589+28,R3 ; __stoi
00000900 430B JSR @R3
00000902 0009 NOP
Ajouté le 27/09/2016 à 17:52 :
D'ailleurs, comment est ce que je pourrais optimiser cette ligne de commande ?
Elle permet de savoir un pixel d'un sprite est noir (color!=0) ou blanc (color=0)
unsigned char y_8 = ty >> 3;
for(...)
{
char color = (current_wall->texture[y_8 + ((wx >> 10)<<2)] & mask);
+10)<<2)] & mask);
000009A4 54F4 MOV.L @(16,R15),R4
000009A6 E3F6 MOV #-10,R3
000009A8 443C SHAD R3,R4
000009AA 4408 SHLL2 R4
000009AC E030 MOV #48,R0
000009AE 03FC MOV.B @(R0,R15),R3
000009B0 50E5 MOV.L @(20,R14),R0
000009B2 633C EXTU.B R3,R3
000009B4 343C ADD R3,R4
000009B6 044C MOV.B @(R0,R4),R4
000009B8 E02C MOV #44,R0
000009BA 03FC MOV.B @(R0,R15),R3
000009BC 2439 AND R3,R4
Citer : Posté le 27/09/2016 17:53 | #
Après peut être que les variations ne sont que des erreurs de mesures, tu as mesuré plusieurs fois de suite ?
Ecrivez vos programmes basic sur PC avec BIDE
Citer : Posté le 27/09/2016 17:58 | #
J'execute mon code 300 fois et je moyenne. Je lance même le code 100 fois avant juste "pour éviter un hypothétique regime transitoire" mdr
Mais je remarque que j'ai deux type de mesures. les "lentes" et les "normales" (ou normales et rapide, j'en sais rien)
C'est à dire que une fois sur X j'obtiens une moyenne plus basse, et des fois une plus haute pour le même code.
{
for (int i=0; i<100; i++)
{
render_draw(camera_x, camera_y, camera_z);
}
int t1 = time_get_ticks();
for (int i=0; i<300; i++)
{
render_draw(camera_x, camera_y, camera_z);
}
int t2 = time_get_ticks();
float dt = (t2-t1) / 128.0 / 300.0;
debug_pop(1/dt); // affiche le nombre de hertz
}
Citer : Posté le 27/09/2016 18:00 | #
Tu recompiles pour chaque test ? (on ne sait jamais, avec les IDE...)
EDIT: ah je suis aveugle lol
Mon blog ⋅ Mes autres projets
Citer : Posté le 27/09/2016 18:03 | #
Dans ce cas je dirais que c'est des erreurs de mesures si parfois c'est plus rapide et parfois plus lent, ça peut dépendre de ton PC qui pourrait faire une tâche en même temps, etc. Faudrait essayer sur la calto.
Cake, il recompile pas pour chaque test, il fait un for
Ecrivez vos programmes basic sur PC avec BIDE
Citer : Posté le 27/09/2016 18:33 | #
On dirait que tu n'as pas isolé ce calcul dans une fonction, Ninestars ? Au final, en extrapolant un peu, on s'en sort facilement. Il suffit de savoir que le suffixe « s » signifie « simple » (par opposition à « double ») et donc les flottants. Je vous mets le code annoté (i.e., lisible x)) :
int ty = current_wall->texture_height / (c2 + c1/wy);
[1] int -> float
[1] float + float
[2] float / float
[1] float -> int
*/
mov.l __itos, r3 // Conversion vers float
mov r0, r4
mov #25, r0
jsr @r3
mov.b @(r0, r14), r0
mov.l r0, @-r15
mov.l @(44, r15), r1
mov.l __divs, r2 // Calcul de c1 / wy
jsr @r2
mov r4, r0
mov.l _adds, r3 // Calcul de c2 + ...
mov r15, r1
add #72, r1
jsr @r3
mov.l @r1, r1
mov.l __divs, r3 // Calcul de cw / ...
jsr @r3
mov.l @r15+, r1
mov.l __stoi, r2 // Conversion vers int
jsr @r2
nop
mov r0,r4
/*
int ty = wy * current_wall->texture_height / point1.z / (wy / point1.z + (1-wy) / point0.z);
[1] int -> float
[1] float -> int
[1] float * float
[4] float / float
[1] float - float
[1] float + float
*/
mov.l __itos, r3 // Conversion int -> float
mov #25, r0
jsr @r3
mov.b @(r0, r14), r0
mov.l __muls, r2 // Calcul de wy * cw
jsr @r2
mov r4, r1
mov r15, r3
mov.l __divs, r2 // Calcul de ... / p1.z
mov r0, r1
add #120, r3
mov.l @r3, r5
jsr @r2
mov r5, r0
mov.l r0, @-r15
mov r4, r1
mov.l __divs, r3 // Calcul de wy / p1.z
jsr @r3
mov r5, r0
mov.l r0, @-r15
mov.l 0x3f800000, r1
mov.l __subs, r2 // Calcul de 1 - wy
jsr @r2
mov r4, r0
mov.l __divs, r3 // Calcul de ... / p0.z
mov r0, r1
mov.w 0x008c, r0
jsr @r3
mov.l @(r0, r15), r0
mov.l _adds, r3 // Calcul du barycentre
jsr @r3
mov.l @r15+, r1
mov.l __divs, r2 // Calcul de ty (float)
jsr @r2
mov.l @r15+, r1
mov.l __stoi, r3 // Conversion float -> int
jsr @r3
nop
Niveau performance, il ne doit pas y avoir de doute. L'optimisation classique au niveau de la série de divisions n'ayant pas été faite, l'analyse pure laisse prévoir un réel gain de vitesse avec le second calcul.
Tu utilises la RTC pour tes tests ? Le compteur R64CNT ne délivre que des signaux à 64 Hz (on peut compter à 128 Hz si on compte les deux fronts, il me semble, mais le registre de la RTC ne donne pas la valeur) ; tu es sûr que le code est assez lent pour ça ?
Sur l'émulateur ça peut être trompeur. Pour être sûr, il faudrait mesurer sur la machine... et avec gint, histoire de pouvoir compter le nombre de cycles proco -- la cerise, comme certains appellent ça.
Citer : Posté le 27/09/2016 18:42 | #
Et puis bon, je veux pas faire mon relou, mais pourquoi ne pas utiliser un vrai compilateur (et même une vraie plateforme :P), surtout pour les gros projets comme ça ? Ouais, on n'a pas d'émulateur, mais on a une calculatrice et on voit vraiment ce que ça va donner dessus (et des utilitaires de transfert CLI qui font que tester c'est rapide)...
Mon blog ⋅ Mes autres projets
Citer : Posté le 27/09/2016 19:11 | #
On dirait que tu n'as pas isolé ce calcul dans une fonction, Ninestars ?
Pour mesurer les perfs j'utilise la lib de Dark Storm il me semble, code c'est ça
#define SCB 0x422B0009
#define SCE 0x80010070
typedef int(*sc_iv) (void);
const unsigned int sc003ba[] = {SCA, SCB, SCE, 0x3B};
#define RTC_GetTicks (*(sc_iv)sc003ba)
int time_get_ticks()
{
return RTC_GetTicks();
}
tu es sûr que le code est assez lent pour ça ?
Le problème c'est que c'est hyper long les transferts par FA-124, c'est pour ça que j'utilise le SDK, que pour compiler, sinon j'ai Sublime Text 2 pour l'édition.
Cake, tu supposes Linux je parie, et qu'est-ce que c'est ce CLI ?
Citer : Posté le 27/09/2016 20:44 | #
Je n'ai pas créée une fonction "juste" pour ce calcul, il est dans la fonction render_draw(). Pourquoi ?
Ça saute aux yeux, en fait. Le code est fondamentalement indéchiffrable parce que la distribution des variables dans la pile et les registres est complètement inconnue ; si tu wrappes le tout dans une fonction, on sait précisément quel paramètre est où. C'est essentiel quand il s'agit d'interpréter le comportement d'un morceau de code en assembleur
Il s'agit bien (0x03b) de RTC_GetTicks(). Je n'ai jamais eu l'occasion de le désassembler (et là mon soft est HS pour des raisons obscures), mais j'ai toujours eu des doutes sur la manière dont on obtenait un tick de 128 Hz... enfin peu importe à la limite.
S'il s'agissait d'un processeur moderne je ferais le coup du cache, mais c'est pas bon. Écoute, si tu veux une mesure précise, t'as qu'à utiliser un timer du proco et le programmer de sorte qu'il n'atteigne pas son terme. En lisant la valeur du compteur à la fin de l'exécution, tu dois pouvoir en déduire une mesure autrement plus précise de la vitesse de ton code qu'avec la RTC. (Du genre, un compteur au MHz au lieu d'un compteur à 100 Hz.)
Je te mets un bout de code là pour SH3 (je crois que t'as pas de SH4 ?), à utiliser sur la machine par contre. Je ne peux pas tester (les maths m'attendent), il faut juste appeler cette fonction avec en paramètre une fonction void → void. Note que le résultat est une affine du temps d'exécution, il y a un overhead à cause du temps d'appel et de récupération du compteur. Essaie d'abord d'appeler une seule fois ta fonction avec ça, si le délai est trop court (inférieur à 1000 unités), essaie de boucler.
{
unsigned int TCOR;
unsigned int TCNT;
union
{
unsigned short WORD;
struct
{
unsigned :7;
unsigned UNF :1;
unsigned :2;
unsigned UNIE :1;
unsigned CKEG :2;
unsigned TPSC :3;
};
} TCR;
};
int execution_time(void (*function)(void))
{
volatile struct Timer *tmu = (volatile struct Timer *)0xfffffe94;
volatile unsigned char *tstr = (volatile unsigned char *)0xfffffe92;
tmu->TCOR = 0xffffffff;
tmu->TCNT = 0xffffffff;
tmu->TCR.TPSC = 0;
tmu->TCR.UNF = 0;
tmu->TCR.UNIE = 0;
tmu->TCR.CKEG = 0;
*tstr |= 1;
function();
unsigned int counter = tmu->TCNT;
*tstr &= ~1;
return 0xffffffff - counter;
}
Citer : Posté le 29/09/2016 17:12 | #
Très bien, merci je vais essayer ce bout de code
Ajouté le 29/09/2016 à 17:16 :
En fait il a pas trop aimé la compilation le sdk haha !
C:\Casio Projets\Render3D\Main.cpp(121) : C5144 (E) A value of type "volatile void *" cannot be used to initialize an entity of type "unsigned char *"
C:\Casio Projets\Render3D\Main.cpp(123) : C5131 (E) Expression must have pointer-to-class type
C:\Casio Projets\Render3D\Main.cpp(124) : C5131 (E) Expression must have pointer-to-class type
C:\Casio Projets\Render3D\Main.cpp(125) : C5131 (E) Expression must have pointer-to-class type
C:\Casio Projets\Render3D\Main.cpp(127) : C5131 (E) Expression must have pointer-to-class type
C:\Casio Projets\Render3D\Main.cpp(128) : C5131 (E) Expression must have pointer-to-class type
C:\Casio Projets\Render3D\Main.cpp(129) : C5131 (E) Expression must have pointer-to-class type
C:\Casio Projets\Render3D\Main.cpp(131) : C5349 (E) No operator "|=" matches these operands
Operand types are: Struct <unnamed> |= int
C:\Casio Projets\Render3D\Main.cpp(135) : C5131 (E) Expression must have pointer-to-class type
C:\Casio Projets\Render3D\Main.cpp(136) : C5349 (E) No operator "&=" matches these operands
Operand types are: Struct <unnamed> &= int
C:\Casio Projets\Render3D\Main.cpp(138) : C5131 (E) Expression must have pointer-to-class type
Ton code commence à la ligne 100
Citer : Posté le 29/09/2016 17:23 | #
- Ajoutes "volatile" avant "struct" à ta ligne 103 et avant "unsigned char" à ta ligne 122
- Ligne 132, remplaces "*tstr" par "tstr->TCOR"
- Ligne 137, remplaces "*tstr" par "tstr->TCOR"
Pour les deux dernières corrections par contre, je suis pas sûr que ce soit ce que lephé avait en tête et j'ai pas RTFM.
Ca devrait résoudre tes autres erreurs aussi.
Mon blog ⋅ Mes autres projets
Citer : Posté le 29/09/2016 18:06 | #
Ok pour la première correction avec le volatile, mais non pour le reste. Il faut juste échanger les noms des deux variables à la déclaration (et pas la valeur).
Edit : j'ai modifié mon message du coup.
Citer : Posté le 29/09/2016 18:13 | #
Merci les gars, c'est un peu miuex mais j'ai toujours ça
C:\Casio Projets\Render3D\Main.cpp(120) : C5144 (E) A value of type "volatile void *" cannot be used to initialize an entity of type "volatile struct <unnamed> *"
C:\Casio Projets\Render3D\Main.cpp(121) : C5144 (E) A value of type "volatile void *" cannot be used to initialize an entity of type "unsigned char *"