Wie langsam ist das x86-Einzelschritt-Debugging?

861
Brent Baccala

Die x86-Architektur bietet eine Hardware- Einzelschrittfalle zum Debuggen. Wie sehr verlangsamt es das laufende Programm?

Wenn beispielsweise eine Linux-Kernel-Funktion erstellt wurde, die nur einen einzigen Prozessschritt ausführt, wie viel langsamer würde dieser Prozess sein? Hat jemand eine gute Schätzung?

Ich frage mich, nachdem ich eine Woche damit verbracht hatte, einen Thread-Fehler aufzuspüren. Es wäre schön, wenn diese Fehler reproduziert werden könnten. Wie wäre es mit einem Feature, das zwei Threads sequenziell ausgeführt hat, und zwar abwechselnd zwischen der Ausführung einer Anweisung in einem Thread und dann einer Anweisung in der anderen in vorhersagbarer Weise. Ich denke an einen Pseudo-Zufallszahlengenerator, der eine Bitfolge erzeugen würde - 0 bedeutet, dass eine Anweisung in Thread 1 ausgeführt wird, 1 bedeutet, dass eine Anweisung in Thread 2 ausgeführt wird.

Dann könnten Sie den PRNG säen und eine reproduzierbare Verschachtelung der Anweisungen erhalten. Verschiedene PRNG-Samen würden unterschiedliche Verschachtelungsmuster erzeugen. Sie könnten einen Testfall unter einer Reihe von PRNG-Samen ausführen, und wenn Sie einen gefunden haben, der einen Fehler ausgelöst hat, reproduzieren Sie ihn.

Jemand hat von so etwas gehört?

Aktualisieren:

Wie könnte es gemacht werden?

Angenommen, wir arbeiten mit einem Core i5, bei dem Sie über 4 Prozessorzustände und 2 Kerne verfügen. Wir verwenden die Einzelschrittfalle, um einen Prozess vom Benutzerraum zum Kernelbereich hin und her zu springen. Das sind also zwei Staaten, richtig? Dann haben wir den anderen Thread auf dem anderen Kern mit seinen Benutzerbereichs- und Kernel-Speicherzuständen ausgeführt, richtig? Es gibt so etwas wie einen Spinlock (wahrscheinlich zwei Spinlocks), der die beiden Kernel-Threads synchronisiert. Jeder spinnt, während der andere seinem Benutzer ein paar Anweisungen gibt, dann synchronisieren sie sich und tauschen Rollen aus.

Klingt, als hätten wir genau die richtige Anzahl von Threads und Kernen, so dass alles auf einmal auf den Chip passt. Aber wie schnell läuft es?

Wir könnten es einfach versuchen. Jemand könnte Kernel-Code schreiben. Oder vielleicht weiß es jemand.

All diese schicken Sachen machen diese neuen Chips aus. Ich wäre beeindruckt und nicht völlig überrascht, wenn es schnell lief.

3
Die Hardware-Einzelschrittfalle ist eine Funktion der [x86-Architektur] (https://en.wikipedia.org/wiki/X86) und ist nicht spezifisch für Intel-Prozessoren. bwDraco vor 9 Jahren 0

2 Antworten auf die Frage

1
Jamie Hanrahan

Die Einzelschrittfalle löst eine Ausnahme aus, nachdem jeder Befehl abgeschlossen ist. Die übliche Verwendung für diese Falle ist, dass Ihr Debugger diese Ausnahme feststellt und Ihnen ermöglicht, sich die Dinge anzusehen, bevor Sie durch die nächste Anweisung gehen.

Wenn Sie darüber nachdenken, ein Tracing durchzuführen, ein detailliertes Protokoll darüber erstellen, was Ihr Code tut, wird Ihr Tracer / Debugger als Ausnahmebehandler aufgerufen, protokolliert, was immer Sie protokollieren möchten, und verwirft dann die Ausnahme - Wiederholung . Ich gehe davon aus, dass sich dadurch die Ausführungsrate des Codes, den Sie verfolgen, um einen Faktor von ein bis mehrere hundert verlangsamen wird.

In Bezug auf Ihre Ideen zum Verschachteln von Anweisungen aus mehreren Threads ist dies nicht der Weg, um Ihr Serialisierungsproblem zu lösen. Sie müssen es im Design nachweislich lösen.

Vielen Dank für Ihre Perspektive auf nachweisbares Design! Ich bin kein guter Programmierer. Ich habe gerade 15.000 Zeilen aus einem Mischmasch aus C, C ++, C ++ 11, Intel-Thread-Primitiven zusammen mit dem C ++ 11-Zeugs, Inline-Assembly und allen Arten von GNU-Abhängigkeiten zusammengeschlagen und nenne es [hoffman] (http: //freesoft.org/hoffman). Ich hätte wirklich gerne ein Debugging-Tool wie das, was ich beschreibe! Brent Baccala vor 9 Jahren 0
Ernsthafter, wie ich im Update zu meinem ursprünglichen Beitrag erklärt habe, glaube ich nicht, dass der Trace / Debugger überhaupt involviert sein muss. Ein spezielles Kernel-Modul ist erforderlich. Brent Baccala vor 9 Jahren 0
Ein Debugging-Tool, wie Sie es beschreiben, ist überhaupt keine schlechte Idee. Ich sage nur, es ist keine gute Möglichkeit, nicht vorhandene Serialisierungsfehler zu finden, zu beheben oder zu beweisen. Jamie Hanrahan vor 9 Jahren 0
... wenn es mit normaler Geschwindigkeit lief. Die Verlangsamung kann Serialisierungsprobleme durchaus verdecken. (Oder es könnte sie herausbringen ...) Jamie Hanrahan vor 9 Jahren 1
0
Roland Pihlakas

Ihr Ansatz scheint nützlich zu sein, und ich habe über ein ähnliches Problem nachgedacht.
Wie kann das gemacht werden? (Es gibt auch einige alternative Möglichkeiten, einschließlich statischer Analyse oder Reflexion und Coroutinen) .
Ihre Methode kann jedoch auf zwei verschiedene Arten stark optimiert werden, wenn Sie willkürlich mehrere Anweisungen übergehen (vielleicht sogar über viele Anweisungen, was auch natürlich erscheint):

1) Bestimmen Sie die zufällige Länge der nächsten Befehlssequenz, bevor Sie die Sequenz starten. Verwenden Sie den Disassembler und setzen Sie am Ende der Sequenz int 3 anstelle von Einzelschritten.

2) Falls Sie int 3 aus irgendeinem Grund nicht verwenden möchten oder Ihrem Disassembler nicht vollständig vertrauen möchten, können Sie Single Steping verwenden und dann die ausgeführten Anweisungen in einen neuen Speicherbereich kopieren.
Wenn der Zufallsgenerator das nächste Mal beschließt, die gleiche Anzahl von sequentiellen Schritten von demselben Programmplatz aus auszuführen, springen Sie einfach zu dem neuen Speicherbereich, der die kopierten Anweisungen enthält, und laufen dort bis zum Ende dieser Sequenz ohne Einzelschritt. Am Ende der Befehlssequenz müssen Sie dann Ihr Debugging-Framework aufrufen.

Für beide Ansätze müssen Sie eine spezielle Behandlung für Anrufe, Sprünge und bedingte Sprünge hinzufügen.