Come testate il tempo di esecuzione del codice VBA?


95

C'è del codice in VBA con cui posso racchiudere una funzione che mi farà sapere il tempo necessario per l'esecuzione, in modo da poter confrontare i diversi tempi di esecuzione delle funzioni?

Risposte:


81

A meno che le tue funzioni non siano molto lente, avrai bisogno di un timer ad altissima risoluzione. Il più preciso che conosco è QueryPerformanceCounter. Cercalo su Google per maggiori informazioni. Prova a inserire quanto segue in una classe, chiamalo CTimerdire, quindi puoi creare un'istanza da qualche parte globale e chiamare semplicemente .StartCountere.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

2
L'ho implementato in Excel VBA (aggiungendo l'overhead come menzionato in questo articolo della Knowledge Base : support.microsoft.com/kb/172338 . Ha funzionato benissimo. Grazie.
Lance Roberts

2
Grazie, funziona bene anche per me. TimeElapsed()fornisce il risultato in millisecondi. Non ho implementato alcuna compensazione del sovraccarico perché ero più preoccupato per l'effetto di una balbuzie nel calcolo del sovraccarico che per la precisione perfetta.
Justin

2
È molto sentito (in righe di codice da gestire): se riesci a convivere con una precisione di ~ 10 ms, la risposta di @ Kodak di seguito fornisce la stessa cosa in una riga di codice (importando GetTickCountda kernel32).
BrainSlugs83

Come usi StartCounterAnd TimeElapsed? Ho fatto un'istanza di Timer CTimerall'inizio e With StartCounterho appena scritto .StartCounterdopo l'inizio del mio sottomarino e .TimeElapsedmi ha risposto Invalid use of property. Quando lascio .StartCounterstare mi dice che un oggetto non è impostato.
Revolucion per Monica

Per Excel 2010: Declare PtrSafe Function stackoverflow.com/questions/21611744/...
user3226167

48

La funzione Timer in VBA ti dà il numero di secondi trascorsi dalla mezzanotte, a 1/100 di secondo.

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

18
Non funzionerebbe: non puoi ottenere più risoluzione prendendo la media in questo modo.
Andrew Scagnelli

4
Tuttavia, se stai misurando le prestazioni in VBA, ottenere una risoluzione di 1/100 di secondo non è male. - Richiamare solo le chiamate di temporizzazione potrebbe richiedere un paio di ms. Se la chiamata è così veloce da richiedere tanta risoluzione per calcolare il tempo, probabilmente non sono necessari i dati sulle prestazioni di quella chiamata.
BrainSlugs83

1
note: su Mac il timer è preciso solo un secondo - e questo potrebbe ottenere numeri negativi se inizia prima di mezzanotte e finisce dopo mezzanotte
TmTron

32

Se stai cercando di restituire l'ora come un cronometro, puoi utilizzare la seguente API che restituisce il tempo in millisecondi dall'avvio del sistema:

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

dopo http://www.pcreview.co.uk/forums/grab-time-milliseconds-included-vba-t994765.html (poiché timeGetTime in winmm.dll non funzionava per me e QueryPerformanceCounter era troppo complicato per l'attività necessaria)


Questa è un'ottima risposta. Da notare: la precisione dei dati restituiti è in millisecondi, tuttavia, il contatore è accurato solo a circa 1/100 di secondo (cioè potrebbe essere disattivato da 10 a 16 ms) tramite MSDN: msdn.microsoft.com / it-it / library / windows / desktop /…
BrainSlugs83

hmm, se la risoluzione qui è la stessa del timer, allora andrei con il timer
Kodak

Qual è la Public Declare Function ...parte? Crea un errore quando aggiungi il tuo codice in fondo al mio
Revolucion per Monica

È necessario spostare questa dichiarazione pubblica all'inizio del modulo
Kodak


3
Sub Macro1()
    Dim StartTime As Double
    StartTime = Timer

        ''''''''''''''''''''
            'Your Code'
        ''''''''''''''''''''
    MsgBox "RunTime : " & Format((Timer - StartTime) / 86400, "hh:mm:ss")
End Sub

Produzione:

RunTime: 00:00:02


2

Abbiamo utilizzato una soluzione basata su timeGetTime in winmm.dll per una precisione al millisecondo per molti anni. Vedere http://www.aboutvb.de/kom/artikel/komstopwatch.htm

L'articolo è in tedesco, ma il codice nel download (una classe VBA che racchiude la chiamata alla funzione dll) è abbastanza semplice da usare e da capire senza poter leggere l'articolo.


0

Secondi con 2 spazi decimali:

Dim startTime As Single 'start timer
MsgBox ("run time: " & Format((Timer - startTime) / 1000000, "#,##0.00") & " seconds") 'end timer

formato secondi

Millisecondi:

Dim startTime As Single 'start timer
MsgBox ("run time: " & Format((Timer - startTime), "#,##0.00") & " milliseconds") 'end timer

formato millisecondi

Millisecondi con separatore virgola:

Dim startTime As Single 'start timer
MsgBox ("run time: " & Format((Timer - startTime) * 1000, "#,##0.00") & " milliseconds") 'end timer

Millisecondi con separatore virgola

Lasciandolo qui per chiunque stia cercando un semplice timer formattato con secondi a 2 spazi decimali come me. Questi sono piccoli timer brevi e dolci che mi piace usare. Occupano solo una riga di codice all'inizio del sottotitolo o della funzione e di nuovo una riga di codice alla fine. Questi non sono pensati per essere pazzi precisi, in genere non mi interessa niente di meno di 1/100 di secondo personalmente, ma il timer dei millisecondi ti darà il tempo di esecuzione più preciso di questi 3. Ho anche letto te può ottenere la lettura errata se capita di eseguire durante l'attraversamento oltre la mezzanotte, un'istanza rara ma solo FYI.


Solo il primo è utile, poiché Timer ha una risoluzione di 10 ms.
Gustav
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.