Recherche de performances

violent_ken Messages postés 1812 Date d'inscription mardi 31 mai 2005 Statut Membre Dernière intervention 26 octobre 2010 - 2 sept. 2005 à 19:04
PCPT Messages postés 13272 Date d'inscription lundi 13 décembre 2004 Statut Membre Dernière intervention 3 février 2018 - 4 sept. 2005 à 22:09
Violent Ken

Salut. Je suis en train de faire un algorithme de calcul, et j'aimerais l'optimiser au maximum.
Par exemple, est-il plus rapide de faire

for x=1 to 10
a=a+30
next x

ou

for x=1 to 30
a=a+10
next x

est-il plus rapide de faire

if a=1 then
else
end if

ou d'utiliser Iif

est-il plus rapide de faire

While a < 500
a = a + 1
Wend

ou

Do Until a = 500
a = a + 1
Loop

a=b^0.5 ou a=sqr(b)

Il y a des tas de possibilités pour faire une même action, et j'aimerais que vous me donniez des astuces pour pouvoir 'optimiser' au maximum le code.
Merci, @+

Note: je sais que le C est bien plus rapide que le VB, mais je compte faire mon algo en VB

33 réponses

BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
2 sept. 2005 à 19:30
pour tes exemples de boucles for, aucune (désolé).
Quand tu peux faire le même traitement en décrémentant vers 0, c'est toujours la meilleure.
Raison de cela:
for x=1 to 10
a=a+30
next x

compilo mettra un truc de ce genre:
mov eax, 1 ; EAX = x, le compteur
lblFOR:
add edx, 30
inc eax
cmp eax, 10 ; ICI INSTRUCTION STUPIDE, faute du developpeur
jne short lblFOR

Si tu fais avec un do while i <> 0
mov eax, 10
lblWHILE:
add edx, 30
dec eax
jne short lblWHILE

1 cycle de pur benef par boucle.

suite sur cppfrance ou asmfr.

ciao...
BruNews, MVP VC++
0
violent_ken Messages postés 1812 Date d'inscription mardi 31 mai 2005 Statut Membre Dernière intervention 26 octobre 2010 2
2 sept. 2005 à 19:35
Violent Ken

Ok. Mais il est plus rapide de faire

b=sqr(5)
for x=1 to b

que de faire

for x=1 to sqr(5)

Y a t-il d'autres astuces ?
J'ai regardé http://www.vbfrance.com/code.aspx?ID=8198 , et il y a pas mal d'optimisations possibles, apparament.
@+
0
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
2 sept. 2005 à 19:44
là c'est évident, on n'appelle pas en boucle la même fonction qui recevra le même param, clair qu'il faut mettre dans une variable le résultat.
Pour le reste il y a peu à faire, en vb tu as très peu prise sur le code produit par le compilo.

ciao...
BruNews, MVP VC++
0
violent_ken Messages postés 1812 Date d'inscription mardi 31 mai 2005 Statut Membre Dernière intervention 26 octobre 2010 2
2 sept. 2005 à 19:45
Violent Ken

Ok.
Merci de l'info
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
cs_DARKSIDIOUS Messages postés 15814 Date d'inscription jeudi 8 août 2002 Statut Membre Dernière intervention 4 mars 2013 130
2 sept. 2005 à 20:01
Ben le plus simple, c'est de tester par toi même :



Tu fait une fonction pour chaque type d'optimisation que tu veux faire,
et tu l'appelle un bon milliers (voir un bon million) de fois, et tu
compare le temps mis pour éxécuter la boucle de la première fonction
avec la boucle pour executer la deuxième fonction, et tu répète ceci
plusieurs fois, ca te donneras déjà une idée de quelle fonction est la
plus rapide.

DarK Sidious

Un API Viewer (pour le VB, VB.NET, C, C# et Delphi) : www.ProgOtoP.com/popapi/
0
PCPT Messages postés 13272 Date d'inscription lundi 13 décembre 2004 Statut Membre Dernière intervention 3 février 2018 47
2 sept. 2005 à 21:57
je rejoins DarkSidious ;)

voivi comment je ferais :
'2 boutons, un label, et mon pitit Timer chéri

Option Explicit


Const NbBoucles As Long = 999 '999
Dim TabTest(NbBoucles) As Currency
Dim MinRes As Currency
Dim MaxRes As Currency


