Session D-WOOD

Debugging in VFP

Jürgen Wondzinski
ProLib Software GmbH


Einleitung

Klar machen auch Sie Fehler (getreu dem Spruch: Wer viel arbeitet, macht viele Fehler, wer nix arbeitet...), daher gehört Fehlersuchen zu den „beliebtesten“ Aufgaben eines jeden Programmierers. Die Vielzahl der in VFP möglichen Überwachungsmethoden kann aber leicht verwirren.

Der Debugger hat zahlreiche Konfigurationsmöglichkeiten, einige neue Möglichkeiten in den Programmablauf einzugreifen und zahlreiche neue Funktionen zu bieten. Es gibt neue Fenster, die innerhalb des Debuggers zusammengefaßt sind. Der Debugger muß nicht mehr nur innerhalb von VFP laufen, er kann auch als separater Task ausgeführt werden.  Ein ganzer Schwung Befehle und Funktionen im VFP Sprachumfang erleichtern und verbessern das Debuggen und Tracen.

Optionen

Wie immer: Bevor Sie das erste mal was verwenden, sollten Sie es einmal richtig einstellen. Für den Debugger finden Sie dazu im Menü "Extras" im "Optionen" Dialog eine eigene Seite reserviert:

Allgemeine Optionen

Als wichtigste globale Option kann bestimmt werden, wie der Debugger arbeiten soll: Als eigener Task, oder innerhalb des FoxPro Fensters. Als Standard Einstellung läuft der Debugger als eigener Task. Dies hat den Vorteil, daß alle Debugfenster mit einem ALT-TAB Task Switch erreicht werden können, oder daß der Debugger neben der eigentlichen Applikation angezeigt werden kann (bei ausreichend großem Monitor). Wenn Sie zu den wenigen Glücklichen gehören, die einen Super-Luxus Rechner mit zwei Monitoren besitzen: Ja, der Debugger kann auf dem einen Monitor laufen und ihr Programm auf dem anderen.

Wenn der Debugger im FoxPro Task mitläuft, können die verschiedenen Fenster einzeln aktiviert werden, wie vom alten Debugger bekannt. Die Fenster des Debuggers können auch als Toolbars ‘gedockt’ werden. Damit ist es möglich, Fenster ‘aus dem Weg zu räumen’. Mittels der RechtenMaus-Taste können Sie sie danach wieder jede der Toolbars entdocken bzw ganz ausschalten.

Falls diese DropDown-Listbox mal disabled sein sollte: Dann haben Sie schon ein Debugger Fenster offen.

Eine weitere allgemein einzustellende Option betrifft Timer-Ereignisse und dessen Code. Dies kann ein sinnvolles Debuggen von Programmen, die Timer Ereignisse enthalten, erst ermöglichen, ist aber im normalen Debugmodus eher hinderlich, da ihr Codefensterinhalt mit jedem Timerevent den Inhalt vom zu tracendem Programm zum Timercode wechselt. Für die Konzentration nicht sonderlich gut.... Also nur im Ausnahmefall einschalten!  So: Was gibts noch?

Optionen für Fenster

Für jedes der fünf Einzelbereiche können nun weitere Optionen eingestellt werden, wie zB Schriftart, Größe und Farbe. Hier können Sie ruhig etwas mutig werden und zb die Einstellung "Ausgewählter Text" etwas besser hervorheben.

Für das Ausgabefenster kann festgelegt werden, ob und in welche Datei die Ausgaben zusätzlich erfolgen sollen. Dies kann ab und an ganz praktisch sein, wenn sie zb die Ereignissequenz einer Form ausdrucken und an die Wand pinnen wollen. (Macht bei unbedarften Büro-Besuchern immer was her!)

Für das Trace Fenster können hier die Einstellungen vorgenommen werden, die in früheren Versionen des Trace Fensters per Menü zu wählen waren, wie zB die Einstellung ob Zeilennummern angezeigt werden sollen und wie groß die Verzögerung beim Ablauf im Trace Fenster zwischen zwei Zeilen sein soll (Throttle).

Die Fenster

