Erweiterte Programmierung


Es gibt im Prinzip zwei unterschiedliche Techniken einen Fehler oder ein unerwünschtes Verhalten von ACComponents zu untersuchen:

 

Einfluss-nehmend

Es wird ein Debugger in den laufenden Prozess eingehängt und Haltepunkte an Codestellen gesetzt wo man den Fehler vermutet. Vorteil diese Methodik ist, dass man Schritt für Schritt den Programmfluss, Heap und Stack beobachten kann. Nachteil ist, dass alle Threads angehalten werden und das ist im Produktivbetrieb nicht wünschenswert und bei zeitkritischen Systemen sogar gefährlich. 

Das Debuggen können Sie mit drei unterschiedlichen Werkzeugen tun, auf die später näher eingegangen wird:

 

Nicht Einfluss-nehmend ("Print debugging")

Nicht Einfluss-nehmende Methoden bedeuten, dass man anhand des Speicher- bzw. Objektzustands und Trace-Hilfsmitteln die Fehlerursache im Programmcode findet. Vorteil dieser Methodik ist, dass der Prozess weiterläuft. Nachteil ist, dass die Suche des Programmfehlers zeitaufwendiger ist. Objektzustände können in iPlus mit den folgenden drei Werkzeugen betrachtet werden:

 

Microsoft Visual Studio® empfehlen wir für die Entwicklung Ihrer eigenen Assemblies und dem Debuggen Ihres Programmcodes in der Entwicklungsphase. Da die Installation von Visual Studio einen größeren Festplattenspeicherplatz erfordert und in Produktionsumgebungen oft das Internet gesperrt ist empfehlen wir den Einsatz von dnSpy für Produktionsumgebungen. 

Falls Sie Ihr Projekt entsprechend unserer Beispielprojekte erstellt haben, können Sie die *.client.exe direkt aus Visual-Studio heraus starten und der Debugger ist sofort aktiv. Falls Sie nur Ihre Assembly kompiliert haben und im iPlus-Installationsverzeichnis hinzugefügt haben, dann müssen Sie den Debugger an den laufenden Prozess anfügen.


dnSpy ist zum Debuggen in Produktionsumgebungen prädestiniert, weil die Installation sehr schlank ist.

Um den iPlus-Dienst oder eine iPlus *.client.exe zu debuggen gehen Sie folgendermaßen vor:

  1. Starten Sie dnSpy mit Administrationsrechten, damit Sie auch den iPlus-Dienst (gip.iplus.service.exe) debuggen können.
  2. Laden Sie die benötigten Assemblies aus dem iPlus-Installationsverzeichnis indem Sie zum Menüpunkt "File->Open" gehen und die entsprechenden Dateien auswählen.
  3. Öffnen Sie anschließend den Menüpunkt "Debug->Attach to Process" und wählen den Prozess aus, den Sie debuggen möchten:

 

  1. Navigieren Sie im Assembly-Explorer (linke Bildschirmhälfte) zu einer Methode in der Sie den Haltepunkt setzen möchten. dnSpy dekompiliert den IL-Code und zeigt Ihnen die Methode im rechten Codefenster an.
  2. Setzen Sie per Mausklick den Haltepunkt.

WinDbg eignet sich zur Untersuchung von Programmabstürzen, die nicht von der iPlus-Runtime abgefangen und im Logfile ausgegeben worden sind. Dieses Szenario kann auftreten,

1. Solche Programmabstürze werden mittels Windows Error Reporting protokolliert. Suchen Sie in der Windows-Ereignisanzeige nach WER-Einträgen, die Auskunft geben über das erstellte Dump-File:  

 

2. Anschließend starten Sie WinDbg (x64-Version) und öffnen das von WER erstellte Complete-Memory-Dumpfile das meist mit der Endung *.hdmp abgelegt wird. Das Small-Dumpfile gibt zwar Auskunft über den Callstack, aber Sie können damit nicht den kompletten Heap (alle Objekte) diagnostizieren. Falls Sie das Complete-Memory-Dumpfile nicht finden können müssen Sie in der Registry den DumpType-Schlüssel auf  "2=Full" stellen und dann erneut warten bis der Fehler auftritt und WER den Dump erstellt hat.

3. Damit Sie in WinDbg leserliche Callstacks und Objekte angezeigt bekommen, müssen Sie zuerst die Symbolpfade setzen, wo sich die pdb-Files befinden. Geben Sie dafür den "Symfix-Befehl" ein:

