it-swarm.com.de

Context wechselt in neuen Linux-Kerneln viel langsamer

Wir möchten das Betriebssystem auf unseren Servern von Ubuntu 10.04 LTS auf Ubuntu 12.04 LTS aktualisieren. Leider scheint sich die Latenz für die Ausführung eines Threads, der lauffähig geworden ist, von 2.6 auf 3.2 Kernel deutlich erhöht zu haben. Tatsächlich sind die Latenzzahlen, die wir bekommen, kaum zu glauben.

Lassen Sie mich genauer auf den Test eingehen. Wir haben ein Programm, das zwei Threads ausführt. Der erste Thread erhält die aktuelle Zeit (in Ticks mit RDTSC) und signalisiert dann einmal pro Sekunde eine Bedingungsvariable. Der zweite Thread wartet auf die Bedingungsvariable und wacht auf, wenn es signalisiert wird. Es wird dann die aktuelle Zeit (in Ticks mit RDTSC) abgerufen. Die Differenz zwischen der Zeit im zweiten Thread und der Zeit im ersten Thread wird berechnet und auf der Konsole angezeigt. Danach wartet der zweite Thread erneut auf die Bedingungsvariable. Es wird nach ca. einem zweiten Durchgang wieder vom ersten Thread signalisiert.

In aller Kürze erhalten wir als Ergebnis einmal pro Sekunde eine Thread-to-Thread-Kommunikation über Bedingungsvariable Latenzmessung.

In Kernel 2.6.32 liegt diese Latenz irgendwo in der Größenordnung von 2,8-3,5 us, was angemessen ist. In Kernel 3.2.0 hat sich diese Latenz auf 40-100 us erhöht. Ich habe keine Unterschiede in der Hardware zwischen den beiden Hosts ausgeschlossen. Sie laufen auf identischer Hardware (Dual-Socket-Prozessoren X5687 {Westmere-EP} mit 3,6 GHz, Hyperthreading, Speedstep und deaktiviertem C-Status). Die Test-App ändert die Affinität der Threads, um sie auf unabhängigen physischen Kernen desselben Sockets auszuführen (dh der erste Thread wird auf Core 0 und der zweite Thread auf Core 1 ausgeführt), sodass kein Thread-Bouncing stattfindet Kerne oder Prellen/Kommunikation zwischen Steckdosen.

Der einzige Unterschied zwischen den beiden Hosts besteht darin, dass auf einem der Hosts Ubuntu 10.04 LTS mit Kernel 2.6.32-28 (die Box für den schnellen Kontextwechsel) und auf dem anderen der neueste Ubuntu 12.04 LTS mit Kernel 3.2.0-23 (der langsame Kontext) ausgeführt wird Schaltkasten). Alle BIOS-Einstellungen und Hardware sind identisch.

Gab es irgendwelche Änderungen im Kernel, die für diese lächerliche Verlangsamung verantwortlich sein könnten?

Update: Wenn Sie den Test auf Ihrem Host- und Linux-Build ausführen möchten, habe ich den Code in Pastebin gepostet für Ihre Einsicht. Kompilieren mit:

g++ -O3 -o test_latency test_latency.cpp -lpthread

Laufen Sie mit (vorausgesetzt, Sie haben mindestens eine Dual-Core-Box):

./test_latency 0 1 # Thread 1 on Core 0 and Thread 2 on Core 1

Update 2 : Nach langem Durchsuchen der Kernelparameter, Beiträgen zu Kerneländerungen und persönlichen Recherchen habe ich herausgefunden, was das Problem ist, und habe die Lösung als gepostet eine Antwort auf diese Frage.

96

Die Lösung für das bad thread wake up performance problem in neueren Kerneln hat mit der Umstellung auf den cpuidle-Treiber intel_idle Von acpi_idle Zu tun, dem Treiber, der in verwendet wird ältere Kernel. Leider ignoriert der intel_idle - Treiber die BIOS-Konfiguration des Benutzers für die C-States und tanzt zu seiner eigenen Melodie. Mit anderen Worten, selbst wenn Sie alle C-Status im BIOS Ihres PCs (oder Servers) vollständig deaktivieren, erzwingt dieser Treiber diese weiterhin während kurzer Inaktivitätsperioden, die fast immer auftreten, es sei denn, es handelt sich um einen rein synthetischen Benchmark (z. B. Stress) ) läuft. Sie können C-Statusübergänge zusammen mit anderen nützlichen Informationen in Bezug auf die Prozessorfrequenzen mit dem wunderbaren Google i7z-Tool auf der meisten kompatiblen Hardware überwachen.

