Kontekst przełącza się znacznie wolniej w nowych jądrach Linuksa

Chcemy zaktualizować system operacyjny na naszych serwerach z Ubuntu 10.04 LTS do Ubuntu 12.04 LTS. Niestety, wydaje się, że opóźnienie uruchomienia wątku, który stał się uruchamialny, znacznie wzrosło z jądra 2.6 do jądra 3.2. W rzeczywistości liczby opóźnień, które otrzymujemy, są trudne do uwierzenia.

Powiem dokładniej o teście. Mamy program, który uruchamia dwa wątki. Pierwszy wątek Pobiera bieżący czas (w kleszczach za pomocą RDTSC), a następnie sygnalizuje warunek zmienna raz na sekundę. Drugi wątek czeka na zmienną condition i budzi się, gdy jest sygnalizowany. Następnie Pobiera bieżący czas (w kleszczach przy pomocy RDTSC). Różnica między czasem w drugim wątku a czasem w pierwszym wątku jest obliczana i wyświetlana na konsoli. Następnie drugi wątek czeka jeszcze raz na zmiennej warunkowej. Zostanie zasygnalizowany ponownie przez pierwszy wątek po około drugim przejściu.

Więc w skrócie otrzymujemy wątek do wątku komunikacja za pomocą zmiennej warunkowej w wyniku pomiaru opóźnienia raz na sekundę.

W jądrze 2.6.32 opóźnienie to jest gdzieś rzędu 2.8-3.5 us, co jest rozsądne. W jądrze 3.2.0 opóźnienie to wzrosło do rzędu 40-100 us. Wykluczyłem wszelkie różnice w sprzęcie między dwoma hostami. Działają one na identycznym sprzęcie (procesory dual socket x5687 {Westmere-EP} pracujące z częstotliwością 3,6 GHz z hyperthreading, speedstep i wszystkie stany C wyłączone). Aplikacja testowa zmienia powinowactwo wątków do uruchamiania ich na niezależnych fizycznych rdzeniach tego samego gniazda (tzn. pierwszy wątek jest uruchamiany na rdzeniu 0, a drugi wątek na rdzeniu 1), więc nie ma odbijania wątków na rdzeniach ani odbijania/komunikacji między gniazdami.

Jedyną różnicą między dwoma hostami jest to, że jeden z nich działa z Ubuntu 10.04 LTS z jądrem 2.6.32-28 (szybkie przełączanie kontekstu), a drugi z najnowszym Ubuntu 12.04 LTS z jądrem 3.2.0-23 (wolne pole przełącznika kontekstowego). Wszystkie ustawienia BIOS - u i sprzęt są identyczne.

Czy były jakieś zmiany w jądrze, które mogłyby wyjaśnić to niedorzeczne spowolnienie w czasie, kiedy wątek zostanie zaplanowany do uruchomienia?

Aktualizacja: Jeśli chcesz uruchomić test na swoim hostingu i linux build, mam wysłany kod do pastebin do zapoznania się. Kompilator:

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

Uruchom z (zakładając, że masz co najmniej dwurdzeniowy pole): {]}

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

Aktualizacja 2 : Po długich poszukiwaniach parametrów jądra, postach na temat zmian w jądrze i osobistych badaniach, odkryłem na czym polega problem i opublikowałem rozwiązanie jako odpowiedź na to pytanie.

Author: Michael Goldshteyn, 2012-08-24

3 answers

Rozwiązanie problemu bad thread wake up performance problem W ostatnich jądrach ma związek z przełączeniem na Sterownik cpuidle intel_idle z acpi_idle, sterownika używanego w starszych jądrach. Niestety, sterownik intel_idle ignoruje konfigurację BIOSu użytkownika dla Stanów C i tańczy do własnej melodii . Innymi słowy, nawet jeśli całkowicie wyłączysz wszystkie stany C w BIOSie komputera (lub serwera), ten sterownik nadal będzie je włączał w okresach krótkiej nieaktywności, które są prawie zawsze dzieje się, chyba że cały rdzeń zużywa syntetyczny benchmark (np stres) jest uruchomiony. Możesz monitorować przejścia stanu C, wraz z innymi przydatnymi informacjami związanymi z częstotliwościami procesorów, za pomocą wspaniałego narzędzia Google i7z na większości kompatybilnego sprzętu.