Die auffälligste Änderung beim ersten Aufruf des neuen Debuggers ist, daß nun gleich fünf Fenster geöffnet werden können: Aufrufliste, Aktuelle Variablen, Ausgabe, Programmverfolgung, Überwachung; oder auf neudeutsch: Call Stack, Locals, Output, Trace und Watch.

Progammverfolgung (Trace)

Das Trace Fenster enthält wie auch der Editor und das Kommando Fenster, ‘Syntax Coloring’. Dadurch werden die verschiedenen Sprachelemente (Kommandos, Variablen, Kommentare, usw.) in unterschiedlichen Farben dargestellt. Welche Farben verwendet werden, hängt von den Einstellungen in den Optionen ab.

Man kann im Trace Fenster sehr einfach und schnell feststellen, welchen Wert eine Variable hat: Einfaches ‘Überfahren’ mit der Maus zeigt den Wert der Variable im ‘Tool Tip’ an. Das funktioniert auch beim Zurückscrollen im Programm.

Die Möglichkeiten, den nächsten Befehl auszuführen, einen Befehl zu ‘überspringen’ (Step over) bzw. aus der aktuellen Prozedur herauszuspringen sind erhalten geblieben. Neu hinzugekommen ist die Möglichkeit, das Programm bis zur Zeile, in der der Cursor steht, auszuführen. Dies kann das Setzen eines extra Haltepunktes ersparen.

Völlig neu ist die Möglichkeit, den Programmablauf an einer selbst gewählten Stelle fortzusetzen. Damit sind Korrekturen im Programm noch zur Laufzeit möglich. Eine fehlerhafte Programmzeile kann ausgelassen (und im Kommandofenster durch eine ‘verbesserte Version’ ersetzt werden) und das Programm in der nächsten Zeile fortgesetzt werden.Auch kann zb der Programmlauf nochmals einige Zeilen zurück aufgesetzt werden.

Ein neues Feature, das zur Produktivität des Entwicklungsprozesses beiträgt, ist die Möglichkeit, sobald ein Fehler festgestellt wurde, in den entsprechenden Sourcecode zu springen. Im ‘Debug’ Menü des Debuggers gibt es dafür den Eintrag ‘Korrigieren’. Durch Anwahl dieses Menüpunktes wird das laufende Programm gestoppt und in VFP die Entwicklungsumgebung gestartet. Es wird die Prozedur im Editor gezeigt, die gerade in Ausführung war. Dies gilt auch für Code in Methoden oder sogar in Klassen: Die Maske oder die Klasse wird im Designer geöffnet und der jeweilige Code Abschnitt zum Editieren geöffnet. Dies funktioniert auch bei Klassen, die in der Hierarchie weiter oben liegen und den Sourcecode an die Objekte vererbt haben.

Haltepunkte

Haltepunkte lassen sich durch einen Doppelklick in den Randbereich des Trace Fensters setzen. In einem erweiterten Breakpoint Dialog können Haltepunkte neu gesetzt, gelöscht oder deaktiviert werden. Vorsicht: Veränderungen an Haltepunkten können nicht vorgenommen werden; sondern der veränderte Haltepunkt muß mit ‘Hinzufügen’ aufgenommen werden und der original Haltepunkt dann gelöscht werden.