Um zu sehen, welcher CPU-Treiber in Ihrem Setup gerade aktiv ist, rufen Sie einfach die Datei current_driver Im Abschnitt cpuidle von /sys/devices/system/cpu Wie folgt auf:

cat /sys/devices/system/cpu/cpuidle/current_driver

Wenn Sie möchten, dass Ihr modernes Linux-Betriebssystem eine möglichst geringe Latenzzeit für Kontextwechsel aufweist, fügen Sie die folgenden Kernel-Boot-Parameter hinzu, um alle diese Energiesparfunktionen zu deaktivieren:

Unter Ubuntu 12.04 können Sie dies tun, indem Sie sie zum Eintrag GRUB_CMDLINE_LINUX_DEFAULT In /etc/default/grub Hinzufügen und dann update-grub Ausführen. Die hinzuzufügenden Boot-Parameter sind:

intel_idle.max_cstate=0 processor.max_cstate=0 idle=poll

Hier sind die wichtigsten Details zu den drei Startoptionen:

Wenn Sie intel_idle.max_cstate Auf Null setzen, wird Ihr cpuidle-Treiber entweder auf acpi_idle Zurückgesetzt (zumindest gemäß der Dokumentation der Option) oder vollständig deaktiviert. Auf meiner Box ist es vollständig deaktiviert (d. H. Das Anzeigen der Datei current_driver In /sys/devices/system/cpu/cpuidle Erzeugt eine Ausgabe von none). In diesem Fall ist die zweite Startoption processor.max_cstate=0 Nicht erforderlich. In der Dokumentation wird jedoch angegeben, dass das Setzen von max_cstate auf Null für den Treiber intel_idle Das Betriebssystem auf den Treiber acpi_idle Zurücksetzen sollte. Deshalb habe ich für alle Fälle die zweite Boot-Option gewählt.

Die Option processor.max_cstate Setzt den maximalen C-Status für den Treiber acpi_idle Auf Null und deaktiviert ihn hoffentlich ebenfalls. Ich habe kein System, auf dem ich das testen kann, da intel_idle.max_cstate=0 Den CPU-Treiber auf der gesamten mir zur Verfügung stehenden Hardware völlig ausschaltet. Wenn Ihre Installation Sie jedoch mit nur der ersten Startoption von intel_idle Auf acpi_idle Zurücksetzt, teilen Sie mir bitte mit, ob die zweite Option processor.max_cstate Das getan hat, wofür sie dokumentiert wurde in den Kommentaren machen, damit ich diese Antwort aktualisieren kann.

Schließlich ist der letzte der drei Parameter idle=poll Ein echtes Leistungsschwein. Dadurch wird C1/C1E deaktiviert, wodurch die letzte verbleibende Latenzzeit auf Kosten eines viel höheren Stromverbrauchs beseitigt wird. Verwenden Sie diese also nur, wenn dies wirklich erforderlich ist. Für die meisten wird dies ein Overkill sein, da die C1 * -Latenz nicht allzu groß ist. Unter Verwendung meiner Testanwendung, die auf der in der ursprünglichen Frage beschriebenen Hardware ausgeführt wurde, stieg die Latenz von 9 auf 3 us. Dies ist sicherlich eine signifikante Reduzierung für Anwendungen mit hoher Latenz (z. B. Finanzhandel, hochpräzise Telemetrie/Verfolgung, hochfrequente Datenerfassung usw.), ist jedoch möglicherweise für die überwiegende Mehrheit der Anwendungen den anfallenden Stromverbrauch nicht wert Desktop-Apps. Die einzige Möglichkeit, dies sicher zu wissen, besteht darin, die Leistungsverbesserung Ihrer Anwendung im Vergleich zum tatsächlichen Anstieg des Stromverbrauchs/der Wärme Ihrer Hardware zu analysieren und die Kompromisse abzuwägen.

Update:

Nach zusätzlichen Tests mit verschiedenen idle=* - Parametern habe ich festgestellt, dass es eine viel bessere Idee ist, idle auf mwait zu setzen, wenn dies von Ihrer Hardware unterstützt wird. Es scheint, dass die Verwendung der Anweisungen MWAIT/MONITOR Es der CPU ermöglicht, in C1E einzutreten, ohne dass der Thread-Aufwachzeit eine merkliche Latenz hinzugefügt wird. Mit idle=mwait Erhalten Sie kühlere CPU-Temperaturen (im Vergleich zu idle=poll), Weniger Stromverbrauch und behalten dennoch die hervorragenden niedrigen Latenzen einer Polling-Leerlaufschleife bei. Daher lautet mein aktualisierter empfohlener Satz von Boot-Parametern für die Aufwach-Latenz bei niedrigem CPU-Thread basierend auf diesen Ergebnissen:

intel_idle.max_cstate=0 processor.max_cstate=0 idle=mwait

Die Verwendung von idle=mwait Anstelle von idle=poll Kann auch bei der Initiierung von Turbo Boost (indem die CPU unter ihrer TDP [Thermal Design Power] bleibt) und Hyperthreading (für das MWAIT ideal ist) hilfreich sein Mechanismus, um nicht den gesamten physischen Kern zu verbrauchen und gleichzeitig die höheren C-Zustände zu vermeiden). Dies muss im Test jedoch noch bewiesen werden, was ich auch weiterhin tun werde.

Update 2:

Die Option mwait idle wurde von neueren 3.x-Kerneln entfernt (danke an Benutzer ck_ für das Update). Das lässt uns zwei Möglichkeiten:

idle=halt - Sollte genauso gut funktionieren wie mwait, aber testen Sie, ob dies bei Ihrer Hardware der Fall ist. Die Anweisung HLT entspricht fast einer Anweisung MWAIT mit dem Statushinweis 0. Das Problem liegt in der Tatsache, dass ein Interrupt erforderlich ist, um aus einem HLT-Status herauszukommen, während ein Speicher schreibt (oder einen Interrupt ausführt) ) kann verwendet werden, um den MWAIT-Status zu verlassen. Abhängig davon, was der Linux-Kernel in seiner Leerlaufschleife verwendet, kann MWAIT dadurch möglicherweise effizienter werden. Also, wie gesagt Test/Profil und sehen, ob es Ihren Latenzanforderungen entspricht ...

und

idle=poll - Die leistungsstärkste Option auf Kosten von Strom und Wärme.

93

Was vielleicht langsamer wurde, ist Futex, der Baustein für Bedingungsvariablen. Dies wird etwas Licht ins Dunkel bringen:

strace -r ./test_latency 0 1 &> test_latency_strace & sleep 8 && killall test_latency

dann

for i in futex nanosleep rt_sig;do echo $i;grep $i test_latency_strace | sort -rn;done

hier werden die Mikrosekunden angezeigt, die für die interessanten Systemaufrufe benötigt werden, sortiert nach Zeit.

Auf dem Kernel 2.6.32

