[linux] 새로운 리눅스 커널에서 컨텍스트 전환이 훨씬 느립니다.

서버의 OS를 Ubuntu 10.04 LTS에서 Ubuntu 12.04 LTS로 업그레이드하려고합니다. 안타깝게도 실행 가능한 스레드를 실행하기위한 지연 시간이 2.6 커널에서 3.2 커널로 크게 증가한 것 같습니다. 실제로 우리가 얻고있는 대기 시간 수치는 믿기 어렵습니다.

테스트에 대해 좀 더 구체적으로 말씀 드리겠습니다. 두 개의 스레드를 실행하는 프로그램이 있습니다. 첫 번째 스레드는 현재 시간 (RDTSC를 사용하는 틱 단위)을 가져온 다음 1 초에 한 번 조건 변수에 신호를 보냅니다. 두 번째 스레드는 조건 변수를 기다렸다가 신호를 받으면 깨어납니다. 그런 다음 현재 시간 (RDTSC를 사용하는 틱 단위)을 가져옵니다. 두 번째 스레드의 시간과 첫 번째 스레드의 시간 간의 차이가 계산되어 콘솔에 표시됩니다. 이 후 두 번째 스레드는 조건 변수를 다시 한 번 기다립니다. 약 1 초 후에 첫 번째 스레드가 다시 신호를 보냅니다.

즉, 결과적으로 1 초에 한 번씩 조건 변수 대기 시간 측정을 통해 스레드 간 통신을 얻습니다 .

커널 2.6.32에서이 지연 시간은 2.8-3.5 us 정도이며 합리적입니다. 커널 3.2.0에서이 지연 시간은 40-100 us 정도까지 증가했습니다. 두 호스트 간의 하드웨어 차이를 제외했습니다. 동일한 하드웨어에서 실행됩니다 (하이퍼 스레딩, 스피드 스텝 및 모든 C 상태가 꺼진 상태에서 3.6GHz에서 실행되는 듀얼 소켓 X5687 {Westmere-EP} 프로세서). 테스트 앱은 스레드의 선호도를 변경하여 동일한 소켓의 독립적 인 물리적 코어에서 실행하므로 (즉, 첫 번째 스레드는 Core 0에서 실행되고 두 번째 스레드는 Core 1에서 실행 됨) 스레드가 튀어 나오지 않습니다. 코어 또는 소켓 간의 바운싱 / 통신.

두 호스트의 유일한 차이점은 하나는 커널 2.6.32-28 (빠른 컨텍스트 스위치 상자)과 함께 Ubuntu 10.04 LTS를 실행하고 다른 하나는 커널 3.2.0-23 (느린 컨텍스트)과 함께 최신 Ubuntu 12.04 LTS를 실행하고 있다는 것입니다. 스위치 박스). 모든 BIOS 설정과 하드웨어는 동일합니다.

스레드가 실행되도록 예약하는 데 걸리는 시간이 엄청나게 느려지는 원인이 될 수있는 커널 변경 사항이 있습니까?

업데이트 :
호스트 및 Linux 빌드에서 테스트를 실행 하려면 코드를 pastebin게시했습니다 . 다음으로 컴파일 :

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

다음으로 실행 (최소한 듀얼 코어 박스가 있다고 가정) :

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

업데이트 2 : 커널 매개 변수, 커널 변경 사항 및 개인 연구에 대한 게시물을 많이 검색 한 후 문제가 무엇인지 파악하고이 질문에 대한 답변으로 솔루션을 게시했습니다.



답변

최근 커널 의 잘못된 스레드 깨우기 성능 문제 에 대한 intel_idle해결책 acpi_idle은 이전 커널에서 사용되는 드라이버 인에서 cpuidle 드라이버로 전환하는 것과 관련이 있습니다. 안타깝게도 intel_idle드라이버는 C 상태에 대한 사용자의 BIOS 구성을 무시 하고 자체 조정에 맞춰 춤을 춥니 다 . 즉, PC (또는 서버) BIOS에서 모든 C 상태를 완전히 비활성화하더라도이 드라이버는 일시적인 비활성 기간 동안 계속 강제로 활성화합니다. 이는 모든 코어를 사용하는 합성 벤치 마크 (예 : 스트레스 )이 실행 중입니다. 대부분의 호환 하드웨어에서 멋진 Google i7z 도구 를 사용하여 프로세서 주파수와 관련된 기타 유용한 정보와 함께 C 상태 전환을 모니터링 할 수 있습니다 .

현재 설정에서 활성화 된 cpuidle 드라이버를 확인하려면 다음과 같이 섹션에 current_driver파일을 분류하십시오 .cpuidle/sys/devices/system/cpu

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

최신 Linux OS에서 컨텍스트 전환 대기 시간을 최소화하려면 다음 커널 부팅 매개 변수를 추가하여 이러한 절전 기능을 모두 비활성화하십시오.

Ubuntu 12.04에서는 GRUB_CMDLINE_LINUX_DEFAULT항목에 추가 /etc/default/grub한 다음 update-grub. 추가 할 부팅 매개 변수는 다음과 같습니다.

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

세 가지 부팅 옵션이 수행하는 작업에 대한 자세한 내용은 다음과 같습니다.

intel_idle.max_cstate0으로 설정 하면 cpuidle 드라이버가 acpi_idle(적어도 옵션 문서에 따라)로 되돌 리거나 완전히 비활성화됩니다. 내 상자에서 그것은 완전히 비활성화되어 있습니다 (즉, current_driver파일을 표시 /sys/devices/system/cpu/cpuidle하면 출력이 생성됩니다 none). 이 경우 두 번째 부팅 옵션 processor.max_cstate=0은 필요하지 않습니다. 그러나 설명서에는 intel_idle드라이버에 대해 max_cstate를 0으로 설정 하면 OS가 acpi_idle드라이버로 되돌아 가야한다고 명시되어 있습니다. 따라서 경우에 대비하여 두 번째 부팅 옵션을 넣었습니다.

processor.max_cstate옵션은 acpi_idle드라이버 의 최대 C 상태 를 0으로 설정하여이 기능도 비활성화합니다. 내가 intel_idle.max_cstate=0사용할 수있는 모든 하드웨어에서 cpuidle 드라이버를 완전히 녹아웃시키기 때문에 이것을 테스트 할 수있는 시스템이 없습니다 . 설치가에서 당신 되돌리기 않는 경우, intel_idleacpi_idle바로 첫 번째 부팅 옵션을, 두 번째 옵션이 있으면 알려 주시기 바랍니다 processor.max_cstate가 나는이 대답을 업데이트 할 수 있도록 의견에서 할 문서화 있었는지했다.

마지막으로 세 매개 변수 중 마지막 매개 변수는 idle=poll진짜 파워 돼지입니다. C1 / C1E를 비활성화하여 훨씬 더 많은 전력 소비를 희생하면서 마지막 남은 지연 시간을 제거하므로 실제로 필요할 때만 사용하십시오. 대부분의 경우 C1 * 지연 시간이 그다지 크지 않기 때문에 과잉입니다. 원래 질문에서 설명한 하드웨어에서 실행되는 테스트 응용 프로그램을 사용하면 지연 시간이 9 us에서 3 us로 늘어났습니다. 이는 지연 시간에 민감한 애플리케이션 (예 : 금융 거래, 고정밀 원격 측정 / 추적, 고주파수 데이터 수집 등)의 경우 확실히 상당한 감소이지만 대부분의 데스크톱 앱. 확실하게 알 수있는 유일한 방법은 애플리케이션의 성능 향상을 프로파일 링하는 것입니다.

최신 정보:

다양한 idle=*매개 변수로 추가 테스트를 한 후 하드웨어에서 지원하는 경우로 설정 idle하는 mwait것이 훨씬 더 나은 아이디어라는 것을 발견했습니다 . 사용 보인다 MWAIT/MONITOR지침은 CPU가 눈에 띄는 지연이 시간까지 스레드 여파에 추가하지 않고 C1E를 입력 할 수 있습니다. 를 사용하면 idle=mwaitCPU 온도가 낮아지고 (에 비해 idle=poll) 전력 사용량이 줄어들고 폴링 유휴 루프의 뛰어난 낮은 대기 시간을 계속 유지할 수 있습니다. 따라서 이러한 결과를 기반으로 낮은 CPU 스레드 깨우기 대기 시간에 대해 업데이트 된 권장 부팅 매개 변수 집합은 다음과 같습니다.

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

idle=mwait대신 대신을 사용 idle=poll하면 Turbo Boost (CPU가 TDP [Thermal Design Power] 이하로 유지되도록함으로써) 및 하이퍼 스레딩 (MWAIT이 동시에 전체 물리적 코어를 소비하지 않는 이상적인 메커니즘)의 시작에 도움 이 될 수 있습니다. 더 높은 C 상태를 피하는 시간). 이것은 아직 테스트에서 입증되지 않았으며 계속해서 수행 할 것입니다.

업데이트 2 :

mwait유휴 옵션이되어 새로운 3.x를 커널에서 제거 (업데이트에 대한 사용자 ck_ 덕분에). 그러면 두 가지 옵션이 있습니다.

idle=halt-와 같이 작동해야 mwait하지만 하드웨어에 해당하는지 테스트하십시오. 이 HLT명령어는 MWAITwith state hint 0과 거의 동일 합니다. 문제는 HLT 상태에서 벗어나려면 인터럽트가 필요하지만 MWAIT 상태에서 벗어나려면 메모리 쓰기 (또는 인터럽트)를 사용할 수 있다는 사실에 있습니다. Linux 커널이 유휴 루프에서 사용하는 것에 따라 MWAIT를 잠재적으로 더 효율적으로 만들 수 있습니다. 그래서 내가 테스트 / 프로필을 말하고 그것이 당신의 대기 시간 요구를 충족하는지 확인하십시오 …

idle=poll -전력과 열을 희생하는 최고의 성능 옵션.


답변

더 느려진 것은 아마도 조건 변수의 구성 요소 인 futex 일 것입니다. 이것은 약간의 빛을 비출 것입니다.

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

그때

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

흥미로운 시스템 호출에 소요 된 마이크로 초가 시간별로 정렬되어 표시됩니다.

커널 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

커널 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

비교하는 “핑퐁”성능 테스트가 포함 된 5 년 된 버그 보고서 를 찾았습니다.

  1. 단일 스레드 libpthread 뮤텍스
  2. libpthread 조건 변수
  3. 평범한 오래된 유닉스 신호

나는 추가해야했다

#include <stdint.h>

컴파일하기 위해이 명령으로

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

커널 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.

커널 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.

커널 3.2에서 관찰 한 것만 큼은 아니지만 커널 2.6.32와 3.1.9 사이의 컨텍스트 전환이 실제로 느려 졌다고 결론을 내립니다. 아직 귀하의 질문에 대한 답변이 아님을 알고 있습니다. 계속해서 파헤칠 것입니다.

편집 : 프로세스 (두 스레드 모두)의 실시간 우선 순위를 변경하면 3.1.9의 성능이 2.6.32와 일치하도록 향상된다는 것을 발견했습니다. 그러나 2.6.32에 동일한 우선 순위를 설정하면 속도가 느려집니다. 그림으로 이동-더 자세히 살펴 보겠습니다.

내 결과는 다음과 같습니다.

커널 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.
$

커널 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.
$


답변

c-states와 분리 된 pstate 드라이버 로 인해 최신 프로세스 및 Linux 커널에서 프로세서가 클릭 다운되는 것을 볼 수도 있습니다 . 따라서이를 비활성화하려면 다음 커널 매개 변수를 사용해야합니다.

intel_pstate=disable


답변