2010-12-29 17 views
3

Ich bin auf der Suche nach der am wenigsten überschaubaren Möglichkeit, Trace/Logging-Hooks in einen sehr leistungsfähigen Treibercode einzufügen. Diese Logging-Sachen müssen immer kompiliert werden, tun aber meistens nichts (tun aber nichts sehr schnell).Selbstmodifizierender Code für Trace Hooks?

Es gibt nichts viel einfacher als nur ein globales on/off-Wort, eine if(enabled){log()} tun. Wenn es mir möglich ist, möchte ich sogar die Kosten vermeiden, jedes Mal, wenn ich auf einen meiner Hooks klicke, dieses Wort zu laden. Es fällt mir ein, dass ich dafür möglicherweise selbst modifizierenden Code verwenden könnte - dh überall wo ich einen Aufruf an meine Trace-Funktion habe, überschreibe ich den Sprung mit einem NOP, wenn ich die Hooks deaktivieren will, und ersetze den Sprung, wenn ich will um sie zu ermöglichen.

Ein schneller Google stellt keinen Stand der Technik dar - hat es jemand getan? Ist es machbar, gibt es irgendwelche großen Stolpersteine, die ich nicht voraussehe?

(Linux, x86_64)

+1

Achten Sie auf die Möglichkeit des Schreib/Ausführungsmodus Exklusivität. Es kann das Schreiben von selbst modifizierendem Code etwas schwieriger machen ... – dmckee

Antwort

4

Ja, diese Technik wurde innerhalb des Linux-Kernels für genau denselben Zweck implementiert (Tracing Hooks).

Siehe the LWN article on Jump Labels für einen Startpunkt.

Es gibt nicht wirklich große Stolpersteine, aber ein paar kleinere: Multithread-Prozesse (Sie müssen alle anderen Threads stoppen, während Sie den Code aktivieren oder deaktivieren); inkohärenten Befehls-Cache (Sie müssen sicherstellen, dass der I-Cache geleert wird, unter alle Kern).

+0

Danke, genau das habe ich gesucht. – kdt

0

Wenn es eine Möglichkeit gäbe, um irgendwie ein Register global zu deklarieren, können Sie das Register mit dem Wert Ihres Wortes an jedem Eintrittspunkt in Ihren Fahrer von außen und dann prüfen, gerade laden konnten das Register. Natürlich würden Sie dann die Verwendung dieses Registers dem Optimierer verweigern, was einige unangenehme Leistungsfolgen haben könnte.

+0

Sie können keine globale Variable mit dem 'register' Schlüsselwort deklarieren, und selbst wenn Sie könnten, wäre es eine schreckliche, schreckliche Idee, dieses Register für alles andere zu verlieren. –

+0

@Adam Rosenfield - Es gibt tatsächlich Möglichkeiten, register globals mit einigen C-Compiler zu deklarieren. Besonders eingebettete. Und ja, es für alles andere zu verlieren wäre sehr schlecht. Ich habe nur eine stichhaltige Idee abgeworfen und auf ihre Mängel hingewiesen. Ich denke nicht, dass das eine Abwertung verdient, aber was auch immer. Ich lasse meine Antwort hier trotzdem. – Omnifarious

+0

Dies wäre ein vernünftiger Ansatz für eine eingebettete Architektur, aber leider muss ich mindestens x86_64 und idealerweise portabel arbeiten. Ich verstehe nicht, warum du auch runtergerauscht wurdest ... – kdt

4

Spielt es eine Rolle, ob Ihr kompilierter Treiber plötzlich doppelt so groß ist?

Erstellen Sie zwei Codepfade - einen mit Protokollierung, einen ohne. Verwenden Sie einen oder mehrere globale Funktionszeiger, um in die leistungsabhängigen Abschnitte zu springen, und überschreiben Sie sie gegebenenfalls.

0

Ich schreibe nicht so sehr auf die Frage, ob dies möglich ist oder nicht, aber wenn Sie etwas Bedeutendes gewinnen.

Auf der einen Seite möchten Sie nicht "Protokollierung aktiviert" jedes Mal testen, wenn eine Protokollierungsmöglichkeit sich präsentiert und auf der anderen Seite "Protokollierung aktiviert" testen und Code mit Ja oder Nein überschreiben Code. Oder "merkt" sich Ihr Fahrer, dass es nicht das letzte Mal war und da diesmal keine angefordert wird, muss nichts getan werden?

Die notwendige Logik scheint nicht trivial zu sein, verglichen mit dem Testen jedes Mal.

+0

Sie sind Missverständnis. Bei der Verwendung von neu geschriebenen Hooks wird nur dann gearbeitet, wenn die Ablaufverfolgung aktiviert ist (Trace-Code einfügen) oder deaktiviert ist (durch Do-nothing-Code ersetzen). Der springende Punkt ist, dass wenn die Verfolgung deaktiviert ist, die Trace-Punkte zu No-Ops werden. – kdt

+0

Was ich meinte war, dass die Logik und der Code, die notwendig sind, um entweder Trace-Code einzufügen oder durch Do-nothing-Code zu ersetzen, die Zeit, die durch die Ausführung von No-Ops gewonnen wird, aufheben kann. –