$ for i in futex nanosleep rt_sig;do echo $i;grep $i test_latency_strace | sort -rn;done
futex
 1.000140 futex(0x601ac4, FUTEX_WAKE_OP_PRIVATE, 1, 1, 0x601ac0, {FUTEX_OP_SET, 0, FUTEX_OP_CMP_GT, 1}) = 1
 1.000129 futex(0x601ac4, FUTEX_WAKE_OP_PRIVATE, 1, 1, 0x601ac0, {FUTEX_OP_SET, 0, FUTEX_OP_CMP_GT, 1}) = 1
 1.000124 futex(0x601ac4, FUTEX_WAKE_OP_PRIVATE, 1, 1, 0x601ac0, {FUTEX_OP_SET, 0, FUTEX_OP_CMP_GT, 1}) = 1
 1.000119 futex(0x601ac4, FUTEX_WAKE_OP_PRIVATE, 1, 1, 0x601ac0, {FUTEX_OP_SET, 0, FUTEX_OP_CMP_GT, 1}) = 1
 1.000106 futex(0x601ac4, FUTEX_WAKE_OP_PRIVATE, 1, 1, 0x601ac0, {FUTEX_OP_SET, 0, FUTEX_OP_CMP_GT, 1}) = 1
 1.000103 futex(0x601ac4, FUTEX_WAKE_OP_PRIVATE, 1, 1, 0x601ac0, {FUTEX_OP_SET, 0, FUTEX_OP_CMP_GT, 1}) = 1
 1.000102 futex(0x601ac4, FUTEX_WAKE_OP_PRIVATE, 1, 1, 0x601ac0, {FUTEX_OP_SET, 0, FUTEX_OP_CMP_GT, 1}) = 1
 0.000125 futex(0x7f98ce4c0b88, FUTEX_WAKE_PRIVATE, 2147483647) = 0
 0.000042 futex(0x601b00, FUTEX_WAKE_PRIVATE, 1) = 1
 0.000038 futex(0x601b00, FUTEX_WAKE_PRIVATE, 1) = 1
 0.000037 futex(0x601b00, FUTEX_WAKE_PRIVATE, 1) = 1
 0.000030 futex(0x601b00, FUTEX_WAKE_PRIVATE, 1) = 1
 0.000029 futex(0x601b00, FUTEX_WAKE_PRIVATE, 1) = 0
 0.000028 futex(0x601b00, FUTEX_WAKE_PRIVATE, 1) = 1
 0.000027 futex(0x601b00, FUTEX_WAKE_PRIVATE, 1) = 1
 0.000018 futex(0x7fff82f0ec3c, FUTEX_WAKE_PRIVATE, 1) = 0
nanosleep
 0.000027 nanosleep({1, 0}, {1, 0}) = 0
 0.000019 nanosleep({1, 0}, {1, 0}) = 0
 0.000019 nanosleep({1, 0}, {1, 0}) = 0
 0.000018 nanosleep({1, 0}, {1, 0}) = 0
 0.000018 nanosleep({1, 0}, {1, 0}) = 0
 0.000018 nanosleep({1, 0}, {1, 0}) = 0
 0.000018 nanosleep({1, 0}, 0x7fff82f0eb40) = ? ERESTART_RESTARTBLOCK (To be restarted)
 0.000017 nanosleep({1, 0}, {1, 0}) = 0
rt_sig
 0.000045 rt_sigaction(SIGCHLD, NULL, {SIG_DFL, [], 0}, 8) = 0
 0.000040 rt_sigaction(SIGCHLD, NULL, {SIG_DFL, [], 0}, 8) = 0
 0.000038 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
 0.000035 rt_sigaction(SIGCHLD, NULL, {SIG_DFL, [], 0}, 8) = 0
 0.000034 rt_sigaction(SIGCHLD, NULL, {SIG_DFL, [], 0}, 8) = 0
 0.000033 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
 0.000032 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
 0.000032 rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
 0.000031 rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
 0.000031 rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
 0.000028 rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
 0.000028 rt_sigaction(SIGRT_1, {0x37f8c052b0, [], SA_RESTORER|SA_RESTART|SA_SIGINFO, 0x37f8c0e4c0}, NULL, 8) = 0
 0.000027 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
 0.000027 rt_sigaction(SIGRTMIN, {0x37f8c05370, [], SA_RESTORER|SA_SIGINFO, 0x37f8c0e4c0}, NULL, 8) = 0
 0.000027 rt_sigaction(SIGCHLD, NULL, {SIG_DFL, [], 0}, 8) = 0
 0.000025 rt_sigaction(SIGCHLD, NULL, {SIG_DFL, [], 0}, 8) = 0
 0.000025 rt_sigaction(SIGCHLD, NULL, {SIG_DFL, [], 0}, 8) = 0
 0.000023 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
 0.000023 rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
 0.000022 rt_sigprocmask(SIG_UNBLOCK, [RTMIN RT_1], NULL, 8) = 0
 0.000022 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
 0.000021 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
 0.000021 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
 0.000021 rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
 0.000021 rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
 0.000021 rt_sigaction(SIGCHLD, NULL, {SIG_DFL, [], 0}, 8) = 0
 0.000019 rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0

Auf dem Kernel 3.1.9