.symfix D:\vbIPlus\bin

 4. Damit WinDbg .NET-Anwendungen debuggen kann, müssen die SOS-Extensions geladen werden (https://docs.microsoft.com/de-de/dotnet/framework/tools/sos-dll-sos-debugging-extension). Geben sie dafür den "cordll-Befehl" ein:

.cordll -ve -u -l

 5. Zuletzt lassen Sie sich den Aufrufstapel von allen Threads ausgeben mit dem Befehl "EEStack":

!EEStack

 

 

Die SOS-Extensions bieten eine Vielzahl von Befehlen, um Probleme analysieren zu können. Die wichtigsten davon sind 

  • "!DumpStackObjects"
  • "!DumpHeap"
  • "!DumpObj" und
  • "!DumpMT".

Mehr dazu unter:

https://docs.microsoft.com/de-de/dotnet/framework/tools/sos-dll-sos-debugging-extension

https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/debugging-managed-code


Mit dem Komponentenexplorer können Sie die netzwerkfähigen Eigenschaften von ACComponent-Instanzen (statische oder auch dynamische) lesen und ändern. 

  1. Selektieren Sie in der Visualisierung oder Prozesssteuerung eine Instanz.
  2. Öffnen Sie per Kontextmenü den Komponentenexplorer unter Menüpunkt "Werkzeuge->Komponentenexplorer".
  3. Drücken Sie die Taste "Suchen"
  4. Selektieren Sie in der linken Liste die entprechende Instanz aus von der Sie die Eigenschaften sehen wollen.
  5. In der rechten Liste können Sie in der Spalte Value, die Eigenschaftswerte lesen oder ändern.

Lokale Eigenschaften können Sie mit dem Komponenten-Explorer nicht sehen oder ändern. Dies können Sie entweder per iplus-Entwicklungsumgebung tun oder per Diagnose-Dialog:


Mit dem Diagnose-Dialog können Sie alle Eigenschaftswerte einer ACComponent-Instanz anzeigen lassen.

  1. Selektieren Sie in der Visualisierung oder Prozesssteuerung eine Instanz.
  2. Öffnen Sie per Kontextmenü den Diagnosedialog unter Menüpunkt "Werkzeuge->Öffne xxx in Diagnose-Dialog".
  3. Wenn Sie den Diagnosedialog auf einem Client öffnen liegen die ACComponent-Instanzen als Proxy-Objekte vor. Der Diagnose-Dialog zeigt in diesem Fall den Zustand des Proxy-Objekts als auch des reelen Objekts (Serverseite).

Der Diagnose-Dialog zeigt nur Eigenschaften an, die mit der ACPropertyInfo-Attributklasse veröffentlicht wurden oder Punkte (Referenzen und Listen), die mit den ACPoint-Attributklassen veröffentlicht wurden. Lokale und private Felder oder Konfigurationseigenschaften dagegen nicht. Um diese ebenfalls auszugeben, überschreiben Sie die Methode DumpPropertyList:

 

Fügen Sie mit der AppendChild()-Methode zusätzliche Feldwerte hinzu. In dem Beispiel oben wurde das lokale Feld _SubscribedToWorkCycle hinzugefügt, das im Diagnose-Dialog folgendermaßen angezeigt wird:

 


Mit den zuvor aufgelisteten Debugging-Techniken und der Ausgabe von Objektzuständen zur Laufzeit, kann man zwar Programmfehler herausfinden, jedoch sind sie keine Hilfe bei Performance-Problemen.

Zur Untersuchung von Performanceproblemen verwenden Sie die Komponente gip.core.autocomponent.RuntimeDump, die Sie als Instanz in einem Anwendungsbaum hinzufügen. RuntimeDump darf bei einem gestarteten iPlus-Dienst nur einmal instanziiert werden. Deswegen empfehlen wir die Instanz im Service-Projekt mit dem ACIdentifer "VBDump" hinzuzufügen:

Zeigen Sie VBDump in der Visualisierung an damit Sie folgende Befehle per Kontextmenü ausführen können:

 

Dump CPU usage

Dieses Kommando erstellt eine Datei mit dem Namen "UsageCPU_YYYYMMDD_hhmmss.txt" im temporären Verzeichnis (%USERPROFILE%\AppData\Local\Temp) wo auch das Meldungsprotokoll abgelegt wird. Hier eine Beispieldatei:

Diese Datei gibt eine Statistik über alle Threads aus, die mit der Klasse "gip.core.datamodel.ACThread" erzeugt worden sind. Deswegen sollten Sie bei der Threadprogrammierung ausschliesslich die Klasse ACThread verwenden.

  • Im Abschnitt <<< SUMMARY >>> werden die Threads nach prozentualer Nutzung ausgegeben.
  • Im Abschnitt <<< DETAILS >>> wird pro Thread die "Top 20"-Ereignisse ausgegeben, die am meisten CPU-Zeit beansprucht haben.
  • Darunter werden die Statistiken von allen Delegate-Queues ausgegeben.
  • Im Abschnitt <<< THREAD-STATES >>> wird der Threadzustand ausgegeben.
  • Im Abschnitt <<< MAPPING MANAGED-Id to NATIVE-Id >>> wird das Mapping zwischen der Managed-ThreadID und der "native Thread-ID" ausgegeben. Dies ist nützlich, wenn man mit dem Process-Explorer das Verhalten der Thread-Nutzung beobachtet hat und dann herausfinden will welcher .NET-Thread sich dahinter verbirgt.

 

Dump Performancelog

Dieses Kommando erstellt eine Datei mit dem Namen "PerfLog_YYYYMMDD_hhmmss.txt" im temporären Verzeichnis (%USERPROFILE%\AppData\Local\Temp) wo auch das Meldungsprotokoll abgelegt wird. Hier eine Beispieldatei:

Diese Datei enthält eine Nutzungs-Statistik über alle Instanzen, die Status-Abhängigen Methoden besitzen. Status-Abhängige Methoden werden zyklisch aufgerufen durch die Aktivierung per "PABase.SubscribeToProjectWorkCycle()". Die Ausführungszeit einer Status-Abhängigen Methode wird protokolliert und in diesem Performancelog ausgegeben.

  • Im Abschnitt <<< SUMMARY >>> werden die Status-Abhängigen Methoden nach prozentualer Nutzung ausgegeben.
  • Im Abschnitt <<< DETAILS >>> wird pro Methode die "Top 20"-Ereignisse ausgegeben, die am meisten CPU-Zeit beansprucht haben.

 

Enable/Disable Performance-logging

Damit aktivieren oder deaktivieren Sie das Performance-logging. Um es dauerhaft beim Startvorgang des Dienstes zu aktivieren, tragen Sie den Abschnitt PerfLogConfiguration in der App.Config-Datei hinzu.

 

Dump Delegate-Queues

Dieses Kommando erstellt eine Datei mit dem Namen "DelegateQueue_YYYYMMDD_hhmmss.txt" im temporären Verzeichnis (%USERPROFILE%\AppData\Local\Temp) wo auch das Meldungsprotokoll abgelegt wird. Hier eine Beispieldatei:

Diese Datei enthält eine Statistik über den Status und den Nutzungsgrad aller Delegate-Queues.

 

Restart Delegate-Queue

Dieses Kommando entfernt alle Einträge aus allen Delegate-queues und startet die Abarbeitungsthreads erneut.

 

Dump all subscribed components

Dieses Kommando erstellt eine Datei mit dem Namen "SubscribedComp_YYYYMMDD_hhmmss.txt" im temporären Verzeichnis (%USERPROFILE%\AppData\Local\Temp) wo auch das Meldungsprotokoll abgelegt wird. In dieser Datei sind alle Instanzen aufgelistet, deren Status-Abhängige Methoden zyklisch aufgerufen werden, weil Sie per "PABase.SubscribeToProjectWorkCycle()" aktiviert wurden.

 

Full Dump

Legen Sie im iPlus-Installationsverzeichnis bzw. im Verzeichnis wo der iPlus-Dienst ausgeführt wird eine leere Textdatei mit dem Namen "Invoke_Dump.txt" an.

Der iPlus-Dienst beginnt alle Anwendungsbäume inklusive des iPlus-Anwendungsbaums in das temporäre Verzeichnis auszugeben. Dabei wird eine XML-Datei mit dem Namen "RuntimeDump_ProcId_yyyyMMdd_HHmmss.xml" erstellt. Die XML-Datei enthält alle Instanzen inklusive aller Eigenschaftswerte und privater Felder wie sie auch im Diagnose-Dialog angezeigt wird.

Zusätzlich wird im Meldungsprotokoll der aktuelle Call-Stack aller Threads ausgegeben.

Dieser Dump ist vorteilhaft, falls der komplette iPlus-Dienst hängt und man vom Client aus keine Befehle mehr an den Dienst senden kann. Dieser Zustand tritt nur in den seltensten Fällen auf und zwar dann, wenn eine eigens entwickelte Assembly verwendet wird, die nicht threadsicher programmiert wurde.

Vergessen Sie nicht die "Invoke_Dump.txt"-Datei wieder aus dem Verzeichnis zu löschen, nachdem die XML-Datei erstellt worden ist!

Hier eine Beispieldatei: