3 Stimmen

Zu viele Aufrufe zu mprotect

Ich arbeite an einer parallelen Anwendung (C, pthread). Ich habe die Systemaufrufe zurückverfolgt, weil ich an einem bestimmten Punkt schlechte parallele Leistungen habe. Meine Traces zeigen, dass mein Programm Folgendes aufruft mprotect() viele viele Male ... genug, um mein Programm erheblich zu verlangsamen.

Ich weise eine Menge Speicher zu (mit malloc() ), aber es gibt nur eine angemessene Anzahl von Aufrufen zu brk() um die Heap-Größe zu erhöhen. Warum also so viele Aufrufe an mprotect() ?!

0 Stimmen

Wie wäre es, Ihr Programm mit strace zu verfolgen, wenn Sie es haben (Linux).

0 Stimmen

Genau das habe ich getan.

3voto

Wuggy Punkte 286

Erstellen und zerstören Sie viele Threads?

Die meisten pthread-Implementierungen fügen bei der Zuweisung des Stacks eines Threads eine "guard page" hinzu. Das ist eine zugriffsgeschützte Speicherseite, die dazu dient, Stack-Überläufe zu erkennen. Ich würde erwarten, dass mindestens ein Aufruf von mprotect jedes Mal erfolgt, wenn ein Thread erzeugt oder beendet wird, um die guard page zu (ent)schützen. Wenn dies der Fall ist, gibt es mehrere offensichtliche Strategien:

  1. Setzen Sie die Größe der Schutzseite auf Null mit pthread_attr_setguardsize() bevor Sie Threads erstellen.
  2. Verwenden Sie einen Thread-Pool (mit so vielen Threads wie es Prozessoren gibt). Sobald ein Thread mit einer Aufgabe fertig ist, geben Sie ihn an den Pool zurück, um eine neue Aufgabe zu erhalten, anstatt ihn zu beenden und einen neuen Thread zu erstellen.

Eine andere Erklärung könnte sein, dass Sie auf einer Plattform arbeiten, auf der der Stack eines Threads vergrößert wird, wenn ein Überlauf festgestellt wird. Ich glaube nicht, dass dies unter Linux mit GCC/Glibc bereits implementiert ist, aber es gab kürzlich einige Vorschläge in diese Richtung. Wenn Sie während der Verarbeitung viel Stack-Speicherplatz verwenden, können Sie die anfängliche/minimale Stack-Größe explizit erhöhen, indem Sie pthread_attr_setstacksize .

Oder es könnte etwas ganz anderes sein!

0 Stimmen

Nein, ich erstelle nur am Anfang eine begrenzte Anzahl von Threads, trotzdem danke.

1 Stimmen

Hmm... verwenden Sie mmap()? Ich erinnere mich vage an ein Problem, das ein Kollege von mir hatte, bei dem mprotect() viele Male - einmal pro Seite - von einer mmap-Region aufgerufen wurde. Ich weiß nicht, ob wir diesem Problem jemals auf den Grund gegangen sind. Wäre es möglich, die Strace-Ausgabe zu posten?

0 Stimmen

@Wuggy es sieht so aus, als ob es 10 Jahre her ist, aber erinnern Sie sich, ob Sie jemals die Grundursache gefunden haben? Ich habe das gleiche Problem bei der Verwendung von mmap()

2voto

Steve McKay Punkte 2063

Wenn Sie können, führen Sie Ihr Programm unter einer Debug-Libc aus und brechen Sie bei mprotect() ab. Schauen Sie sich den Aufrufstapel an und sehen Sie, was Ihr Code tut, der zu den mprotect()-Aufrufen führt.

2voto

Sangman Kim Punkte 135

Die Glibc-Bibliothek, die ptmalloc2 für ihr malloc verwendet, benutzt intern mprotect() für das Mikromanagement des Heaps für andere Threads als den Hauptthread (für den Hauptthread wird stattdessen sbrk() verwendet.) malloc() weist dem Thread zunächst mit mmap() einen großen Teil des Speichers zu, wenn ein Heap-Bereich umkämpft zu sein scheint, und ändert dann die Schutzbits des unnötigen Teils, um ihn mit mprotect() zugänglich zu machen. Später, wenn der Heap vergrößert werden muss, wird der Schutz mit mprotect() wieder auf lesbar/schreibbar geändert. Diese mprotect()-Aufrufe dienen zum Vergrößern und Verkleinern des Heaps in Multithread-Anwendungen.

http://www.blackhat.com/presentations/bh-usa-07/Ferguson/Whitepaper/bh-usa-07-ferguson-WP.pdf erklärt dies etwas ausführlicher.

0voto

David Schwartz Punkte 172718

Die 'valgrind'-Suite hat ein Werkzeug namens 'callgrind', das Ihnen sagt, was was aufruft. Wenn Sie die Anwendung unter 'callgrind' laufen lassen, können Sie die resultierenden Profildaten mit 'kcachegrind' betrachten (es kann Profile analysieren, die von 'cachegrind' oder 'callgrind' erstellt wurden). Dann doppelklicken Sie einfach auf "mprotect" im linken Fensterbereich und es wird Ihnen angezeigt, welcher Code ihn wie oft aufruft.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X