$ for i in futex nanosleep rt_sig;do echo $i;grep $i test_latency_strace | sort -rn;done
futex
 1.000129 futex(0x601764, FUTEX_WAKE_OP_PRIVATE, 1, 1, 0x601760, {FUTEX_OP_SET, 0, FUTEX_OP_CMP_GT, 1}) = 1
 1.000126 futex(0x601764, FUTEX_WAKE_OP_PRIVATE, 1, 1, 0x601760, {FUTEX_OP_SET, 0, FUTEX_OP_CMP_GT, 1}) = 1
 1.000122 futex(0x601764, FUTEX_WAKE_OP_PRIVATE, 1, 1, 0x601760, {FUTEX_OP_SET, 0, FUTEX_OP_CMP_GT, 1}) = 1
 1.000115 futex(0x601764, FUTEX_WAKE_OP_PRIVATE, 1, 1, 0x601760, {FUTEX_OP_SET, 0, FUTEX_OP_CMP_GT, 1}) = 1
 1.000114 futex(0x601764, FUTEX_WAKE_OP_PRIVATE, 1, 1, 0x601760, {FUTEX_OP_SET, 0, FUTEX_OP_CMP_GT, 1}) = 1
 1.000112 futex(0x601764, FUTEX_WAKE_OP_PRIVATE, 1, 1, 0x601760, {FUTEX_OP_SET, 0, FUTEX_OP_CMP_GT, 1}) = 1
 1.000109 futex(0x601764, FUTEX_WAKE_OP_PRIVATE, 1, 1, 0x601760, {FUTEX_OP_SET, 0, FUTEX_OP_CMP_GT, 1}) = 1
 0.000139 futex(0x3f8b8f2fb0, FUTEX_WAKE_PRIVATE, 2147483647) = 0
 0.000043 futex(0x601720, FUTEX_WAKE_PRIVATE, 1) = 1
 0.000041 futex(0x601720, FUTEX_WAKE_PRIVATE, 1) = 1
 0.000037 futex(0x601720, FUTEX_WAKE_PRIVATE, 1) = 1
 0.000036 futex(0x601720, FUTEX_WAKE_PRIVATE, 1) = 1
 0.000034 futex(0x601720, FUTEX_WAKE_PRIVATE, 1) = 1
 0.000034 futex(0x601720, FUTEX_WAKE_PRIVATE, 1) = 1
nanosleep
 0.000025 nanosleep({1, 0}, 0x7fff70091d00) = 0
 0.000022 nanosleep({1, 0}, {0, 3925413}) = ? ERESTART_RESTARTBLOCK (Interrupted by signal)
 0.000021 nanosleep({1, 0}, 0x7fff70091d00) = 0
 0.000017 nanosleep({1, 0}, 0x7fff70091d00) = 0
 0.000017 nanosleep({1, 0}, 0x7fff70091d00) = 0
 0.000017 nanosleep({1, 0}, 0x7fff70091d00) = 0
 0.000017 nanosleep({1, 0}, 0x7fff70091d00) = 0
 0.000017 nanosleep({1, 0}, 0x7fff70091d00) = 0
rt_sig
 0.000045 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
 0.000044 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
 0.000043 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
 0.000040 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
 0.000038 rt_sigaction(SIGCHLD, NULL, {SIG_DFL, [], 0}, 8) = 0
 0.000037 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
 0.000036 rt_sigaction(SIGCHLD, NULL, {SIG_DFL, [], 0}, 8) = 0
 0.000036 rt_sigaction(SIGCHLD, NULL, {SIG_DFL, [], 0}, 8) = 0
 0.000035 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
 0.000035 rt_sigaction(SIGCHLD, NULL, {SIG_DFL, [], 0}, 8) = 0
 0.000035 rt_sigaction(SIGCHLD, NULL, {SIG_DFL, [], 0}, 8) = 0
 0.000035 rt_sigaction(SIGCHLD, NULL, {SIG_DFL, [], 0}, 8) = 0
 0.000034 rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
 0.000031 rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
 0.000027 rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
 0.000027 rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
 0.000027 rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
 0.000027 rt_sigaction(SIGRT_1, {0x3f892067b0, [], SA_RESTORER|SA_RESTART|SA_SIGINFO, 0x3f8920f500}, NULL, 8) = 0
 0.000026 rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
 0.000026 rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
 0.000025 rt_sigaction(SIGCHLD, NULL, {SIG_DFL, [], 0}, 8) = 0
 0.000024 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
 0.000023 rt_sigprocmask(SIG_UNBLOCK, [RTMIN RT_1], NULL, 8) = 0
 0.000023 rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
 0.000022 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
 0.000021 rt_sigaction(SIGCHLD, NULL, {SIG_DFL, [], 0}, 8) = 0
 0.000019 rt_sigaction(SIGRTMIN, {0x3f89206720, [], SA_RESTORER|SA_SIGINFO, 0x3f8920f500}, NULL, 8) = 0