'
'
Private Sub Form_Load()
AfTimer.TypeTimer = BenchMark
CMD_Start.Enabled = False
LBL_EnCours.Caption = ""
End Sub
'
'
Private Sub CMD_Init_Click()
CMD_Init.Enabled = False

AfTimer.Enabled = True
Call MaProc
AfTimer.Enabled = False
MinRes AfTimer.Value: MaxRes AfTimer.Value

CMD_Start.Enabled = True
End Sub
'
'
Private Sub CMD_Start_Click()
Dim i As Long
Dim MoyenneMs As Currency, Mess As String

CMD_Start.Enabled = False
MoyenneMs = 0

For i = 0 To NbBoucles
LBL_EnCours.Caption = i + 1 & " sur " & NbBoucles + 1
AfTimer.Enabled = True
Call MaProc
AfTimer.Enabled = False
TabTest(i) = AfTimer.Value
If TabTest(i) > MaxRes Then MaxRes = TabTest(i)
If TabTest(i) < MinRes Then MinRes = TabTest(i)
DoEvents
Next i


For i = 0 To NbBoucles
MoyenneMs = MoyenneMs + TabTest(i)
Next i

MoyenneMs = MoyenneMs / (NbBoucles + 1)

Mess = "Nombre de Test : " & NbBoucles + 1 & vbCrLf & _
"Vitesse min = " & MinRes & "ms" & vbCrLf & _
"Vitesse max = " & MaxRes & "ms" & vbCrLf & _
"moyenne = " & MoyenneMs & "ms"

'MsgBox Mess
Debug.Print Mess


End Sub
'
'
Private Sub MaProc()
'ta procédure
End Sub

il ne faut pas oublier, pour être très précis, que l'appel, mêem vide, de la procédure, est une action qui prend aussi sont temps....

tu peux donc saisir ta procédure directement à l'endroit ou tu fais l'appel (les clicks)

voici quelques traces :


<HR>

Private Sub MaProc()
Dim x As Integer, a As Integer
For x = 1 To 10
a = a + 30
Next x
End Sub
Nombre de Test : 1000
Vitesse min = 0,0824ms
Vitesse max = 5,0811ms
moyenne = 0,1175ms



<HR>

Private Sub MaProc()
Dim a As Integer
a = 0
While a < 500
a = a + 1
Wend
End Sub


Nombre de Test : 1000
Vitesse min = 0,0833ms
Vitesse max = 21,1695ms
moyenne = 0,153ms



<HR>

Private Sub MaProc()
Dim a As Integer
a = 0
Do Until a = 500
a = a + 1
Loop
End Sub


Nombre de Test : 1000
Vitesse min = 0,0824ms
Vitesse max = 5,0811ms
moyenne = 0,1175ms


<HR>

nb : évidemment, AfTimer dispo dans mes sources
PCPT
0
us_30 Messages postés 2065 Date d'inscription lundi 11 avril 2005 Statut Membre Dernière intervention 14 mars 2016 10
2 sept. 2005 à 22:07
Entièrement d'accord avec DaksiDious...

Les tutos sur le sujet sont assez bien fait, en général et se recoupe très souvent... Mais il reste encore des choses à dire... Par exemple, sur les boucles FOR, il est préférable de déclarer la variable de la boucle (souvent pas fait), surtout lorsque la variable rentre dans un calcul (souvent le cas) afin d'éviter de passer par le type Variant (toujours à proscrire pour la rapidité)... Voici un exemple illustrant la chose...

=

Sub essai()

temps = Timer

Dim t As Long 'Déclaration : Variable de la boucle
Dim a As Long

For t = 1 To 20000000
a = t
Next t

MsgBox "La durée du test : " & Timer - temps & " seconde(s)"

End Sub

=

Amicalement,
Us.
0
cs_CanisLupus Messages postés 3757 Date d'inscription mardi 23 septembre 2003 Statut Membre Dernière intervention 13 mars 2006 21
2 sept. 2005 à 22:21
Salut, il manque un avis sur le :

if a=1 then
else
end if

ou d'utiliser Iif

Je n'ai pas testé la diff entre les 2 mais a priori, Iif est une fonction donc sans doute plus gourmande qu'un simple if .. then ...else...
D'autre part, penser à la maintenance, il se peut qu'on veuille rajouter 1 ou plusieurs instructions dans dans le if et/ou dans le else et le Iif n'est pas prévu pour ça.

