Schwerpunkte

Software-Entwicklung

Embedded-Linux-Systeme tracen – Teil 5

01. Juni 2021, 08:30 Uhr   |  Tobias Schlichtmeier

Embedded-Linux-Systeme tracen – Teil 5
© Roman Samborskyi | shutterstock.com

Im vierten Teil der Artikel-Reihe zeigten wir, wie man mit Tracealyzer die Userspace Performance ermittelt. Im fünften Teil der Reihe geht es ebenfalls um Userspace-Anwendungen. Wir zeigen wie sich Compiler-Optionen auf die Leistung auswirken.

Das ist der fünfte Artikel einer Serie von Beiträgen über das Verwenden von Tracealyzer zum Erfassen und Analysieren von Traces von Embedded-Linux-Systemen. Hier finden Sie Teil 1, Teil 2, Teil 3 sowie Teil 4 der Artikelreihe.

Im vierten Artikel der Serie ging es darum, wie sich Userspace-Anwendungen mithilfe von LTTng instrumentieren und die Trace-Daten zu Evaluierungszwecken in Tracealyzer sichten lassen. Nützlich ist das Tool unter anderem dann, wenn sich ein bestimmtes Feature auf verschiedene Weise kodieren lässt und die Leistungsfähigkeit der verschiedenen Implementierungs-Varianten zu vergleichen ist. Im fünften Teil geht es darum, zu zeigen, wie man mit LTTng und Tracealyzer Aufschluss darüber gewinnt, wie sich die verschiedenen Compiler-Optionen auf die Performance auswirken. In der Vergangenheit war das stets eine invasive und zudem relativ schwierige Aufgabe.

Leistungsfähigkeit einer Sinus-Funktion

Unter anderem wird gezeigt, wie die Gleitkomma-Compileroptionen die Leistungsfähigkeit von sehr unspektakulären Berechnungen, etwa der Sinus-Funktion, beeinflussen können. Auf Basis des Versuchs lässt sich wiederum verstehen, wie die Optionen Einfluss auf die Performance von Userspace-Anwendungen nehmen können, in denen komplizierte Berechnungen ausgeführt werden.

Grundlage des besagten Experiments soll der folgende Codeabschnitt sein:

#include <math.h>

#include <lttng/tracef.h>

int main(int argc, char *argv[])

{

    int x;

                float sample_freq = 1000;

                float freq = 100;

                float sample;

                float t;

                for (t = 0; t < 1000; Tracealyzer+)

                {

                                sample = sin((2*M_PI*freq*t)/sample_freq);                     

                                tracef("%f", sample);

                }

    return 0;

}

Hier werden 1.000 Punkte einer 100-Hz-Sinuswelle berechnet, die mit 1 kHz abgetastet wird. Nachfolgend ist das recht unkomplizierte Makefile zu sehen, mit dem der obige Codeabschnitt erzeugt wurde:

.PHONY: all

all: hello

sine_test: sine_test.o

                ${CC} -o sine_test sine_test.o -llttng-ust -ldl -lm

sine_test.o: sine_test.c

                ${CC} -c sine_test.c

Trace-Darstellung
© Percepio

Bild 1. In der Trace-Darstellung in Tracealyzer ist die Unstetigkeit deutlich zu sehen.

Nachdem eine LTTng-Sitzung gestartet wurde, wird die kompilierte Binärdatei auf der Befehlszeilen-Ebene ausgeführt und anschließend die Sitzung gleich wieder beendet (was im vorigen Beitrag gezeigt wurde). Der Trace wird daraufhin an einen PC übertragen und in Tracealyzer geöffnet. Nach dem Konfigurieren der User-Event-Interpretation erscheint im User Event Signal Plot die in Bild 1 gezeigte Darstellung – die Unstetigkeit in der Sinuswelle ist unübersehbar.

Datei printf
© Percepio

Bild 2. Keine Unstetigkeit ist dagegen bei der Ausgabe des Inhalts einer mit printf erzeugten Datei zu sehen.

Hätte man in den Code einen printf-Aufruf eingefügt, der jede Signalprobe in eine Datei überträgt, so hätte man bei der grafischen Ausgabe des Dateiinhalts das in Bild 2 gezeigte Ergebnis erhalten. Interessanterweise enthält die auf dem Bildschirm dargestellte Sinuswelle keinerlei Unstetigkeit. Das liegt ganz einfach daran, dass beim Schreiben von Werten in eine Datei das Konzept »Zeit« keinerlei Rolle spielt, sondern die berechneten Werte einfach der Reihe nach ausgegeben werden. Wenn die berechneten Werte dagegen an eine Trace-Datei ausgegeben werden, wird zu jedem Trace-Wert die Systemzeit hinzugefügt.

Trace
© Percepio

Bild 3. Auch nach dem Einfügen der Compiler-Option ist im Trace eine Unstetigkeit sichtbar.

Als nächstes ist das Makefile mit einer Compiler-Option zu versehen, um das daraufhin entstehende Ergebnis zu untersuchen (Details über die gezeigten Compiler-Optionen folgen gegen Ende des Artikels).

.PHONY: all

all: hello

sine_test: sine_test.o

                ${CC} -o sine_test sine_test.o -llttng-ust -ldl -lm

sine_test.o: sine_test.c -mfloat-abi=hard

Im User Event Signal Plot von Tracealyzer ist jetzt das in Bild 3 gezeigte Ergebnis zu sehen. Da nach wie vor eine Unstetigkeit zu beobachten ist, ist eine weitere Compiler-Option hinzuzufügen:

.PHONY: all

all: hello

sine_test: sine_test.o

                ${CC} -o sine_test sine_test.o -llttng-ust -ldl -lm

sine_test.o: sine_test.c -mfloat-abi=hard -mfpu=neon

Trace
© Percepio

Bild 4. Wie unschwer zu erkennen ist, hat sich die Unstetigkeit mit der weiteren Compiler-Option entscheidend verringert.

Nach dem Erfassen eines weiteren Trace ist er wieder in Tracealyzer zu öffnen – tatsächlich liefert der User Event Signal Plot ein anderes Resultat (Bild 4). Auch in dieser Sinuswelle ist noch eine Unstetigkeit zu sehen, jedoch ist der Zeitsprung deutlich geringer (der Abstand zwischen zwei Punkten in der Grafik ist ein Echtzeitwert).

Seite 1 von 2

1. Embedded-Linux-Systeme tracen – Teil 5
2. Fortsetzung: Embedded-Linux-Systeme tracen – Teil 5

Auf Facebook teilen Auf Twitter teilen Auf Linkedin teilen Via Mail teilen

Das könnte Sie auch interessieren

Verwandte Artikel

Percepio AB