Der vom Toolanbieter pls favorisierte Ansatz eliminiert deshalb die Instrumentierung und damit auch deren kritische Auswirkungen auf das Laufzeitverhalten und den Speicherbedarf. Statt die notwendigen Informationen mit Hilfe der Software zu erfassen, kommen On-Chip-Emulatoren zum Einsatz, die nicht-invasiv sind. Das System lässt sich dadurch gezielt beobachten, ohne es jedoch zu beeinflussen. Mittlerweile sind solche On-Chip-Emulatoren von verschiedenen Herstellern verfügbar, zum Beispiel die »Embedded Macrocell« (ETM) von ARM oder die »Multi-Core Debug Solution« (MCDS) von Infineon.
Letztere wird uns für die nachfolgenden Ausführungen als Referenzplattform dienen. Mit MCDS (Bild 3) lassen sich unter anderem die abgearbeiteten Befehle (Program Trace) zyklengenau aufzeichnen, und es unterstützt mit einer ausgefeilten On-Chip-Trigger- und -Filter-Logik eine gezielte Analyse der Applikation beziehungsweise des gesamten Hard- und Softwaresystems. Die Möglichkeit, bereits während der Aufzeichnung durch die MCDS-Hardware Daten zu filtern, ist enorm wichtig. Zum einen brächten die durch ein ungefiltertes Aufzeichnen zwangsläufig entstehenden großen Datenmengen den verwendeten On-Chip-Trace-Speicher sehr schnell zum Überlaufen. Zum anderen steht über die Debug-Schnittstelle – beispielsweise JTAG – nur eine begrenzte Bandbreite zur Übertragung von Trace-Daten zum Host zur Verfügung, der Anwender hat also keine Möglichkeit, kontinuierlich zu tracen. Neben dem Tracing bietet die MCDS-Hardware noch eine weitere, für die Beobachtung des Laufzeitverhaltens sehr nützliche Funktion: das Zählen von Ereignissen, ohne dass Zählerwerte in den Anwendungsspeicher geschrieben werden müssen. In unserem Fall sind sie Bestandteil der Trace-Ausgabe und lassen sich somit auch mit anderen aufgezeichneten Ereignissen und Trace-Daten korrelieren.
Unterstützung durch die Hardware
Statt den Code zu instrumentieren und Zähler im Target-Speicher anzulegen, ermittelt bei der Hardware-unterstützten Coverage-Analyse die MCDS die Informationen zu den beschrittenen Kanten. Dafür ist allerdings eine modifizierte Version des GNU-Compilers erforderlich, die zwar die CFG-Informationen für die »gcov«-Analyse bereitstellt, aber keine Instrumentierung im bekannten Sinne durchführt. Mit der MCDS lässt sich nicht-invasives Profiling nun auf zweierlei Arten realisieren: Durch Program-Trace mit anschließender Coverage-Analyse oder durch Verwendung der MCDS-Hardwarezähler. Program-Trace mit Coverage-Analyse:
Beim Program-Trace-Ansatz werden alle ausgeführten Instruktionen aufgezeichnet. Liegt ein hinreichend langer Trace vor, rekonstruiert das Tool über eine Post-Trace-Analyse den tatsächlichen Kontrollfluss. Dafür bestimmt es zuerst alle vom Programm beschrittenen Kanten im CFG und ermittelt anschließend, wie oft sie beschritten wurden. Diese Häufigkeiten stellt das Tool dann »gcov« zur Verfügung, um den zweiten, optimierenden Compilerlauf basierend auf den ermittelten Laufzeitinformationen vorzubereiten. Bleibt die Frage zu klären, wie mit der Beschränkung des On-Chip-Trace-Speichers umzugehen ist, denn dessen Kapazität lässt typischerweise nur einen wenige Millisekunden umfassenden Program-Trace zu. Zugute kommt einem hierbei der zyklische Charakter der betrachteten Applikationen, der die Verwendung einer Fenstertechnik erlaubt. Dabei wird eine ganze Reihe von zeitlich versetzt gestarteten Einzelaufzeichnungen zu einem vollständigen Trace zusammengesetzt.
Aus diesem lässt sich zwar nicht ein kontinuierlicher Program-Trace rekonstruieren, aber immerhin eine repräsentative Aussage über die Häufigkeiten der begangenen Programmpfade ableiten. Das Auslesen des Trace-Speichers und die Rekonfiguration der Trigger- und Filter-Logik können übrigens zur Laufzeit erfolgen, ohne das Zeitverhalten des Systems zu beeinträchtigen. MCDS-Hardwarezähler: Bei der zweiten Methode, der Verwendung der MCDS-Hardwarezähler, beobachtet die MCDS die Kanten im CFG des Programms im Gegensatz zur Program-Trace-Methode direkt und verknüpft sie mit den Hardwarezählern. Hier spielt der begrenzte Trace-Speicher keine Rolle, da die Zählerwerte im Speicher kaum ins Gewicht fallen. Zur Identifizierung der Kanten durch MCDS ist jedoch eine »Lightweight«-Instrumentierung notwendig (Bild 4). Sie lässt sich mittels eingefügter »NOP«-Instruktionen realisieren.
Diese Instrumentierung ändert das Laufzeitverhalten nur um jeweils einen Takt und wirkt sich marginal auf die Codegröße aus. Für die Coverage-Analyse wird die MCDS so konfiguriert, dass Adresskomparatoren die Kantenerkennung vornehmen und das Inkrementieren der Ereigniszähler steuern. Dafür werden die Komparatoren einfach auf die Adressen der eingefügten NOPs programmiert. Nach dem Auslesen der Zählerwerte aus dem Trace-Speicher lässt sich direkt die Ausführungshäufigkeit der Kanten ermitteln. Nachteilig bei dieser Methode ist, dass sich aufgrund der beschränkten Anzahl von Zählern und Adresskomparatoren nur wenige Kontrollflusskanten pro Ausführungszyklus gleichzeitig vermessen lassen. Das stellt in der Praxis aber kein Problem dar, da auch hier wiederum eine Art Fenstertechnik zur Anwendung kommen kann. In einem Durchlauf wird nur eine bestimmte Anzahl von Kanten vermessen. Nach einer festgelegten Zeit verschiebt sich das Fenster auf die nächste Gruppe von Kanten, und die Messung startet erneut. Die Zeitdauer einer Messung muss allerdings gegenüber der Periodendauer des Applikationszyklus' – typischerweise im Bereich von einigen hundert Millisekunden – hinreichend groß sein, um eine akzeptable statistische Sicherheit zu erreichen.
Die Tools im Workflow
Der industrielle Einsatz des beschriebenen Verfahrens ist nur sinnvoll, wenn sowohl das Applikations-Profiling als auch die Code-Optimierung als Gesamt-Workflow verfügbar sind. Bild 5 zeigt schematisch die zugehörigen Teilkomponenten und ihre Interaktionen. Hervorzuheben ist dabei, dass für den praktischen Einsatz die Coverage-Analyse nicht auf die gesamte Applikation zur Anwendung kommt, sondern in einem ersten Schritt zunächst die tatsächlich laufzeitkritischen Funktionen ermittelt werden. Das kann ebenfalls mit Hilfe der MCDS geschehen. Sind kritische Funktionen identifiziert oder auch vom Benutzer manuell angegeben, starten die weiteren Optimierungsschritte wie Coverage-Analyse und erneute Compilierung. Sollten Optimierungsziele nicht erreicht oder Randbedingungen wie eine beschränkte Codegröße nicht erfüllt werden, kann es notwendig sein, Teile des Workflows mehrfach zu durchlaufen, um beispielsweise die Optimierungseinstellungen des Compilers oder gar die Auswahl der zu optimierenden Funktionen zu ändern.(cg)
JENS BRAUNES ist Softwarearchitekt bei pls Development Tools und dort verantwortlich für die Entwicklung von Konzepten zur Anwendung von On-Chip-Emulatoren
pls Development Tools
Telefon 03 57 22/38 40
www.pls-mc.com