Je rajouterai qu'il y a aussi les if...elseif....elseif....else... et dans ce cas, (en vb6) je préfère le select case que je pense plus rapide et plus simple à maintenir.

-------------------------------------------------
Dresseur de puces, .... normal pour un loup !?
0
violent_ken Messages postés 1812 Date d'inscription mardi 31 mai 2005 Statut Membre Dernière intervention 26 octobre 2010 2
2 sept. 2005 à 22:34
Violent Ken

Merci pour tout ces conseils, j'apprécie bcp.
Je vais moi même tester mes procédures, surtout qu'apparemment la pseudo-meilleure-rapidité d'un while/wend face à un do/until dépend des instructions contenues dans la boucle.
En tout cas, merci beaucoup
@+
0
us_30 Messages postés 2065 Date d'inscription lundi 11 avril 2005 Statut Membre Dernière intervention 14 mars 2016 10
2 sept. 2005 à 22:42
Pour le IIF, c'est moins rapide que IF ELSE, car toutes la fonction est analysé... donc avec : IIF ( condition , resultat si vrai, resultat si faux) : les trois paramètres sont passés en revue... contrairement à IF qui s'arrêterait si la condition est vraie, ou saute directement à ELSE dans le cas contraire... Bon, enfin tous ceci est expliqué dans l'aide de VB... où il préconise pas l'emploi IIF si on cherche à aller vite...

Mais voilà, perso, je trouve plus clair un code sur une ligne comme IIF, que les multiples lignes... bon, donc entre rapidité et clarté d'un code ?... faut choisir...

ET pour DO ?...

LE plus rapide c'est d'utiliser :

DO

LOOP condition

et DO...LOOP est toujours plus rapide que WHILE/WEND...



Ceci dit, je pense qu'on est pas prêt de tarir le sujet...

Us.
0
violent_ken Messages postés 1812 Date d'inscription mardi 31 mai 2005 Statut Membre Dernière intervention 26 octobre 2010 2
2 sept. 2005 à 23:11
Violent Ken

us_30, "l'étude" http://www.vbfrance.com/code.aspx?ID=25985 semble te donner raison pour les do/loop , while/wend (quoique, c'est pas évident)
Quant aux Select Case, il me paraissent plus lent que les if/then/else/end if
Et les ElseIf, je ne sais pas trop, je ne les utlilise jamais (à tort ?)
@+
0
PCPT Messages postés 13272 Date d'inscription lundi 13 décembre 2004 Statut Membre Dernière intervention 3 février 2018 47
2 sept. 2005 à 23:17
a = 1 2 3 ou 4

Select case a
case 1:...
case 2:...
case 3:...
case 4:...
end select

if a=1 then
...
elseif a=2 then
...
elseif a = 3 then
...
else
....
endif

je modifie un peu mon code ci dessus (Aftimer). en effet, je n'ai pas pris en compte que le fait de faire le test lui même, prend des ressouces, faussant donc les résultats

PCPT
0
cs_CanisLupus Messages postés 3757 Date d'inscription mardi 23 septembre 2003 Statut Membre Dernière intervention 13 mars 2006 21
2 sept. 2005 à 23:20
Tiens, puisqu'on cause de boucles (for ... next, do ... while, etc ...), un ptit DoEvents dans une boucle assez longue (en vb6) est souvent nécessaire.
C'est sans doute une instruction supplémentaire pour le processeur mais, en gros, ça lui dit qu'il peut reprendre la main pour exécuter d'autres tâches pendant que les opérations contenues dans la boucle ne le mobilisent pas.

Un avis différent ?

-------------------------------------------------
Dresseur de puces, .... normal pour un loup !?
0
violent_ken Messages postés 1812 Date d'inscription mardi 31 mai 2005 Statut Membre Dernière intervention 26 octobre 2010 2
2 sept. 2005 à 23:27
Violent Ken

Pour le cas du doevents, prenons le cas d'une boucle simple

