106 votes

Comment tester le temps d'exécution d'un code VBA ?

Existe-t-il un code en VBA avec lequel je peux envelopper une fonction qui me permettra de connaître le temps d'exécution, afin de pouvoir comparer les différents temps d'exécution des fonctions ?

92voto

Mike Woodhouse Points 27748

À moins que vos fonctions ne soient très lentes, vous aurez besoin d'une minuterie à très haute résolution. Le plus précis que je connaisse est QueryPerformanceCounter . Google pour plus d'informations. Essayez de placer ce qui suit dans une classe, appelez-la CTimer par exemple, vous pouvez créer une instance globale quelque part et appeler simplement .StartCounter et .TimeElapsed

Option Explicit

Private Type LARGE_INTEGER
    lowpart As Long
    highpart As Long
End Type

Private Declare Function QueryPerformanceCounter Lib "kernel32" (lpPerformanceCount As LARGE_INTEGER) As Long
Private Declare Function QueryPerformanceFrequency Lib "kernel32" (lpFrequency As LARGE_INTEGER) As Long

Private m_CounterStart As LARGE_INTEGER
Private m_CounterEnd As LARGE_INTEGER
Private m_crFrequency As Double

Private Const TWO_32 = 4294967296# ' = 256# * 256# * 256# * 256#

Private Function LI2Double(LI As LARGE_INTEGER) As Double
Dim Low As Double
    Low = LI.lowpart
    If Low < 0 Then
        Low = Low + TWO_32
    End If
    LI2Double = LI.highpart * TWO_32 + Low
End Function

Private Sub Class_Initialize()
Dim PerfFrequency As LARGE_INTEGER
    QueryPerformanceFrequency PerfFrequency
    m_crFrequency = LI2Double(PerfFrequency)
End Sub

Public Sub StartCounter()
    QueryPerformanceCounter m_CounterStart
End Sub

Property Get TimeElapsed() As Double
Dim crStart As Double
Dim crStop As Double
    QueryPerformanceCounter m_CounterEnd
    crStart = LI2Double(m_CounterStart)
    crStop = LI2Double(m_CounterEnd)
    TimeElapsed = 1000# * (crStop - crStart) / m_crFrequency
End Property

3 votes

Je l'ai mis en œuvre dans Excel VBA (en ajoutant les frais généraux comme indiqué dans cet article de la KB : support.microsoft.com/kb/172338 . Il a bien fonctionné. Merci.

2 votes

Merci, cela fonctionne bien pour moi aussi. TimeElapsed() donne le résultat en millisecondes. Je n'ai pas implémenté de compensation d'overhead car je m'inquiétais plus de l'effet d'un bégaiement dans le calcul de l'overhead que d'une précision parfaite.

2 votes

C'est beaucoup de surdonnées (en lignes de code à gérer) -- si vous pouvez vivre avec une précision de ~10ms, la réponse de @Kodak ci-dessous donne la même chose en une ligne de code (en important GetTickCount de kernel32).

62voto

dbb Points 1211

La fonction Timer de VBA vous donne le nombre de secondes écoulées depuis minuit, au 1/100 de seconde.

Dim t as single
t = Timer
'code
MsgBox Timer - t

18 votes

Ça ne marcherait pas. On ne peut pas obtenir plus de résolution en prenant la moyenne comme ça.

8 votes

Néanmoins, si vous mesurez les performances en VBA, obtenir une résolution de 1/100e de seconde n'est pas mal. -- L'invocation des appels de chronométrage peut à elle seule prendre quelques ms. Si l'appel est si rapide que vous avez besoin d'une telle résolution pour le chronométrer, vous n'avez probablement pas besoin de données de performance sur cet appel.

1 votes

notes : sur Mac, le chronomètre n'est précis qu'à la seconde près, ce qui peut donner des chiffres négatifs s'il commence avant minuit et se termine après minuit.

35voto

Kodak Points 577

Si vous essayez de retourner l'heure comme un chronomètre, vous pouvez utiliser l'API suivante qui renvoie le temps en millisecondes depuis le démarrage du système :

Public Declare Function GetTickCount Lib "kernel32.dll" () As Long
Sub testTimer()
Dim t As Long
t = GetTickCount

For i = 1 To 1000000
a = a + 1
Next

MsgBox GetTickCount - t, , "Milliseconds"
End Sub

après http://www.pcreview.co.uk/forums/grab-time-milliseconds-included-vba-t994765.html (car timeGetTime dans winmm.dll ne fonctionnait pas pour moi et QueryPerformanceCounter était trop compliqué pour la tâche nécessaire)

0 votes

C'est une excellente réponse. A noter : le précision des données retournées est en millisecondes, cependant, le compteur est seulement précis à environ 1/100e de seconde (c'est-à-dire qu'il peut être décalé de 10 à 16 ms) via MSDN : msdn.microsoft.com/fr/us/library/Windows/desktop/

0 votes

hmm, si la résolution est la même ici qu'avec le Timer, alors je choisirais le Timer.

0 votes

Quel est le Public Declare Function ... partie ? Une erreur se produit lorsque l'on ajoute votre code au bas du mien.

4voto

Erb Points 59

Pour les nouveaux venus, ces liens expliquent comment faire un profilage automatique de tous les abonnements que vous voulez surveiller :

http://www.nullskull.com/a/1602/profiling-and-optimizing-vba.aspx

http://sites.mcpher.com/share/Home/excelquirks/optimizationlink voir procProfiler.zip dans http://sites.mcpher.com/share/Home/excelquirks/downlable-items

2voto

Tom Juergens Points 1749

Nous utilisons depuis de nombreuses années une solution basée sur timeGetTime dans winmm.dll pour une précision à la milliseconde près. Voir http://www.aboutvb.de/kom/artikel/komstopwatch.htm

L'article est en allemand, mais le code dans le téléchargement (une classe VBA enveloppant l'appel de fonction de la dll) est suffisamment simple pour être utilisé et compris sans pouvoir lire l'article.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X