perf_event_open Überlaufsignal

8

Ich möchte die (mehr oder weniger) genaue Menge an Anweisungen für ein Stück Code zählen. Außerdem möchte ich ein Signal erhalten, nachdem eine bestimmte Anzahl von Anweisungen übergeben wurde.

Zu diesem Zweck verwende ich das von perf_event_open .

Ich verwende die zweite Art, wie die Manpage vorschlägt, Überlaufsignale zu erhalten:

  

Signalüberlauf

     

Ereignisse können so eingestellt werden, dass bei einem Schwellenwert ein Signal ausgegeben wird   ist gekreuzt. Der Signal-Handler wird über die Abfrage (2), Auswahl (2),   epoll (2) und fcntl (2), Systemaufrufe.

     

[...]

     

Die andere Möglichkeit besteht in der Verwendung von PERF_EVENT_IOC_REFRESH ioctl. Dies   ioctl fügt einen Zähler hinzu, der jedes Mal dekrementiert, wenn das Ereignis überläuft.   Bei einem Wert ungleich Null wird beim Überlauf ein POLL_IN-Signal gesendet, nach dem Wert jedoch   0 erreicht, wird ein Signal vom Typ POLL_HUP und dem zugrunde liegenden Ereignis gesendet   ist deaktiviert.

Weitere Erklärung von PERF_EVENT_IOC_REFRESH ioctl:

  

PERF_EVENT_IOC_REFRESH

     

Nicht vererbte Überlaufzähler können dies verwenden, um a zu aktivieren   Zähler für eine Anzahl von Überläufen, die durch das Argument angegeben werden,   Danach ist es deaktiviert. Nachfolgende Aufrufe dieses ioctl   Fügen Sie den Argumentwert zur aktuellen Anzahl hinzu. Ein Signal mit   POLL_IN set wird bei jedem Überlauf bis zur Zählung passieren   erreicht 0; Wenn das passiert ist ein Signal mit POLL_HUP gesetzt   gesendet und das Ereignis ist deaktiviert. Mit einem Argument von 0 ist   als undefiniertes Verhalten betrachtet.

Ein sehr minimales Beispiel würde so aussehen:

%Vor%

Im Grunde mache ich folgendes:

  1. Richten Sie einen Signalhandler für SIGIO-Signale ein
  2. Erstellen Sie einen neuen Leistungsindikator mit perf_event_open (gibt einen Dateideskriptor zurück)
  3. Verwenden Sie fcntl , um dem Dateideskriptor Signalübertragungsverhalten hinzuzufügen.
  4. Führen Sie eine Payload-Schleife aus, um viele Anweisungen auszuführen.

Beim Ausführen der Payload-Schleife werden zu einem bestimmten Zeitpunkt 1000 Anweisungen ( sample_interval ) ausgeführt. Entsprechend der manage perf_event_open löst dies einen Überlauf aus, der dann einen internen Zähler dekrementiert. Sobald dieser Zähler Null erreicht, wird ein Signal vom Typ POLL_HUP gesendet und das zugrunde liegende Ereignis wird deaktiviert.

Wenn ein Signal gesendet wird, wird der Steuerfluss des aktuellen Prozesses / Threads gestoppt und der Signal-Handler wird ausgeführt. Szenario:

  1. 1000 Anweisungen wurden ausgeführt.
  2. Das Ereignis ist automatisch deaktiviert und ein Signal wird gesendet.
  3. Das Signal wird sofort geliefert , der Steuerungsfluss des Prozesses wird gestoppt und der Signalhandler wird ausgeführt.

Dieses Szenario würde zwei Dinge bedeuten:

  • Die endgültige Anzahl der gezählten Befehle wäre immer gleich für ein Beispiel, das überhaupt keine Signale verwendet.
  • Der Befehlszeiger, der für den Signal-Handler gespeichert wurde (und auf den über ucontext zugegriffen werden kann) würde direkt auf den Befehl verweisen, der den Überlauf verursacht hat.

Grundsätzlich könnte man sagen, das Signalverhalten kann als synchron gesehen werden.

Das ist die perfekte Semantik für das, was ich erreichen möchte.

Was mich betrifft, ist das von mir konfigurierte Signal jedoch im Allgemeinen ziemlich asynchron und einige Zeit kann vergehen, bis es schließlich geliefert wird und der Signal-Handler ausgeführt wird. Dies kann für mich ein Problem darstellen.

Betrachten Sie zum Beispiel das folgende Szenario:

  1. 1000 Anweisungen wurden ausgeführt.
  2. Das Ereignis ist automatisch deaktiviert und ein Signal wird gesendet.
  3. Einige weitere Anweisungen bestehen
  4. Das Signal wird ausgegeben, der Steuerungsfluss des Prozesses wird gestoppt und der Signalhandler wird ausgeführt.

Dieses Szenario würde zwei Dinge bedeuten:

  • Die endgültige Anzahl der gezählten Anweisungen wäre weniger als ein Beispiel, das überhaupt keine Signale verwendet.
  • Der Befehlszeiger, der für den Signal-Handler gespeichert wurde, würde auf die Anweisungen zeigen, die den Überlauf oder irgendeinen nach ihm verursacht haben.

Bisher habe ich oben ein Beispiel getestet und habe verpasste Anweisungen, die das erste Szenario unterstützen würden.

Allerdings würde ich gerne wissen, ob ich mich auf diese Annahme verlassen kann oder nicht. Was passiert im Kernel?

    
Dawodo 29.06.2014, 08:29
quelle

1 Antwort

3
  

Ich möchte die (mehr oder weniger) genaue Menge an Anweisungen für ein Stück Code zählen. Außerdem möchte ich ein Signal erhalten, nachdem eine bestimmte Anzahl von Anweisungen übergeben wurde.

Sie haben zwei Aufgaben, die miteinander in Konflikt stehen können. Wenn Sie eine Zählung erhalten möchten (genaue Mengen eines Hardware-Ereignisses), verwenden Sie einfach die Leistungsüberwachungseinheit Ihrer CPU im Zählmodus (setzen Sie nicht sample_period / sample_freq von perf_event_attr Struktur verwendet) und platzieren Sie den Messcode in Ihrem Zielprogramm (wie in Ihrem Beispiel). In diesem Modus werden gemäß der man-Seite von perf_event_open keine Überläufe generiert ( Die PMU der CPU sind normalerweise 64 Bit breit und überlaufen nicht, wenn sie nicht auf einen kleinen negativen Wert eingestellt sind, wenn der Abtastmodus verwendet wird:

  

Überläufe werden nur durch Stichprobenereignisse generiert (sample_period muss einen Wert ungleich Null haben).

Um einen Teil des Programms zu zählen, geben Sie ioctl s von perf_event_open fd ein, wie in man beschrieben Seite

  

perf_event ioctl Aufrufe - Verschiedene ioctls wirken auf perf_event_open () Dateideskriptoren: PERF_EVENT_IOC_ENABLE ... PERF_EVENT_IOC_DISABLE ... PERF_EVENT_IOC_RESET

Sie können den aktuellen Wert mit rdpmc (auf x86) oder mit read syscall auf dem fd lesen, wie im kurzen Beispiel von die man-Seite :

%Vor%
  

Zusätzlich möchte ich ein Signal erhalten, nachdem eine bestimmte Anzahl von Anweisungen übergeben wurde.

Wollen Sie wirklich Signal bekommen oder brauchen Sie nur Anweisungszeiger bei 1000 ausgeführten Befehlen? Wenn Sie Zeiger sammeln möchten, verwenden Sie perf_even_open mit dem Sampling-Modus, aber tun Sie es mit einem anderen Programm , um die Messung des Ereignissammlungscodes zu deaktivieren. Außerdem wird es weniger negative Auswirkungen auf Ihr Zielprogramm haben, wenn Sie nicht für jeden Überlauf Signale verwenden (mit einer großen Menge an Kernel-Tracer-Interaktionen und Wechsel vom / zum Kernel), sondern stattdessen Funktionen von perf_events verwenden, um mehrere Überlaufereignisse zu sammeln in einzelnen mmap-Puffer und Abfrage auf diesem Puffer. Bei Überlauf-Interrupt von PMU wird der Interrupt-Interrupt-Handler aufgerufen, um den Instruktionszeiger in den Puffer zu speichern, und dann wird das Zählen zurückgesetzt und das Programm kehrt zur Ausführung zurück. In Ihrem Beispiel wird der Interrupt-Interrupt-Handler Ihr Programm wecken, mehrere Syscalls ausführen, zum Kernel zurückkehren und dann wird der Kernel den Zielcode neu starten (also ist der Overhead pro Sample größer als bei Verwendung von mmap und Parsing). Mit precise_ip flag können Sie erweiterte Sampling Ihrer PMU aktivieren (wenn es einen solchen Modus hat, wie PEBS und PREC_DIST in Intel x86 / em64t für einige Zähler wie INST_RETIRED, UOPS_RETIRED, BR_INST_RETIRED, BR_MISP_RETIRED, MEM_UOPS_RETIRED, MEM_LOAD_UOPS_RETIRED, MEM_LOAD_UOPS_LLC_HIT_RETIRED und mit einfachem Hack bis cycles too; oder wie IBS von AMD x86 / amd64; Papier über PEBS und IBS ) , wenn die Befehlsadresse direkt von der Hardware mit niedrigem Schlupf gespeichert wird. Einige sehr fortschrittliche PMUs können Sampling in Hardware durchführen und Überlaufinformationen mehrerer Ereignisse in Reihe mit automatischem Reset des Zählers ohne Softwareunterbrechungen speichern (einige Beschreibungen auf precise_ip sind in derselben Zeitung ).

Ich weiß nicht, ob es im perf_events-Subsystem und in Ihrer CPU möglich ist, zwei per_event-Tasks gleichzeitig aktiv zu haben: Beide zählen Ereignisse im Zielprozess und gleichzeitig haben sie Samplings von anderen Prozessen. Mit Advanced PMU kann dies in der Hardware möglich sein und perf_events im modernen Kernel erlauben es. Aber Sie geben keine Details zu Ihrer Kernel-Version und Ihrem CPU-Hersteller und Ihrer CPU an, daher können wir diesen Teil nicht beantworten.

Sie können auch versuchen, andere APIs auf PMU wie PAPI oder likwid ( Ссылка ) zuzugreifen. Einige von ihnen lesen möglicherweise direkt PMU-Register (manchmal MSR) und können die Abtastung zur gleichen Zeit ermöglichen, wenn das Zählen aktiviert ist.

    
osgx 05.03.2017 04:48
quelle

Tags und Links