Performance-Tester als Access-Add-In

Zusammenfassung

Erstellen Sie ein Add-In zum Messen und Vergleichen der Performance von Funktionen.

Techniken

Formuare, Add-Ins, VBA, Klassen

Voraussetzungen

Access 2000 und höher

Beispieldateien

Beispieldatenbank.mdbPerformance.mda

André Minhorst, Duisburg

Die Performance einer Datenbankanwendung ist mithin ein entscheidender Faktor für die Akzeptanz beim Benutzer. Muss dieser bei bestimmten Aktionen länger als ein paar Sekunden auf die Anwendung warten, stellt sich schnell Unzufriedenheit ein. Nun dreht es sich in diesem Beitrag nicht um die Optimierung der Performance, sondern um die Messung der Resultate von Performance-Optimierungen. Und dabei erfahren Sie, wie Sie sich ein nützliches Add-In zur Messung der Performance bauen.

Die Performance einer Anwendung hängt in der Regel von vielen kleinen Faktoren und Bereichen ab, die man getrennt optimiert und entsprechend messen möchte. Für die Messung wird normalerweise die Zeit ermittelt, die die Anwendung für die Erledigung einer bestimmten Aufgabe benötigt.

Das ist auch bei dem Add-In der Fall, das Sie in diesem Beitrag kennen lernen: Es erwartet die Angabe zweier Funktionen mit der gleichen Aufgabe und ermittelt die von den Funktionen benötigte Zeit.

Zeit messen per API

Unter VBA gibt es verschiedene, unterschiedlich genaue Möglichkeiten zur Zeitmessung. Im hier verwendeten Tool kommen zwei API-Funktion namens QueryPerformanceCounter und QueryPerformanceFrequency zum Zuge, die man folgendermaßen deklariert (jeweils in einer Zeile):

Declare Function QueryPerformanceCounter Lib "Kernel32" (X As Currency) As Long
Declare Function QueryPerformanceFrequency Lib "Kernel32" (Y As _Currency) As Long

Die erste Funktion weist der als Parameter angegebenen Variablen den Zählerstand eines Prozessor-Counters zu. Wird dieser durch die mit QueryPerformanceFrequency ermittelte Counter-Frequenz geteilt, so erhält man in einer vom jeweiligen Rechner abhängigen Auflösung die Zeit in Sekunden. Um die Zeit zu messen, die eine Funktion benötigt, speichert man einmal den so ermittelten Wert in einer Currency-Variablen, ruft die Funktion auf und berechnet dann aus der Differenz des aktuellen Wertes und dem gespeicherten Wert die benötigten Sekunden.

üblicherweise möchte man mit einer Performance-Messung zwei oder mehr verschiedene Varianten einer Funktion vergleichen. Bevor man hier loslegt, sollte man sich zunächst im Klaren darüber sein, wo sich Optimierungen und damit auch Messungen überhaupt lohnen. Es gibt sicher viele Beispiele für kleine Code-Optimierungen, die eine änderung der benötigten Zeit im Bereich von Sekundenbruchteilen bewirken. Hier kann man den Hebel ansetzen, wenn diese Funktionen sehr, sehr oft aufgerufen werden oder wenn man die Anwendung wirklich bis ins Letzte auf Performance tunen möchte.

Bild 1: Das Performance-Test-Tool im Einsatz

Wer suchet, der findet

Zunächst sollten Sie sich jedoch auf die Suche nach den wirklichen Performance-Schluckern machen und diesen auf den Leib rücken. Bei dieser Suche hilft Ihnen das nachfolgend beschriebene Tool nicht. Sie sollen aber dennoch nicht ohne einen Tipp zu diesem Thema weiterlesen: Verwenden Sie doch einfach die QueryPerformanceCounter-Funktion an verschiedenen Stellen der Anwendung, die Ihnen verdächtig vorkommen.

Schauen Sie zunächst, welche Funktionen viel Zeit kosten, und verfeinern Sie die Suche anschließend, bis Sie optimalerweise die Zeile gefunden haben, die für unerwünscht hohen Zeitverbrauch verantwortlich sind.

Optimieren mit System

Haben Sie eine einzelne oder mehrere zusammenhängende Zeilen gefunden, die für schlechte Performance (mit)verantwortlich sind, haben Sie einen Ansatzpunkt für eine Optimierung. Manchmal lässt sich der Optimierungshebel genau an der gefundenen Stelle ansetzen, manchmal sind aber auch Operationen erforderlich, die sich auf weit größere Teile des Quellcodes beziehen.

Optimierungen quantitativ bewerten

Hier kommt nun endlich das Performance-Test-Tool zum Einsatz. Es sieht wie in Bild 1 aus und lässt sich wie folgt bedienen: Zunächst wählen Sie das Standardmodul oder das Formular aus, in dem sich die zu testende Routine befindet. Nach dem Auswählen des Objekts werden die weiteren Kombinationsfelder mit den im ausgewählten Modul enthaltenen Routinen gefüllt. Ganz wichtig: Die Routinen müssen als öffentliche Routinen deklariert sein! Sonst hat das Tool keine Möglichkeit, die Routinen aufzurufen.