Haltepunkte können auch an Zusatzbedingungen gebunden werden. So wird das Programm an dieser Stelle nur gestoppt, wenn die Zusatzbedingung erfüllt ist. Außerdem ist es möglich, einen Haltepunkt ab einer bestimmten Anzahl von Durchläufen einer Programmzeile zu aktivieren (Sie kennen das sicher: 100 mal aktiviert, 100 mal is nix passiert... erst beim 101 mal kracht's.)

Im Breakpoint Dialog erscheinen auch Haltepunkte, die im Watch Fenster gesetzt wurden. Haltepunkte können deaktiviert (‘disabled’) werden, so daß sie den Programmablauf nicht beeinflussen. Ihre Definition bleibt erhalten. Sie können damit jederzeit wieder ‘eingeschaltet’ werden.

Die Haltepunkte können mittels ‘Datei’; ‘Konfiguration speichern’ als Debugger Einstellungen gesichert werden und später projektbezogen wieder geladen werden. Die Haltepunkte (und die beobachteten Variablen) müssen also bei einem Programmabbruch nicht verloren gehen.

Überwachungsfenster (Watch)

 Das Watch Fenster war bereits in ‘alten’ Versionen des Debuggers enthalten. Auch bei diesem Fenster wurden einige Überarbeitungen vorgenommen. Das Zufügen von weiteren Ausdrücken ist nur noch eine Eingabezeile oder per Drag & Drop möglich. Es können wesentlich mehr Ausdrücke als in den bisherigen Versionen des Debuggers beobachtet werden.

Arrays und Objekte können in das Watch Fenster aufgenommen werden und in einer hierarchischen Darstellung beobachtet werden. Es muß nicht jedes zu beobachtende Arrayelement separat aufgenommen werden. Besonders wichtig ist diese Möglichkeit jedoch, um die Eigenschaften von Objekten auszuwerten. Die gesamte Hierarchie eines Objektes kann angezeigt werden. Einzelne Eigenschaften können separat beobachtet werden.

Per Drag und Drop können sie auch direkt aus dem Trace oder Codefenster Variablen, Felder oder Funktionsausdrücke in die Debug-Fenster  ziehen.

Auch der Datentyp wird nun zusätzlich zu den Werten angezeigt. Verändert sich der Wert einer Zeile im Watch Fenster, so wird dieser Wert rot dargestellt. Damit sind Veränderungen schnell zu erkennen, auch wenn das Fenster viele Zeilen enthält.

Im Watch Fenster ist es nun auch direkt möglich, den Wert einer Variablen zu verändern. So kann zur Laufzeit der sich anbahnende Fehler (wegen fehlendem oder falschem Variableninhalt) noch während des Debuggens korrigiert werden und der Programmlauf fortgesetzt werden. (Ansonsten müssten sie das Debuggen stoppen, den Fehler in Code berichtigen, neu kompilieren und wieder das Debuggen anstarten... puhh)

Durch einen Doppelklick in den Randbereich können Haltepunkte gesetzt werden, die bei der Änderung des Wertes aktiviert werden.

Aktuelle Variablen (Locals) Fenster

Das Locals Fenster ist ein neues Fenster. Es zeigt in einer ähnlichen Weise wie das Watch Fenster Werte von Variablen an. Für Arrays und Objektvariablen gibt es auch hier die Möglichkeit der hierarchischen Darstellung. Es gibt allerdings keine Möglichkeit den Inhalt des Fensters festzulegen oder Werte von Ausdrücken anzuzeigen. Es werden die jeweils für den aktuellen Programmabschnitt gültigen Variablen mit ihren Werten angezeigt.

Für Programmabschnitte (Prozeduren, Methoden), die im Programmstack enthalten sind, können die jeweils gültigen Variablen angezeigt werden. Damit besteht die Möglichkeit, Probleme, die durch den Gültigkeits­bereich von Variablen entstehen, zu er­kennen.

Ausgabefenster (Debug Output)

                                                                                                                                                   Das Debug Output Fenster ist das dritte neue Fenster. Es zeigt Ausgaben, die mit Debug Befehlen im Programm erzeugt wurden (DebugOut) und, wenn diese Option aktiviert wurde, die Ereignisse an.

Das Anzeigen von Ereignissen kann per Dialog ein­gestellt werden. Es kann ausgewählt werden, welche Ereignisse dargestellt werden sollen. Die ‘Mouse Move’ und die Paint Events sollten normalerweise ausgeschaltet werden.


Die Ausgaben des Output Fensters können natürlich wieder zusätzlich in eine Datei mitprotokolliert werden. Damit ersetzt es die früher gern gemachten SCREEN ausgaben, die ja immer an den Stellen ausgegeben werden, die von irgendeiner anderen Form verdeckt sind...

Aufruf-Stack (Call Stack) Fenster

Das Aufruf-Stack Fenster ist ebenfalls ein neues Fenster. Ein Teil der Funktionalität des Aufruf-Stack Fensters war in den früheren Versionen des Debuggers im Menü des Trace Fensters enthalten.

Das Aufruf-Stack Fenster zeigt die Aufrufabfolge bis zum aktuellen aktuellen Programmabschnitt an. Bei der An­wahl von Pro­zeduren in der Hierarchie wird jeweils im Trace Fenster angezeigt, wo der Programmzeiger des dortigen Programmabschnittes steht.

Event Tracking

Was früher sehr mühsam per Hand bzw. mit einem Tool erledigt werden mußte, ist nun im Debugger integriert: Die Möglichkeit, die Ereignisse in einem Programm zu verfolgen.

Diese Option kann programmatisch mit ‘SET EVENTTRACK ON’ bzw. über die Toolbar aktiviert werden. Es kann zusätzlich eingestellt werden, welche Ereignisse im der Ausgabe erscheinen sollen. Achtung: Die beiden Events 'MouseMove' und 'Paint'  sollten, bis auf Ausnahmefälle, immer abgestellt werden, da sie ansonsten den Wald vor lauter Bäumen nicht mehr sehen. Die Ereignisliste kann aber auch programmgesteuert per ‘SET EVENTLIST TO ....’ zugewiesen werden.

Die Ausgabe kann natürlich zusätzlich als Protokoll in eine Datei geschrieben werden.

Vergessen Sie nicht, über den Hauptschalter (links oben im Dialog) das generelle Tracking einzuschalten, wenn Sie in diesem Dialog Einstellungen vornehmen, sonst passiert garnix.

Sehr brauchbar ist die Ereignisverfolgung, um sich endlich mal Klarheit über den Ablauf der Ereignisse beim Starten einer Form zu verschaffen...

Toolbar

Die Debug-Toolbar erscheint entweder automatisch, sobald Sie eines der Debugfenster geöffnet haben, oder  Sie verankern sie dauerhaft, indem Sie unter dem Menüpunkt "Ansicht" bei Symbolleisten diese Toolbar aktivieren. Sie bietet alternativ zum Menü einen schnellen Zugriff auf die wichtigsten Eigenschaften:

Neben dem obligaten "Datei Öffnen" Punkt haben wir die Möglichkeit, einen angehaltenen Programmlauf wieder anzustarten (identisch mit RESUME), bzw ganz abzubrechen (CANCEL).

Danach folgt eine Vierergruppe mit den Sinnbildern für "Hineinspringen", "Überspringen",  "Herausspringen" und "an Position springen".  Damit können Sie nach dem Laden des Programmes den Debuglauf anstarten, bzw Zeile für Zeile durchsteppen. Falls sie in einer Unterroutine gelandet sind (zB Menüaufbau), von der sie genau wissen, daß hier kein Fehler auftritt, so können sie mit "Herausspringen" den Rest der Unterroutine ablaufen lassen und erst bei Rücksprung in die höhere Ebene wieder in den Tracemodus schalten.  Analog dazu können sie mit "Überspringen" gleich den Subroutinen –Aufruf  ungetracet durchlaufen lassen. Wenn Sie die Stelle, an der ihr Problem auftritt, schon einigermassen wissen, können Sie einfach ihren Cursor an die entsprechende Programmcode-Zeile stellen, und dann mittels "an Position springen" das Programm bis dorthin ausführen lassen.

Die nächsten fünf Buttons schalten die oben besprochenen Teilfenster des Debuggers ein bzw aus.

Die letzte Dreier- und Zweiergruppe bedient den Haltepunktdialog und den Coverage-Profiler- bzw Ereignisverfolgungsdialog.  Da für diese Programmteile kein entsprechender Menüpunkt existiert, ist dies der einzige Aufrufpunkt. Dummerweise sind die Buttons nur aktiviert, wenn zumindest ein anderes Debugfenster offen ist.

Tastatur-Kürzel

Obwohl der Debugger auch die recht nützliche Toolbar hat, ist es speziell im Einzelschritt-Modus sehr praktisch, daß man auch direkt über die Tastatur den Programmfluß steuern kann.

Hier als Tabelle zum Ausschneiden und "Hintern Monitor pappen":

Aktion Taste
Abbrechen ESC
Wiederaufnehmen F5
Überspringen F6
Ausführen bis Cursor F7
Hineinspringen F8
Haltepunkt setzen/löschen F9
Herausspringen UMSCHALT+F7
Fenster "Debug-Ausgabe" ALT+2
Fenster "Überwachung" ALT+3
Fenster "Aktuelle Variablen" ALT+4
Fenster "Aufruf-Stack" ALT+7
Fenster "Programmverfolgung" ALT+8
Konfiguration speichern ALT+S
Alle Haltepunkte löschen STRG+UMSCHALT+F9
Dialogfeld "Haltepunkte" STRG+B
Datei öffnen STRG+O
Debugger beenden ALT+F4


Neue Befehle und Funktionen

Im Zusammenhang mit den neuen Möglichkeiten für den Debugger wurde auch der Befehlsumfang der Sprache erweitert:

Debug

Der Befehl ‘Debug’ startet den Debugger, aber er aktiviert ihn nicht. Um den Debugger direkt zu aktivieren, ist es besser wie bisher den Befehl ‘SET STEP ON’ zu verwenden. Wenn der Debugger vor dem Start des Programms schon aktiv war, dann aktiviert ‘Debug’ nur das Debugger-Fenster.

DebugOut

Mit dem DebugOut Kommando ist es möglich, beliebige Messages in das Debug Ausgabe Fenster (bzw. in der Protokoll Datei) zu schreiben. Falls der Debugger nicht aktiv ist, passiert garnichts. Hinter dem Befehl DEBUGOUT kann dann ein String stehen oder eine Funktion, die einen String zurückliefert (z.B. Program()).

Damit ist dieser Befehl ein ideales Mittel, um während der Programmierphase die üblichen Statusmeldungen auszugeben, die man sonst mittels WAIT WINDOW oder "?" ausgegeben hat.

Im Kommando DebugOut können beliebige Ausdrücke verwendet werden. Dadurch ist es möglich, auch eigene Routinen einzubinden, die übrigens auch dann abgearbeitet werden, wenn das Programm ohne Debugger läuft. D.h. es wird nur die Ausgabe unerdrückt, nicht aber der Test.

Mit ‘Set DebugOut to <xxx>’ können die Ausgaben zusätzlich in eine Protokolldatei gelenkt werden, womit die Möglichkeit besteht, auch bei Kunden vor Ort Protokolle von kritischen Programmteilen zu erstellen.

Falls Sie das letzte Quentchen Performance aus ihren Programmen rausholen wollen, so empfiehlt es sich, in die globale INLUDE Datei folgende Zeile reinzusetzen (und danach alles neu durchzukompilieren):

    #DEFINE  DEBUGOUT  NOTE

Damit werden diese Zeilen zum Kommentar, und werden überhaupt nicht mehr ausgeführt....

Assert

Mit dem ASSERT Befehl kann die Einhaltung von bestimmten Bedingungen an bestimmten Programmpunkten gewährleistet werden (to assert: zusichern). In den Zeiten vor ASSERT haben sie bestimmt viele Male folgenden Code geschrieben, um einem hartnäckigen Fehler auf die Spur zu kommen:

    IF DebugMode
       WAIT WINDOW "Testwert ist: " + BöseVariable
    ENDIF

Wenn sie nun vor dem Programmlauf die globale Variable DebugMode auf .T. setzen, dann können sie die Früchte ihrer Arbeit auch sehen. Danach müssen sie entweder alle WAIT WINDOWs wieder aus dem Programmcode entfernen, oder sie setzen die Variable wieder auf .F., mit dem Erfolg, daß die IF Bedingung auch in der EXE immer wieder abgefragt wird. Der Befehl ASSERT ist nun quasi VFPs Antwort auf diese Methodik.  Anstatt dessen schreiben sie nun:

    ASSERT BöseVariable # "0815"  MESSAGE "Hier schepperts!"

Mit dem Befehl SET ASSERTS ON können sie nun global die ASSERT Überprüfung einschalten,  und nur dann werden diese Zeilen abgearbeitet. Falls dann ihre BöseVariable tatsächlich den Wert 0815 beinhaltet, wird eine Messagebox angezeigt:

Der ASSERT hat also folgende Syntax:

    Assert <lExpression> [Message cMessageText]

Nur wenn der logische Ausdruck als falsch ausgewertet wird, wird eine Messagebox, optional mit dem Text cMessageText, angezeigt. In der Box können dann die Optionen Debug, Abbrechen, Ignorieren und Alle Ignorieren gewählt werden. Man kann also entweder in den Debugger springen, um nachzusehen was genau passiert ist, oder das Programm abbrechen (weil man eh schon weiß, was los ist), oder aber die Nachricht ignorieren. Der Punkt ‘Alle ignorieren’ entspricht dem Befehl SET ASSERT OFF. Die Meldungen des Assert Befehls (cMessageText) erscheinen übrigens auch im Debug Ausgabe Fenster.

Der SET ASSERT ON | OFF Befehl ist die kleine Gemeinheit beim ersten Test dieses Befehls: Die Standardeinstellung für Assert ist nämlich ‘OFF’ was bedeutet: die Assert Befehle sollen ignoriert werden. In der ausgelieferten Version eines Programms sollte diese Einstellung natürlich so stehen, aber während der Programmentwicklung kann dieser Befehl aber sehr nützlich sein, insbesondere wenn mehrere Leute zusammen arbeiten oder ein Programmteil bzw Klasse eines anderen Programmierers eingesetzt werden soll. Wenn dort die entsprechenden Assert Befehle verwendet werden, können Fehler, die eventuell erst in späteren Teilen der Routine auftauchen, oder zu unerklärlichen Fehlern führen, früh abgefangen werden (sogar mit passender Meldung).

Als Tip hier die Empfehlung, den ASSERT Befehl prinzipiell am Anfang jeder Prozedur oder Funktion einzusetzen und damit die übergebenen Parameter abtesten. Da Parameter-Übergabefehler schon zur Testpahse auftauchen, ist der ASSERT wesentlich besser geeignet, als die üblichen

    IF PARAMETER() > 2 AND TYPE("tcPara2") = "C" ...

Abprüfungen, die ja dann im Echtbetrieb auch dauernd laufen und dann Zeit kosten.

Sonstige Debug-Möglichkeiten

SYS(1023) / SYS(1024)

Mit diesen beiden Funktionen können Sie die Übergabe der HelpContextId an die Windows-Hilfe-Engine überprüfen. SYS(1023) schaltet den Überwachungsmodus ein, und SYS(1024) wieder aus.

Wenn sie in ihrer laufenden Form dann die F1 Taste drücken, erhalten sie folgenden Dialog:

Auf diese Weise können Sie die den Objekten zugewiesenen HelpContextIds überprüfen, und wahlweise durch "Ja"  auch den entsprechenden Hilfetext anzeigen lassen. Dieser Modus ist sinnvoll, wenn die Online-Hilfe mal nicht das anzeigt, was Sie meinen.....

SYS(1270) / SYS(1271) / SYS(1272)

Die SYS(1270) Funktion ist eine der wenigen, die sie in kürzester Zeit nicht mehr missen wollen: Sie gibt ihnen die Objektreferenz des Objektes zurück, über dem die Maus gerade steht. (Alternativ können Sie auch die X und Y Koordinaten einer Bildschirmposition angeben).

Die SYS(1271) wiederum gibt den physikalischen Dateinamen der Form aus, auf der die übergebene Objektreferenz lebt. Klingt kompliziert, hmm? Einfach mal im Debugfenster eingeben:

    SYS(1271, SYS(1270))

Allein durch Positionieren der Maus über verschiedene Forms erhalten sie nun den Dateinamen der Maske. Aber das Beste ist die SYS(1272), die uns die komplette Objekthierarchie eines übergebenen Objektes ermittelt.

    SYS(1272, SYS(1270))

Nun erhalten sie wiederum nur durch das Drüberfahren mit der Maus den kompletten Objektnamen. Als weiterer praktischer Anwendungsfall wäre zu nennen:

    ON KEY LABEL F12o = SYS(1270)

Nun können sie beim Debuggen einfach die Maus über ein suspektes Objekt schieben, F12 drücken, und im Debugger nun das Objekt "o" genau durchleuchten.  Oder im Befehlsfenster dieses O direkt manipulieren... Je mehr sie damit rumspielen, um so mehr Möglichkeiten werden sie entdecken.  Wichtig dabei ist nur eins: Wenn Sie das Ergebnis von SYS(1270) auf eine Variable leiten (hier das "o") dann haben sie eine weitere Objektreferenz auf die Form (bzw eines Unterobjektes auf der Form). Sie müssen diese Referenz zuerst löschen, bevor sie die Form wieder schliessen. Falls nicht, kann die Form nicht komplett geschlossen werden; Sie haben dann eine "hängende Referenz", die sie zuerst wieder loswerden müssen.

Coverage

Mit dem ‘Coverage’ Befehl können besonders kritische Programmteile exakt unter die Lupe genommen werden. Dies kann sowohl den Programmablauf, als auch die Performance betreffen.

Mit ‘Set Coverage to <xxx>’ werden für alle ausgeführten Programmzeilen diverse Informationen in die Datei <xxx> geschrieben:

    ·         Die Zeit, die für die Programmzeile benötigt wurde,

    ·         die Klasse, aus der die Programmzeile stammt,

    ·         die Prozedur,

    ·         die Zeilennummer,

    ·         sowie der Dateiname aus dem der Befehl stammt

Natürlich können Sie den Namen der Logdatei auch visuell durch Anwahl des vorletzten Buttons auf der DebugToolbar wählen.  Abgeschaltet wird der Spuk durch erneutes Aufrufen von SET COVERAGE TO ohne Dateiname.

Diese Log-Datei wird, wenn große Programmstücke damit protokolliert werden, übrigens recht lang (vor allem, wenn sie mal eine Schleife ein paar tausend mal durchlaufen...).

Die Werte, die mit COVERAGE erzeugt werden, sind, was die Ausführungszeiten betrifft, nicht sehr sinnvoll und wiederholbar, da natürlich allein das Wegschreiben dieser Daten zu Verzögerungen führt und auch eventuelle Systemereignisse in Windows selbst mit in die Ausführungszeiten eingehen. Daraus folgt, daß eigentlich nur vergleichende Wertungen vorgenommen werden können. Auch sind bei den heutigen Rechnertechnologien die Ausführungszeiten pro Befehlszeile so gering, daß zu 80% als Zeitdauer nur 0,000 Sekunden angegeben wird. Daher empfiehlt es sich, für solche Tests den alten 486er auszugraben... Was man aber sehr wohl aus den Coverage Dateien ziehen kann, sind Informationen, wie oft eine Zeile angesprungen wurde, welche Programmzeilen überhaupt nicht durchlaufen wurden oder in welcher Sequenz die Subroutinen durchgelaufen sind.In der Praxis wird man also mit eingeschaltetem Profiler seine Applikation einmal komplett durchlaufen lassen, und jede erdenkliche Option anstarten, sodass tunlichst alle Programmteile zumindest einmal angestartet wurden.

Die dabei entstandene Logdatei kann nun mit beliebigen Programmen ausgewertet werden. Seit VFP6 liefert Microsoft nun auch ein Standardauswerteprogramm namens COVERAGE.APP mit. Der Name dieses Programms ist wiederum in der Systemvariable _COVERAGE hinterlegt (Im Extras –> Optionen -> Dateiablage Dialog zu setzen). Im Extras Menü findet sich danach auch der Punkt "Erfassungsprotokoll-Profiler", der nach dem Start zuerst einmal die soeben erzeugte Logdatei anfordert. Danach wird meistens noch nach einigen Subprogrammen des gerade getesteten Programms gefahndet, und danach die Logdatei in Verbindung mit den Sourcecodezeilen gebracht.

Der Profiler kann zwei verschiedene Anzeigearten haben: den Erfassungsmodus und den Profilemodus. Schaun wir zuerst mal den ersteren an:

In der oberen Hälfte kann man nun die einzelnen Prozeduren bzw Programmteile auswählen, unten sieht man den dazugehörigen Programmcode. Die senkrechten Striche am linken Rand zeigen nun alle Stellen an, die beim Testlauf NIE durchgelaufen sind. Diese sind daher ungetestet und könnten rein theoretisch noch Programmfehler beinhalten.

Im Profiler-Modus siehts nun so aus:

Hier können wir nun erkennen, wie oft eine Programmzeile verwendet wurde, und wieviel Zeit für die Abarbeitung erstmalig und durchschnittlich notwendig war.  Anhand dieser Angaben kann man mit etwas suchen die langsamen Stellen in seinem Programm finden und eventuell optimieren.

Über die Toolbar kann man noch diverse Spielereien wählen: so zb ob die beiden Ausgabebereiche als Gruppiertes Fenster (wie oben) oder als zwei Einzelfenster laufen sollen. Über den Optionen-Dialog lässt sich unter anderm mit der hervorragend übersetzten Option "Umgebung" festlegen, ob die Dialogfenster als Top-LevelForm extern zu VFP laufen sollen, oder innerhalb des VFP-Hauptfensters.

Wer sich für die Details und Arbeitsweise des Programms interessiert, dem sei der Blick in die Datei HOME()+"\XSOURCE\ XSOURCE.ZIP angeraten: Hier sind alle Assistenten im Sourcecode vorhanden! Es steht also Tür und Tor offen, das Programm nach seinen Wünschen anzupassen.

Doch bevor Sie damit loslegen und im fremden Code rumpfuschen: Die Coverage.App ist schon vorgesehen für Erweiterungen, sog. Add-Ins.Ein solches AddIn hat zB. Markus Egger geschrieben: MaxCov.App (sie finden es auch auf der Begleit-CD).Über den Button 'AddIns' können Sie es ausführen, wenn sie eine Logdatei im Profiler-Modus geladen haben:

Es zeigt nun den Programm­code verdichtet und ausser­dem farbig hinterlegt an, sodass es wesentlich ein­facher ist, nach den Schwach­stellen in ihrem Programm zu suchen.

Alle Zeilen, die auffällig langsam sind, werden rot hinterlegt. Mehrfache Aufrufe sind in blau, und davon wiederum die langsamen in Fettschrift.

Tips und Tricks

....müssen natürlich auch sein!

Der Debugger hat heftig Probleme, wenn man Objekt-Eigenschaften anzeigen will, die als PROTECTED angelegt sind. Ist ja auch verständlich, denn auch der Debugger ist ein externer Zugriff. Um trotzdem die Werte anzeigen zu können, kann man in seine zentrale INCLUDE Datei reinsetzen:

    #DEFINE PROTECTED NOTE

Bedingt natürlich, dass diese Include-Datei auch in allen Klassen eingebunden ist....

    Noch einer:

Wenn Sie mehrere Forms mit PRIVATE DATASESSION laufen haben, dann zeigen die Debuggerfenster jeweils die Information aus der Datasession-Welt an, über der die Maus steht. Einfach nur die Maus über verschiedene Forms bewegen....

    Einen hab ich noch:

In den DEACTIVATE Event seiner FORM Basisklasse gehört auf jeden Fall ein

    ACTIVATE SCREEN

rein. Damit kann man erreichen, dass im interaktiven Modus die beliebeten Fragezeichen-Ausgaben vom Befehlsfenster aus nicht auf der aktuell laufenden Form erscheinen, sondern brav auf dem Screen.  Übrigens, wenn ihnen das zu kompliziert ist: Mittels

    _SCREEN.PRINT("Testausgabe" +chr(13))

können Sie natürlich auch explizit auf den Screen ausgeben. Mir persönlich zu kompliziert, dann doch lieber ein ? eintippen.

    ... und noch einen:

Und wenn sie diese Screen-Ausgaben wieder mal nicht sehen, dann sei an den berühmten Drei-Finger-Griff erinnert: Nein, nicht Ctrl-Alt-Del, sondern Shift-Ctrl-Alt, also die drei Tasten in der linken unteren Ecke Ihrer Tastatur. Alle drei gleichzeitig drücken: Solange sie drücken, werden alle Fenster weggeblendet, und sie haben Freie Sicht zum Mittelmeer (bzw. zu ihren Ausgaben).


vorheriger Vortrag D-REPO

zur Übersicht der Gruppe PROG

nächster Vortrag D-HOOK

 

dFPUG c/o ISYS GmbH

Frankfurter Str. 21 b

 

D-61476 Kronberg

per Fax an:

+49-6173-950903

oder per e-Mail an:

konferenz@dfpug.de

© Texte, Grafiken und Inhalt: ISYS GmbH