Ich fand diesen 5 Jahre alter Fehlerbericht , der einen vergleichbaren "Ping Pong" -Leistungstest enthält

  1. single-Threaded-Libpthread-Mutex
  2. libpthread bedingungsvariable
  3. einfache alte Unix-Signale

Ich musste hinzufügen

#include <stdint.h>

um zu kompilieren, was ich mit diesem befehl gemacht habe

g++ -O3 -o condvar-perf condvar-perf.cpp -lpthread -lrt

Auf dem Kernel 2.6.32

$ ./condvar-perf 1000000
NPTL
mutex                 elapsed:    29085 us; per iteration:   29 ns / 9.4e-05 context switches.
c.v. ping-pong test   elapsed:  4771993 us; per iteration: 4771 ns / 4.03 context switches.
signal ping-pong test elapsed:  8685423 us; per iteration: 8685 ns / 4.05 context switches.

Auf dem Kernel 3.1.9

$ ./condvar-perf 1000000
NPTL
mutex                 elapsed:    26811 us; per iteration:   26 ns / 8e-06 context switches.
c.v. ping-pong test   elapsed: 10930794 us; per iteration: 10930 ns / 4.01 context switches.
signal ping-pong test elapsed: 10949670 us; per iteration: 10949 ns / 4.01 context switches.

Ich komme zu dem Schluss, dass sich der Kontextwechsel zwischen Kernel 2.6.32 und 3.1.9 zwar verlangsamt hat, jedoch nicht so stark, wie Sie es in Kernel 3.2 beobachten. Mir ist klar, dass dies Ihre Frage noch nicht beantwortet. Ich werde weiter graben.

Bearbeiten: Ich habe festgestellt, dass das Ändern der Echtzeitpriorität des Prozesses (beide Threads) die Leistung von 3.1.9 auf 2.6.32 verbessert. Wenn Sie jedoch die gleiche Priorität für 2.6.32 festlegen, verlangsamt sich die Geschwindigkeit.

Hier sind jetzt meine Ergebnisse:

Auf dem Kernel 2.6.32

$ ./condvar-perf 1000000
NPTL
mutex                 elapsed:    29629 us; per iteration:   29 ns / 0.000418 context switches.
c.v. ping-pong test   elapsed:  6225637 us; per iteration: 6225 ns / 4.1 context switches.
signal ping-pong test elapsed:  5602248 us; per iteration: 5602 ns / 4.09 context switches.
$ chrt -f 1 ./condvar-perf 1000000
NPTL
mutex                 elapsed:    29049 us; per iteration:   29 ns / 0.000407 context switches.
c.v. ping-pong test   elapsed: 16131360 us; per iteration: 16131 ns / 4.29 context switches.
signal ping-pong test elapsed: 11817819 us; per iteration: 11817 ns / 4.16 context switches.
$ 

Auf dem Kernel 3.1.9

$ ./condvar-perf 1000000
NPTL
mutex                 elapsed:    26830 us; per iteration:   26 ns / 5.7e-05 context switches.
c.v. ping-pong test   elapsed: 12812788 us; per iteration: 12812 ns / 4.01 context switches.
signal ping-pong test elapsed: 13126865 us; per iteration: 13126 ns / 4.01 context switches.
$ chrt -f 1 ./condvar-perf 1000000
NPTL
mutex                 elapsed:    27025 us; per iteration:   27 ns / 3.7e-05 context switches.
c.v. ping-pong test   elapsed:  5099885 us; per iteration: 5099 ns / 4 context switches.
signal ping-pong test elapsed:  5508227 us; per iteration: 5508 ns / 4 context switches.
$ 
8
amdn

Möglicherweise sehen Sie auch Prozessoren, die in neueren Prozessen und Linux-Kerneln aufgrund des Treibers pstate, der von c-states getrennt ist, heruntergefahren sind. Um dies zu deaktivieren, müssen Sie zusätzlich den folgenden Kernel-Parameter angeben:

intel_pstate=disable

0
Kyle Brandt