Aby zobaczyć, który sterownik cpuidle jest aktualnie aktywny w Twojej konfiguracji, po prostu skopiuj plik current_driver w sekcji cpuidle /sys/devices/system/cpu w następujący sposób:

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

Jeśli chcesz, aby Twój nowoczesny system operacyjny Linux miał najniższy kontekst aby wyłączyć wszystkie te funkcje oszczędzania energii, należy dodać następujące parametry rozruchu jądra:]}

Na Ubuntu 12.04 możesz to zrobić, dodając je do wpisu GRUB_CMDLINE_LINUX_DEFAULT w /etc/default/grub, a następnie uruchamiając update-grub. Parametry rozruchu do dodania to:

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

Oto krwawe szczegóły o tym, co robią trzy opcje rozruchu:

Ustawienie intel_idle.max_cstate na zero spowoduje albo przywrócenie sterownika cpuidle do acpi_idle (przynajmniej w dokumentacji opcji), albo wyłączenie go całkowicie. Na moim pudełku jest całkowicie wyłączony (tzn. wyświetlenie pliku current_driver w /sys/devices/system/cpu/cpuidle generuje wyjście none). W tym przypadku druga opcja rozruchu processor.max_cstate=0 jest niepotrzebna. Jednak dokumentacja stwierdza, że ustawienie max_cstate na zero dla sterownika intel_idle powinno przywrócić system operacyjny do sterownika acpi_idle. Dlatego na wszelki wypadek wstawiam drugą opcję rozruchu.

Opcja processor.max_cstate ustawia maksymalny Stan C dla Sterownika acpi_idle na zero, miejmy nadzieję, że go również wyłączy. Nie wiem. mam system, na którym mogę to przetestować, ponieważ intel_idle.max_cstate=0 całkowicie powala sterownik cpuidle na całym dostępnym mi sprzęcie. Jeśli jednak Twoja instalacja przywróci cię z intel_idle do acpi_idle tylko za pomocą pierwszej opcji rozruchu, daj mi znać, czy druga opcja processor.max_cstate zrobiła to, co zostało udokumentowane w komentarzach, abym mógł zaktualizować tę odpowiedź.

Wreszcie, ostatni z trzech parametrów, idle=poll jest prawdziwym Wieprzem mocy. Wyłączy C1/C1E, który usunie Ostatnie opóźnienie kosztem znacznie większego zużycia energii, więc używaj tego tylko wtedy, gdy jest to naprawdę konieczne. Dla większości będzie to przesada, ponieważ opóźnienie C1* nie jest aż tak duże. Korzystając z mojej aplikacji testowej działającej na sprzęcie, który opisałem w oryginalnym pytaniu, opóźnienie wzrosło z 9 us do 3 us. Jest to z pewnością znaczne ograniczenie dla aplikacji wrażliwych na opóźnienia (np. handel finansowy, wysoka precyzja telemetrii / śledzenia, wysokie freq. dane akwizycja itp...), ale może nie być wart energii elektrycznej dla zdecydowanej większości aplikacji desktopowych. Jedynym sposobem, aby mieć pewność, jest profilowanie poprawy wydajności aplikacji w porównaniu z faktycznym wzrostem zużycia energii / ciepła przez sprzęt i rozważenie kompromisów.

Update:

Po dodatkowych testach z różnymi parametrami idle=* odkryłem, że ustawienie idle na mwait jeśli obsługiwane przez twój sprzęt jest znacznie lepsze pomysł. Wydaje się, że użycie instrukcji MWAIT/MONITOR pozwala procesorowi wejść do C1E bez zauważalnego opóźnienia dodawanego do czasu budzenia wątku. Z idle=mwait uzyskasz niższe temperatury procesora (w porównaniu do idle=poll), mniejsze zużycie energii i nadal zachowasz doskonałe niskie opóźnienia pętli bezczynności polling. Dlatego mój zaktualizowany zalecany zestaw parametrów rozruchu dla niskiego opóźnienia budzenia wątku PROCESORA w oparciu o te ustalenia to: {]}

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

Użycie idle=mwait zamiast idle=poll może również pomoc w zainicjowaniu Turbo Boost (pomagając procesorowi pozostać poniżej jego TDP [Thermal Design Power]) i hyperthreading (dla którego MWAIT jest idealnym mechanizmem do nie zużywania całego fizycznego rdzenia, unikając jednocześnie wyższych stanów C). To nie zostało jeszcze udowodnione w testach, jednak, co będę nadal robić.

Aktualizacja 2:

Opcja mwait idle została usunięta z nowszej wersji 3.jądra x (podziękowania dla użytkownika ck_ za aktualizację). Pozostawia nam to dwie opcje:

idle=halt - powinno działać tak dobrze jak mwait, ale przetestuj, aby upewnić się, że tak jest w przypadku twojego sprzętu. Instrukcja HLT jest prawie równoważna MWAIT z podpowiedzią stanu 0. Problem polega na tym, że przerwanie jest wymagane do wyjścia ze stanu HLT, podczas gdy zapis w pamięci (lub przerwanie) może być użyte do wyjścia ze stanu MWAIT. W zależności od tego, co jądro Linuksa używa w swojej bezczynnej pętli, może to uczynić MWAIT potencjalnie bardziej wydajnym. Więc, jak powiedziałem przetestuj / profil i sprawdź, czy spełnia Twoje potrzeby związane z opóźnieniami...

I

idle=poll - opcja najwyższej wydajności, kosztem energii i ciepła.

 92
Author: Michael Goldshteyn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-08 17:03:26

Być może to, co stało się wolniejsze, to futex, budulec zmiennych warunkowych. To rzuci trochę światła:

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

Then

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

Który pokaże mikrosekundy pobrane dla interesujących wywołań systemowych, posortowane według czasu.

On 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

Na jądrze 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

Znalazłem 5-letni raport o błędzie który zawiera test wydajności "ping ponga", który porównuje

  1. jednowątkowy libpthread mutex
  2. zmienna warunkowa libpthread
  3. plain old Unix signals

Musiałem dodać

#include <stdint.h>

W celu skompilowania, co zrobiłem za pomocą tego polecenia

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

On 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.

Na jądrze 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.

Wnioskuję, że pomiędzy jądrem 2.6.32 a 3.1.9 przełącznik kontekstowy rzeczywiście zwolnił, choć nie tak bardzo, jak w jądrze 3.2. Zdaję sobie sprawę, że to jeszcze nie odpowiada na twoje pytanie, będę trzymać kopanie.

Edit: odkryłem, że zmiana priorytetu w czasie rzeczywistym procesu (oba wątki) poprawia wydajność w 3.1.9, aby pasowała do 2.6.32. Jednak ustawienie tego samego priorytetu w punkcie 2.6.32 powoduje jego spowolnienie... zastanów się-przyjrzę się temu bardziej.

Oto moje wyniki:

On 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.
$ 

Na jądrze 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
Author: amdn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-24 19:11:03

Możesz również zobaczyć procesory klikające w dół w nowszych procesach i jądrach Linuksa ze względu na Sterownik pstate , który jest oddzielny od C-states. Dodatkowo, aby to wyłączyć, należy użyć następującego parametru jądra:

intel_pstate=disable

 0
Author: Kyle Brandt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-11 15:08:37