For x=1 to 100000
L(x)=in(rnd*10)+1
next x
(tient d'ailleurs, y parait que ne pas mettre le x ne change pas grand chose, à voir)

Faut-il songer à mettre un doevents ?
A première vue non, puisque cette instruction ralentit considérablement la performance de calcul. Mais faut-il envisager une ligne du genre :
if (x mod 1000)=0 then doevents

Et est-ce que çà change qqchose de mettre
if ( x mod 1000)=0 then
ou bien, if not(x mod 1000) then
?
0
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
2 sept. 2005 à 23:33
DoEvents n'engendre pas qu'une instruction, c'est très gros en traitement. Dans tous les cas, pas moyen de faire un thread en vb alors faut s'en contenter.
PeekMessage
TranslateMessage
DispatchMessage

et tout cela en boucle.

ciao...
BruNews, MVP VC++
0
us_30 Messages postés 2065 Date d'inscription lundi 11 avril 2005 Statut Membre Dernière intervention 14 mars 2016 10
2 sept. 2005 à 23:40
Ah tiens ! je dérive un peu... Dans mon algo sur la multiplication de grand nombre, pour l'optimisation, j'ai été obligé de sortir un calcul une fois tous les 90 boucles... avec un truc semblable : if X mod 90 = 0 then ... J'avais planché un peu dessus pour trouver mieux... mais sans succès... si qlq'un trouve un truc mieux, s'y preneur...

(A noter que le test X mod... est exécuté dans une boucle, donc testé à chaque passage...)

Bon... pour en revenir à la dernière remarque de ViolentKen... une interruption, une fois tous les X fois, cela me semble une bonne idée pour pas trop pénaliser le traitement avec DoEvents...

Us.
0
PCPT Messages postés 13272 Date d'inscription lundi 13 décembre 2004 Statut Membre Dernière intervention 3 février 2018 47
2 sept. 2005 à 23:50
y'a pas à chier, il faut un DoEvents. et pas que tous les 1000 fois.
il suffit de tenter de déplacer une fenêtre pendant sa boucle durant un doevents, on voit vite pourquoi c'est indispensable !

NOT implique 2 calculs. il sera toujours plus long, mais plus "propre" en lecture de source

bon, voici mon code corrigé :
2 AfTimers + 2boutons + 1label

Option Explicit


Const NbBoucles As Long = 999 '999
Dim TabTest(NbBoucles) As Currency
Dim MinRes As Currency
Dim MaxRes As Currency
'
'
Private Sub Form_Load()
AfTimer_Proc.TypeTimer = BenchMark
AfTimer_Wait.TypeTimer = Classical
CMD_Start.Enabled = False
LBL_EnCours.Caption = ""
End Sub
'
'
Private Sub CMD_Init_Click()
CMD_Init.Enabled = False

AfTimer_Proc.Enabled = True
Call MaProc
AfTimer_Proc.Enabled = False
MinRes AfTimer_Proc.Value: MaxRes AfTimer_Proc.Value
AfTimer_Wait.Interval = Int(MinRes) * 2
CMD_Start.Enabled = True
End Sub
'
'
Private Sub CMD_Start_Click()
CMD_Start.Enabled = False
AfTimer_Wait.Enabled = True
End Sub
'
'
Private Sub AfTimer_Wait_Timer()
AfTimer_Proc.Enabled = True
Call MaProc
AfTimer_Proc.Enabled = False
End Sub
'
'
Private Sub AfTimer_Proc_BenchResult(WhichApi As String, Result As Currency)
Static Cpt As Long
LBL_EnCours.Caption = Cpt + 1 & " sur " & NbBoucles + 1
TabTest(Cpt) = Result
If TabTest(Cpt) > MaxRes Then MaxRes = TabTest(Cpt)
If TabTest(Cpt) < MinRes Then MinRes = TabTest(Cpt)
Cpt = Cpt + 1
If Cpt = NbBoucles + 1 Then
AfTimer_Wait.Enabled = False
Call FinTest
End If
End Sub
'
'
Private Sub FinTest()
Dim i As Long
Dim MoyenneMs As Currency, Mess As String
MoyenneMs = 0

CMD_Start.Enabled = True

For i = 0 To NbBoucles
MoyenneMs = MoyenneMs + TabTest(i)
Next i

MoyenneMs = MoyenneMs / (NbBoucles + 1)

Mess = "Nombre de Test : " & NbBoucles + 1 & vbCrLf & _
"Vitesse min = " & MinRes & "ms" & vbCrLf & _
"Vitesse max = " & MaxRes & "ms" & vbCrLf & _
"moyenne = " & MoyenneMs & "ms"

'MsgBox Mess
Debug.Print Mess
End Sub
'
'
Private Sub MaProc()
'...
End Sub

et voici les même traces :


<HR>

Private Sub MaProc()
Dim x As Integer, a As Integer
For x = 1 To 10
a = a + 30
Next x
End Sub

Nombre de Test : 1000
Vitesse min = 0,0265ms
Vitesse max = 0,4953ms
moyenne = 0,0315ms

<HR>

Private Sub MaProc()
Dim a As Integer
a = 0
While a < 500
a = a + 1
Wend
End Sub

Nombre de Test : 1000
Vitesse min = 0,0877ms
Vitesse max = 0,8029ms
moyenne = 0,0959ms

<HR>

Private Sub MaProc()
Dim a As Integer
a = 0
Do Until a = 500
a = a + 1
Loop
End Sub

Nombre de Test : 1000
Vitesse min = 0,0877ms
Vitesse max = 0,5649ms
moyenne = 0,097ms

<HR>

voilà qui est bien plus crédible, et qui ne prend que les ressources de la procédure + son appel (CALL ...)
AfTimer ici
PCPT
0
PCPT Messages postés 13272 Date d'inscription lundi 13 décembre 2004 Statut Membre Dernière intervention 3 février 2018 47
3 sept. 2005 à 12:45
umm, j'aurais supposé que mon timer aurait bien servi et remué les foules....
(à tord apparemment....)
PCPT
0
us_30 Messages postés 2065 Date d'inscription lundi 11 avril 2005 Statut Membre Dernière intervention 14 mars 2016 10
3 sept. 2005 à 16:32
Euh... à minuit tout le monde dort...

JE ne suis pas entièrement d'accord avec toi, sur deux points.

Pour DoEvents déjà. Tu dis qu'il le faut le mettre à chaque fois, pour permettre un déplacement de la fenêtre... Bon ok, mais pour moi, je conçois plus le DoEvents, pour que l'utilisateur puisse changer d'application, réduire la fenêtre ou arrêter la procédure en cours... Donc, c'est des actions qui n'ont pas besoin d'être testées en permanence... IL me semble, que si l'utilisateur lance un long calcul (pour peu qu'on l'informe), qu'il n'a pas besoin d'avoir en permanence la possibilité de déplacer la fenêtre de l'application... On parle d'optimisation, il faut revenir au sujet... Le DoEvents est évidemment une fonction à l'opposé d'une optimisation. Trouvé un moyen entre le besoin de convivialité et la performance, est nécessairement un compromis... et comment rendre cette contrainte acceptable ? ...la solution proposé par Violent Ken, me semble déjà intéressante...

Ma deuxième remarque, est sur ton code... L'idée est bien. Mais... Perso, je préfère utiliser ma façon, même si trop manuel. C'est à dire, mettre le compteur juste au début et juste à la fin de la partie de code à tester, évitant ainsi tout intermédiaire... déjà, parce que je peux mieux évaluer la différence (en pourcentage) entre deux façons de procéder... bon, ceci dit, quand on regarde les remarques pour ce genre de tests, on voit toujours que la première discorde se situe finalement sur le "protocole" pour tester... c'est peut-être déjà la première chose à bien définir... Perso, au vu du post précédent de BruNews, je pense que le meilleur c'est effectivement d'étudier le codage résultant en ASM, pour voir le plus court... mais, là je ne sais plus faire...

Amicalement,
Us.
0
PCPT Messages postés 13272 Date d'inscription lundi 13 décembre 2004 Statut Membre Dernière intervention 3 février 2018 47
3 sept. 2005 à 16:59
salut'
(mon post de minuit n'est que la correction de celui de 22h )

sans parler du fait de déplacer la fenêtre, prenons encore plus simple :

ouvre le gestionnaire des tâches (ou une appli avec jauge processeur)
fait une boucle sur 1million et pendant le travail, ferme l'appli (bouton fermer, ou un bouton UnLoad),
et regarde ce qui ce passe dans la jauge.

quand au fait d'appeler la procédure (test) directement, c'est bien ce que j'ai écris au départ.

"il ne faut pas oublier, pour être très précis, que l'appel, mêem vide, de la procédure, est une action qui prend aussi sont temps....
tu peux donc saisir ta procédure directement à l'endroit ou tu fais l'appel (les clicks)"

là, c'est uniquement pour une question de lisibilité. de plus, rien empêche de décompter le temps d'appel de la procédure vide....

toujours est-il que çà peut être bien pratique pour comparer efficacement les différences de temps de calculs, ce qui me semble être la question de départ...

PCPT
0
Rejoignez-nous