Legen Sie nun zunächst fest, wie oft die Funktionen jeweils aufgerufen werden sollen. Das ist sinnvoll, wenn eine Routine sehr schnell abläuft – also beispielsweise schneller als eine Millisekunde -, aber in der eigentlichen Anwendung etwa in einer Schleife viele Male aufgerufen wird. Beginnen Sie einfach mit einer kleinen Zahl wie 1 oder 10 und arbeiten Sie sich dann in größere Dimensionen vor, wenn das Messergebnis nicht befriedigend ist. Anschließend legen Sie die zu vergleichenden Routinen fest. Hierbei ist Folgendes zu beachten:

  • Die Messung von Routinen in Formular-Modulen ist mit Sub- und Function-Prozeduren möglich.
  • In Klassenmodulen befindliche Methoden können Sie nicht direkt messen! Eine alternative Möglichkeit finden Sie allerdings weiter unten.
  • Wenn Sie die benötigten Daten eingegeben haben, klicken Sie einfach auf die Schaltfläche Test starten. Das Tool arbeitet die angegebenen Funktionen so oft wie angegeben ab und gibt im Formular die gemessene Zeit sowie die absoluten und relativen Abweichungen von der jeweils anderen Routine aus. Außerdem kennzeichnet es die schnellere und die langsamere Variante mit entsprechenden Symbolen (siehe Bild 1).

    Wie testet man Methoden aus Klassenmodulen

    Auf die Methoden von Klassenmodulen kann das Tool nicht direkt zugreifen. Der Grund ist, dass die Klasse dazu deklariert und instanziert werden müsste, was zwar prinzipiell möglich ist, aber nur, wenn der Name der Klasse zuvor bekannt ist. Das Tool soll aber als Add-In in beliebigen Datenbanken eingesetzt werden; somit müsste es zur Laufzeit zuvor nicht bekannte Klassen instanzieren. Das funktioniert mit VBA leider nicht, daher müssen Sie zur Messung der Performance von in Klassen verborgenen Methoden einen kleinen Umweg gehen.

    Dazu legen Sie in einem Standardmodul eine öffentliche Function-Routine an, die die gewünschte Klasse deklariert und instanziert und die entsprechende Methode aufruft. Das kann beispielsweise wie in Quellcode 1 aussehen.

    clsZeitmessungBeispiele ist eine Klasse mit den zwei Methoden EarlyBinding und LateBinding, die in Quellcode 2 abgedruckt sind.

    Die erste Funktion TestKlasse1 deklariert und instanziert ein Objekt der Klasse clsZeitmessungBeispiele und ruft die Methode EarlyBinding auf, die Funktion TestKlasse2 erledigt selbiges für die Methode LateBinding.

    Um zu vergleichen, welche der beiden Methoden schneller ist, wählen Sie einfach das Standardmodul mdlZeitmessungBeispiele und die beiden Funktionen TestKlasse1 und Testklasse2 im Performance-Mess-Tool aus und starten den Test. Die absolute Differenz zwischen den gemessenen Zeiten ist sicher aussagekräftig, bezieht sich jedoch auf den kompletten Aufruf inklusive Wrapper-Funktion und der eigentlich zu testenden Methode.

    Um den relativen Unterschied zwischen den beiden Methoden zu ermitteln, müssen Sie freilich noch einen draufsetzen: Das Tool bietet die Möglichkeit, eine Referenzfunktion anzugeben. Diese Funktion sollte alle Elemente bis auf die eigentlich zu testenden Anweisungen enthalten.

    Quellcode 1: Aufruf von in Klassen befindlichen Methoden

    Public Function TestKlasse1()
        Dim obj As clsZeitmessungBeispiele
        Set obj = New clsZeitmessungBeispiele
        obj.EarlyBinding
        Set obj = Nothing
    End Function
    Public Function TestKlasse2()
        Dim obj As clsZeitmessungBeispiele
        Set obj = New clsZeitmessungBeispiele
        obj.LateBinding
        Set obj = Nothing
    End Function
    Public Function TestKlasseReferenz()
        Dim obj As clsZeitmessungBeispiele
        Set obj = New clsZeitmessungBeispiele
        ''obj.LateBinding
        Set obj = Nothing
    End Function

    Quellcode 2: Methoden der Klasse clsZeitmessungBeispiele

    Public Sub EarlyBinding()
        Dim cbr As CommandBar
        Dim strName As String
        For Each cbr In Application.CommandBars
            strName = cbr.Name
        Next cbr
        Set cbr = Nothing
    End Sub
    Public Sub LateBinding()
        Dim strName As String
        Dim cbr As Object
        For Each cbr In Application.CommandBars
            strName = cbr.Name
        Next cbr
        Set cbr = Nothing
    End Sub
    

    Bild 2: Genaueres Messen der relativen Differenz durch Verwenden einer Referenzfunktion

    Bild 3: Einträge des Kombinationsfeldes cboModule

    In Quellcode 1 ist dies die dritte Funktion namens TestKlasseReferenz, die zwar ein Objekt der Klasse clsZeitmessungBeispiele erzeugt, aber keine Methode aufruft.

    Die Differenz der gemessenen Zeiten für die Funktionen mit den eigentlichen Aufrufen und des Referenzaufrufs liefert so einen wesentlich genaueren Wert für den relativen Unterschied beim Aufrufen der zu testenden Methoden.

    Ende des frei verfügbaren Teil. Wenn Du mehr lesen möchtest, hole Dir ...

    den kompletten Artikel im PDF-Format mit Beispieldatenbank

    diesen und alle anderen Artikel mit dem Jahresabo

    Schreibe einen Kommentar