en / de
Expertisen
Methoden
Dienstleistungen
Referenzen
Jobs & Karriere
Firma
Technologie-Trends TechCast WebCast TechBlog News Events Academy

Performance-Analyse in einer graphischen C++-Applikation

 

Dass Performance-Analyse unter C++ mit geeignetem Vorgehen und Tools kein Ratespiel sein muss, soll der vorliegende Blog illustrieren.

Kontext

Die Entwicklung der vorliegenden graphischen Applikation begann im Jahr 1999 und ist in MFC C++ implementiert. Über die Zeit wurden auch Teile in GDI+ und in .NET implementiert. Hier eine stark vereinfachte schematische Darstellung der Anwendung.

Schematische Darstellung des User Interface bei 1280 * 1024 Pixels

Schematische Darstellung des User Interface bei 1280 * 1024 Pixels

Die MFC-Methoden OnPaint werden von der dunkelblauen CView sowie vom hellblauen CDialog aus eingeleitet. Mittels sogenanntem double buffering sowie owner drawn controls werden die enthaltenen Teilflächen und Bedienelemente gezeichnet. Würde jeder CDialog autonom zeichnen, würde die Ansicht flackern. Der Grund, dass der hellblaue CDialog ebenso OnPaint verarbeitet ist der, dass hier die häufigsten graphischen Aktualisierungen stattfinden. Das entlastet den Rest der Anwendung. Die Uhr oben rechts löst jede Sekunde einen Zeichenprozess aus, der aber auf den Bereich der Uhr begrenzt bleibt.

Bislang unterstützte die Anwendung eine Bildschirmauflösung von 1280 * 1024 Pixels. Das aktuelle Release bringt diverse Erweiterungen. Dazu gehören die Unterstützung von Breitbildschirmen in der Auflösung von 1600 * 900 Pixels sowie erstmals die Anzeige und Steuerung eines Gerätes via VNC. Dessen Anzeige ist im Bild oben mit einem weissen Schachmuster angedeutet.

Bisher bewegte sich die CPU-Auslastung auf dem Zielsystem mehrheitlich im einstelligen Prozentbereich. Falls das Gerät mit VNC-Anbindung zur Ansicht kommt, stieg diese auf etwa 30 Prozent. Tests zeigten, dass damit eine sichere Bedienung gewährleistet bleibt. Für die VNC-Anbindung wird eine externe .NET-Komponente eingesetzt, welche mittels managed C++-Wrapper integriert wird.

Bei den Tests der neuen Bildschirmauflösung zusammen mit aktiver VNC-Ansicht zeigte sich eine CPU-Last von ca. 60% mit inakzeptablen Verzögerungen bei der Anzeige. Die Frage war natürlich, woher dieser Unterschied stammte. Zum Vergleich die noch etwas stärker vereinfachte Darstellung der Anwendung im 16:9-Format.

Schematische Darstellung des User Interface bei 1600 * 900 Pixels

Schematische Darstellung des User Interface bei 1600 * 900 Pixels

Um die Anpassungen möglichst gering zu halten, musste der hellblaue Teil gleich gross bleiben. Weil in dieser Ansicht in der Vertikalen 124 Pixel weniger zur Verfügung stehen, mussten einige Bereiche anders angeordnet werden.

Performance-Analyse

Es galt nun, ein geeignetes Werkzeug für die Performance-Analyse zu finden. Zuerst versuchten wir es mit very sleepy. Das Tool lieferte uns nicht die gewünschten Informationen. Als nächstes probierten wir es mit dem ebenfalls kostenlos verfügbaren MicroProfiler. Damit ist eine Integration in Visual Studio möglich.

Visual Studio mit MicroProfiler Context Menu Erweiterung

Visual Studio mit MicroProfiler Context Menu Erweiterung

Das Profiling lässt sich für einzelne Projekte ein- und wieder ausschalten. Nimmt man ein Projekt hinzu, wird die Datei micro-profiler.initializer.cpp mit ins Projekt aufgenommen. Die Analyse mit diesem Tool verlangt also einen Rebuild.

