Page 2 sur 2

Publié : mar. 11/août/2009 9:29
par Progi1984
Ollivier a écrit :@PAPIPP

1) Tu me rabaches un truc que je sais déjà sur RDTSC, de ta part, comme de celle de Progi1984, donc inutile
Excuse moi mais qu'est ce que j'ai à voir là dedans ?

Publié : mar. 11/août/2009 16:55
par Ollivier
Rien de mal, au contraire. Tu m'as appris à me servir de RDTSC quand un ProcedureReturn dans une procédure retourne un quad en chargeant EAX en poids faible et EDX en poids fort.

La tournure de la phrase peut porter à confusion, mais ce qui est inutile, c'est bien le rabachage de PAPIPP qui donne une énorme envie de continuer à donner de son temps pour partager du code et des idées.

Publié : mar. 11/août/2009 21:36
par PAPIPP
Pour éviter de trop rabâcher et bien que la répétition soit une excellente forme pédagogique je t’invite à regarder
ici Mercredi 17 Juin 2009 23h11
http://www.purebasic.fr/french/viewtopi ... p&start=15
La boucle est bouclée

Publié : mer. 12/août/2009 6:54
par Ollivier
Je tâcherai d'expliquer le code tout en haut quand j'aurai le temps. En attendant, j'ai l'intime conviction qu'il ne suffit pas de lire un fichier ASM pour être sorti de l'auberge quand à la chronométrie des instructions.

Code : Tout sélectionner

EnableExplicit
DisableDebugger

Procedure.Q BuildQuad(Low.I, High.I)
  ! mov Eax, [p.v_Low]
  ! mov Edx, [p.v_High]
  ProcedureReturn
EndProcedure

Define A.I
Define B.I
Define C.I
Define D.I
Define E.I
Define F.I

Delay(100)
! MOV [v_A], Eax

Delay(1)
! MOV [v_A], Eax

! RDTSC
! MOV [v_E], Eax
! RDTSC
! MOV [v_F], Eax

! RDTSC
! MOV [v_A], Eax
! XOR Eax, Eax
! MOV [v_B], Edx
! RDTSC
! MOV [v_C], Eax
! MOV [v_D], Edx

MessageRequester("Supprimez la ligne 21", "!RDTSC" + Chr(9) + Chr(9) + Chr(9) + "} " + Str(F - E) + " cycle(s)" + Chr(10) + "!MOV [v_X], Eax" + Chr(10) + Chr(10) + "!RDTSC" + Chr(9) + Chr(9) + Chr(9) + "} " + Str(BuildQuad(C, D) - BuildQuad(A, B) ) + " cycle(s)" + Chr(10) + "!MOV [v_X], Eax" + Chr(10) + "!MOV [v_Y], Edx")

Publié : mer. 12/août/2009 21:42
par Ollivier
@PAPIPP

J'ai vu ton message (le dernier de la page précédente). Je le prends pour excuse tout à fait correcte. Et c'est à moi de m'excuser de t'avoir mis la pression.

J'ai vraiment pensé que tu te moquais, alors que tu as juste rassemblé plusieurs erreur de maladresse (cinq, c'est un record à mes yeux, mais si ce n'est que de la maladresse, c'est largement excusable). La programmation doit rester un échange. Si tu dis que tu es débutant en PB, je peux prendre soin de t'expliquer correctement ce qui cloche et quel code serait mieux adapté par le fond de tes remarques. Et, à mon avis ainsi tu aurais d'autres choses à m'apprendre sans aucune faille. Comme bon nombre de membres ici.

La chronométrie implique de prendre les valeurs (ici les cycles) de manières relatives. Une instruction va s'exécuter selon un contexte:
- l'instruction qui la précède;
- l'amorçage de la tâche;
- la durée d'appel de son argument (instructions de saut);

Les résultats individuels sont donc variés et ne peuvent donner lieu à un simple comme s'il s'agissait d'un domino-day où les instructions sont toutes idem et carrées dans leur exécution.

La remarque de LSI ("c'est strictement pareil") laissait penser, si elle avait été vraie, que son CPU avait la capacité matérielle d'optimiser les multiplications à produits identiques. Ce qui aurait pu être plausible. ça s'est révélé faux. Cependant, ça n'empêche en rien de déceler des choses intéressantes en créant les bons outils de mesure. L'exemple ci-dessus en est un. Mais il y en a une foule d'autres. Un autre exemple au pif, un JNE (If a <> b) plus lent qu'un JE (If a = b).

Aussi le meilleur outils c'est quand TOI tu répètes une instruction dans l'éditeur des centaines ou des milliers de fois en poussant souvent au max les limites du compilateur. Cette tâche te prendrait beaucoup de temps. Heureusement, Fred a créé un superbe compilateur (il a des défauts aussi bien sûr!). Sa compilation est rapide. Il est souple (Cf le sujet "Le compilateur en mode Standby"). Et le langage Basic est à la portée de bon nombres d'informaticiens. Sa syntaxe est plus légère que le C et l'assembleur y est insérable comme une lettre à la poste. Bien sûr, tout cela, tu le sais déjà, je pense. Ce qui est intéressant mais pas forcément séduisant, c'est de créer une application non-autonome. C'est-à-dire un exécutable qui, quand le commun des mortels sur le Net tombe dessus, quand il l'exécute se voit afficher "Compilateur introuvable! Aller à la page www.purebasic.com pour de plus amples renseignements." En revanche, la communauté PB, elle, n'a aucune difficulté à exécuter ce code. Un exemple non-autonome: Python.

