Ich schreibe, um zu sehen, ob jemand von euch jemals eine Umsetzung der Idee, die ich beschreiben werde, gesehen oder gehört hat.
Ich bin daran interessiert, eine Debug-Bibliothek im printf-Stil für ein eingebettetes Ziel zu entwickeln. Das Ziel ist extrem entfernt, und das Kommunikationsbandbudget zwischen mir und dem Ziel ist extrem eng, daher möchte ich in der Lage sein, die Debugging-Nachrichten in einem sehr effizienten Format zu erhalten.
Sehr häufig sehen Debuganweisungen wie folgt aus:
%Vor%Natürlich, wenn dies in Text erweitert wird, ist die gedruckte Zeichenfolge etwas wie "Innere Schleife, Verarbeitungselement 5 von 10. \ n", insgesamt ~ 42 Bytes oder so. Über 90% der von dieser Anweisung ausgedruckten Daten sind statisch, wörtlich - zur Kompilierungszeit bekannt. Natürlich sind nur die "5" und "10" zur Kompilierzeit nicht bekannt.
Ich möchte nur diese zwei ganzen Zahlen zurücksenden (8 statt 42 Bytes). Sobald ich diese Daten erhalten habe, würde ich einen "Decoder-Ring" haben, der es mir ermöglicht, die empfangenen Daten wiederherzustellen und die vollständige Debug-Nachricht hier an meinem Standort auszudrucken.
Ich würde den "Decoder-Ring" automatisch (als Teil des Build-Prozesses) erzeugen, indem ich jeder myDebugLibraryPrintf () -Anweisung zum Zeitpunkt der Kompilierung eine eindeutige ID geben und eine Tabelle generieren würde, die diese eindeutigen IDs den ursprünglichen Format-Strings zuordnet. Wenn dann myDebugLibraryPrintf () für das Ziel aufgerufen wird, überträgt es die eindeutige ID und die% varargs-Werte "%d"
, "%f"
etc., die in der Formatzeichenkette angezeigt werden, aber die Formatzeichenkette selbst wird NICHT übertragen. (Ich werde wahrscheinlich "%s"
Elemente für jetzt einfach nicht zulassen ...) Zurück an meinem Standort, haben wir ein Programm, das die eindeutigen IDs in der Tabelle nachschlägt, die passende Formatzeichenkette findet und sie verwendet, um die ursprüngliche Debug-Nachricht.
Ich habe das Gefühl, dass jemand diese Idee schon einmal gehabt hat und ich dachte mir, dass vielleicht jemand in der Community so etwas gesehen hätte (oder sogar eine Open-Source-Bibliothek, die das tut).
Einschränkungen:
Um klarzustellen, ich habe es hier mit C / C ++ zu tun, und ich bin nicht an einer 100% -vollständigen Ersatzimplementierung von printf () interessiert - Dinge wie nicht-literale Formatzeichenfolgen, %s
(String-) Formatbezeichner oder erweiterte Formatbezeichner wie das Setzen der Breite oder Genauigkeit in der varargs-Liste mit %*.*d
müssen nicht unterstützt werden.
Ich möchte, dass die String-Tabelle automatisch als Teil des Build-Prozesses generiert wird, so dass das Hinzufügen von Debugging nicht mehr Arbeit erfordert als das Hinzufügen eines traditionellen printf (). Wenn mehr als der minimale Aufwand erforderlich ist, wird niemand auf meinem Projekt es verwenden.
Es wird ziemlich viel davon ausgegangen, dass zusätzliche Arbeit als Teil des Build-Prozesses zum Generieren der Stringtabelle erforderlich ist. Glücklicherweise habe ich die Kontrolle über den gesamten Quellcode, mit dem ich diese Bibliothek verwenden möchte, und ich habe eine große Flexibilität innerhalb des Build-Prozesses.
Danke!
Ich habe diese Idee nur mit einer vordefinierten Menge von Strings implementiert. Der Code würde wie debug_print(INSIDE_LOOP_MSG_ID, i, n)
aussehen. Wenn Entwickler neue Nachrichten hinzufügen wollten, mussten sie den neuen Text in eine bestimmte Header-Datei einfügen und ihr eine neue ID geben.
Ich halte es für eine interessante Herausforderung, sie aus einer normal aussehenden Druckanweisung zu erstellen. Ich habe keine vorhandenen Implementierungen gefunden.
Eine Idee könnte ein Makro / eine Vorlage sein, die das erste String-Argument in einen Hash-Wert zur Kompilierzeit umwandelt . Also schreibt der Entwickler debug_print("test %d",i)
, was zu debug_port_send(0x1d3s, i)
kompiliert wird. Das Schreiben eines Post-Processing-Skripts zum Extrahieren der Strings und Hashes für die Verwendung auf der Empfängerseite sollte einfach sein. (Die einfachste Möglichkeit, Hash-Kollisionen aufzulösen, besteht darin, eine Fehlermeldung zu geben und den Benutzer zu zwingen, den Wortlaut geringfügig zu ändern).
bearbeiten:
Also habe ich das mit dem Kompilierzeit-Hash unter dem obigen Link versucht.
Mit etwas mehr Cleverness könntest du mehrere Argumente unterstützen. Die Untersuchung der Disassemblierung zeigt, dass alle Hashes tatsächlich zur Kompilierungszeit berechnet werden. Die Ausgabe ist wie erwartet, keine Kollisionen von identischen Strings. ( Diese Seite bestätigt, dass das Hex für 3.14 korrekt ist):
%Vor% Alles, was Sie jetzt brauchen, ist ein Textverarbeitungsskript, das auf dem Code ausgeführt werden kann, der die Zeichenfolgen aus Debug_Print extrahiert, die Hashwerte berechnet und eine Tabelle auf Ihrer Empfängerseite füllt. Der Empfänger erhält einen Hash-Wert aus dem Aufruf Send
, sucht die dazugehörige Zeichenfolge und übergibt diese zusammen mit den Argumenten an einen normalen printf-Aufruf.
Das einzige Problem, das ich sehe, ist, dass die verschachtelten Makros im Kompilierzeit-Hash mein Refactoring-Plug-In zu verwirren und die Reaktionsfähigkeit meiner IDE zu zerstören . Durch das Deaktivieren des Add-Ins wurde dieses Problem behoben.
Ich habe etwas gesehen, das auf der ARM-Plattform etwas Ähnliches erreicht. Ich glaube, es heißt die " Embedded Trace Macrocell " . Eine Reihe von Makros übersetzt Anweisungen wie TRACE_POWER_SYSTEM_VOLTAGE_REGULATOR_TRIGGER(inputX);
in zwei Registerschreibvorgänge in die ETM-Register. Beachten Sie, dass dies NUR 16 Bit, 32 Bit und 64 Bit Ganzzahlen als Argumente akzeptiert.
Wir können die ARM-Tools verwenden, um diese (zeitgestempelten) Puffer zu extrahieren. Dann wenden wir ein vorkompiliertes Trick-Bit an, um das erste (Index-) Registerschreiben in eine Ausgabedatei zu konvertieren, die wie folgt aussieht:
%Vor%Der Code wurde untersucht, um den Datentyp des Arguments zu bestimmen, also müssen wir uns nicht darum kümmern. Es kann auch mit einem "Echtzeit" -Zeitstempel (anstelle von ms seit dem Einschalten) und Datei- und Zeilennummern der Trace-Anweisungen versehen werden.
ARM ist so eingestellt, dass dieser Ringpuffer intern (und sehr schnell) gespeichert wird, damit er in der Produktion verwendet werden kann. Auch wenn Sie nicht über die Hardwareunterstützung verfügen, können einige Aspekte leicht reproduziert werden.
Beachten Sie, dass es beim Analysieren einer Ablaufverfolgung äußerst wichtig ist, dass Sie nur eine "Decodier" -Datei verwenden, die der bestimmten Version des Codes entspricht, der auf dem Gerät ausgeführt wird.
Ich erinnere mich an viele Tools zum Extrahieren von String-Literalen zum Zwecke der Internationalisierung. GNU-Zeichenfolgen können die Zeichenfolgen direkt aus der ausführbaren Datei extrahieren. Dies sollte mit einem Teil der Aufgabe helfen.
Ich hatte das gleiche Problem PLUS Ich wollte die Bildgröße reduzieren (wegen des winzigen eingebetteten Blitzes). Meine Lösung ist das Senden von Dateiname und Zeile (was 14-20 Byte sein sollte) und das Vorhandensein eines Source-Parsers auf der Serverseite, der eine Karte der tatsächlichen Texte erzeugt. Auf diese Weise enthält der eigentliche Code keine "Format" -Zeichenfolgen, sondern eine einzelne "Dateiname" -Zeichenfolge für jede Datei. Außerdem können Dateinamen leicht durch enum ersetzt werden (im Gegensatz zum Ersetzen jeder Zeichenfolge im Code), um den COMM-Durchsatz zu reduzieren.
Ich hoffe, der Beispiel-Pseudo-Code wird helfen, die Idee zu klären:
%Vor%Tags und Links c debugging printf string-table