Ich entschied mich dazu, die Hauptanwendung inklusive aller abhängigen Projekte (via Project Dependencies…) zu analysieren. Ausserdem das Teilprojekt mit allen Abhängigkeiten, welche die VNC-Komponente einbindet.

Unten die Ansicht des MicroProfilers im 16:9-Anzeigeformat, die automatisch zusammen mit der Anwendung gestartet wird. Im mittleren Fenster sieht man, dass die beiden Hauptverursacher beinahe 12 der 15 Sekunden Analysedauer durch mehrere tausend Mal aufgerufenes Zeichnen für sich beanspruchen. Im oberen Fenster sieht man übrigens den Kontext und im unteren die aufgerufene Funktion.

Performance-Analyse mit C++, MicroProfiler und GDI+

Performance-Analyse mit dem MicroProfiler

Nun konnte mit Hilfe von gezielt eingebauten Logfile-Einträgen untersucht werden, welche Stellen dafür verantwortlich waren, dass so häufig gezeichnet wurde. Wie so oft, lag die Ursache in einer Kleinigkeit. Das folgende Code-Fragment zeigt, wie die VNC-Fläche selber _drawingArea plus des enthaltenden „parent dialogs“ zum Neuzeichnen markiert werden InvalidatePaneRect. _drawingArea->InvalidateRect (clientRect); löst einen Zeichenprozess auf der hellblauen Fläche aus. Dumm nur, dass InvalidatePaneRect () an die dunkelblaue Hauptansicht und damit auch an sämtliche enthaltenen Dialoge der Hauptansicht mitgegeben wird und zwar viermal pro Sekunde! Weil der „parent dialog“ nicht grösser als die VNC-Fläche ist, können die grau markierten Codezeilen getrost entfernt werden.

 

//--- IClientCallback interface -----------------------------------------------
void ClientImpl::invalidate (CRect& clientRect)
{
    if (::IsWindow (m_hWnd))
    {
        if (_drawingArea)
        {
            _drawingArea->InvalidateRect (clientRect);
            ClientToScreen (clientRect);
            InvalidatePaneRect (&clientRect);
        }
    }
}

Damit konnte die CPU-Auslastung mehr als halbiert werden. Blieb nur noch die Frage, warum bei 16:9 die Grundauslastung des Systems so viel höher als bei 5:4 war (ca. 10% gegenüber 1-3%). Auch hier war das Resultat überraschend einfach: Bei 5:4 wurde innerhalb von 10 Sekunden ohne weitere Aktivität genau 10 Mal gezeichnet, logisch wegen der Uhr. Bei 16:9 aber geschlagene 270 Mal! Warum das? Antwort: Weil die Uhr in den weissen Anwendungsbereich geschoben werden musste, wurde mit jeder Sekunde die ganze weisse Fläche mit ihren Teilflächen zum Neuzeichnen fällig! Problem erkannt, Problem schon fast gelöst!

Fazit

Das kostenlos erhältliche Tool MicroProfiler hat die Analyse gezielt unterstützt. Bei sporadisch durchgeführten Performance-Analysen ist das Konfigurieren der Projekte und der anschliessende Rebuild problemlos akzeptiert. Beim Übersetzen von zwei managed C++-Projekten traten allerdings Kompilierfehler auf:

cl : Command line error D8016: '/clr' and '/GH' command-line options are incompatible

Die Aufgabe konnte in diesem Fall aber auch ohne die Analyse dieser managed C++-Projekte gelöst werden.

Kommentare

2 Antworten zu “Performance-Analyse in einer graphischen C++-Applikation”

  1. Arty sagt:

    Thank you for using MicroProfiler! Your review for it in Visual Studio Gallery and stars on github’s page are very welcomed!

  2. Daniel Dörig sagt:

    done

Schreiben Sie einen Kommentar

Ihre E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Newsletter - aktuelle Angebote, exklusive Tipps und spannende Neuigkeiten

 Jetzt anmelden
NACH OBEN
Zur Webcast Übersicht