Donc la chronométrie précise revient à chercher une méthode qui ouvre beaucoup plus de portes que d'écrire un simple programme. C'est exactement comme fouiller un champ, sous prétexte d'une légende qui indiquerait qu'un trésor s'y cache, alors qu'au final c'est l'action de ce travail de la terre qui a enrichi la récolte et donc produit un trésor.

Ce que je te conseille c'est de créer un petit programme qui t'affiche un message comme

Code : Tout sélectionner

Debug "Voici un message"
et de l' "encapsuler" dans une chaîne pour obtenir ce programme dans la fenêtrede déboguage. La première difficulté c'est les guillemets, car on ne peut pas écrire

Code : Tout sélectionner

Debug "Debug "Voici un message""
Les guillemets à l'intérieur doivent être remplacés par un Chr(34). Et comme une chaîne est entourée par une PAIRE de guillemets, il faut en théorie écrire DEUX fois CHR(34) sans compter les fermetures et les réouvertures de chaîne ainsi que les liens (les signes plus "+")

Code : Tout sélectionner

Debug "Debug " + Chr(34) + "Voici un message" + Chr(34)
On peut heureusement simplifier par une procédure:

Code : Tout sélectionner

Debug "Debug" + G("Voici un message")
Avec la procédure G() comme suit:

Code : Tout sélectionner

Procedure.S G(Chaine.S)
  Protected Result.S
  Result = Chr(34) + Chaine + Chr(34)
  ProcedureReturn Result
EndProcedure
Et cette procédure est la première procédure que j'explique ici et qui se situe dans le code générateur plus haut, au début du sujet.

Publié : jeu. 13/août/2009 22:55
par Ollivier
Ensuite, il y a cette procédure-ci:

Code : Tout sélectionner

Procedure StoreTrust(*C.OpString)
   With *C
      CreateFile(0, #Home + \TrustFileName + ".pb")
      Impr("DisableDebugger")
      BouclageEcriture(1, 100, "XYZTUVWXYZABCDEFGHIJKLM")
      BouclageEcriture(2, 100, "X * Y * Z * T * U * V * W * X * Y * Z * A * B * C * D * E * F * G * H * I * J * K * L * M")
      Impr("MessageRequester(" + G("Quantité approx de cycles utilisés") + ", " + G("Avec optimisation = ") + " + Str(Fin1 - Ini1) + " + G(" cycles") + " + Chr(10) + " + G("Sans optimisation = ") + " + Str(Fin2 - Ini2) + " + G(" cycles") + ")")
      CloseFile(0)
   EndWith
EndProcedure 
Debug va afficher un message dans le débogueur. Si le message est une ligne de code qui doit être exécutée, au lieu d'utiliser Debug, dans le code générateur, on utilise Impr() (comme imprimer).

J'ai appelé cette procédure StoreTrust(), parce qu'elle stocke le code enfant. Et j'ai mis Trust parce qu'il faut vraiment avoir confiance en ce que l'on crée, vu qu'il est très facile de créer des codes impossibles à comprendre et trop gros pour être débogué à la main.

Dans cette procédure, pour repartir à zéro et réécrire un routine d'enregistrement de code, il suffit de faire le ménage:

Code : Tout sélectionner

Procedure StoreTrust(*C.OpString)
   With *C
      CreateFile(0, #Home + \TrustFileName + ".pb")
      CloseFile(0)
   EndWith
EndProcedure 
Et de commencer à mettre son propre code:

Code : Tout sélectionner

Procedure StoreTrust(*C.OpString)
   With *C
      CreateFile(0, #Home + \TrustFileName + ".pb")
      Impr("Debug " + G("Voici mon propre code!") )
      CloseFile(0)
   EndWith
EndProcedure 
Ainsi, tu peux exécuter à peu près tout et n'importe quoi. Ce programme devient une sorte de "Macro-Basic". C'est ainsi qu'il faut voir la procédure BouclageEcriture(). C'est en fait une macro dynamique du code enfant. Parce qu'en PureBasic, il est impossible de créer une macro qui va augmenter le nombre boucles imbriquées avec un simple nombre en argument.

La procédure BouclageEcriture(10, 1, "Max") créera le code suivant:

Code : Tout sélectionner

Define Ini10.I
Define Fin10.I
! RDTSC 
! MOV [v_Ini10], Eax
For AA = 0 To Max
  ! RDTSC
  ! MOV [v_Fin10], Eax
  Break 1
Next
(Comme tu peux le voir, c'est uniquement la seule ligne For qui est chronométrée.)

BouclageEcriture(11, 3, "Maximum") créera le code suivant:

Code : Tout sélectionner

Define Ini11.I
Define Fin11.I
! RDTSC
! MOV [v_Ini11], Eax
For AA = 0 To Maximum
  For AB = 0 To Maximum
    For AC = 0 To Maximum
      ! RDTSC
      ! MOV [v_Fin11], Eax
      Break 3
    Next
  Next
Next
Avec ces deux codes, on se rend bien compte que la procédure BouclageEcriture() joue le rôle d'une très puissante macro qui génère et mesure des boucles. Ainsi, c'est là, je pense que la boucle est bouclée...