Bối cảnh chuyển đổi chậm hơn nhiều trong nhân linux mới


99

Chúng tôi đang tìm cách nâng cấp Hệ điều hành trên máy chủ của mình từ Ubuntu 10.04 LTS lên Ubuntu 12.04 LTS. Thật không may, có vẻ như độ trễ để chạy một luồng đã trở nên có thể chạy được đã tăng lên đáng kể từ nhân 2.6 lên nhân 3.2. Trên thực tế, những con số về độ trễ mà chúng ta đang nhận được rất khó tin.

Hãy để tôi nói rõ hơn về bài kiểm tra. Chúng tôi có một chương trình chạy hai luồng. Luồng đầu tiên lấy thời gian hiện tại (trong tích tắc sử dụng RDTSC) và sau đó báo hiệu một biến điều kiện mỗi giây một lần. Luồng thứ hai chờ biến điều kiện và thức dậy khi nó được báo hiệu. Sau đó, nó nhận được thời gian hiện tại (trong tích tắc sử dụng RDTSC). Chênh lệch giữa thời gian trong luồng thứ hai và thời gian trong luồng đầu tiên được tính toán và hiển thị trên bảng điều khiển. Sau đó, luồng thứ hai đợi biến điều kiện một lần nữa. Nó sẽ được báo hiệu lại bởi luồng đầu tiên sau khoảng một giây trôi qua.

Vì vậy, tóm lại, chúng ta nhận được một luồng để phân luồng giao tiếp thông qua kết quả là đo độ trễ biến điều kiện mỗi giây một lần.

Trong kernel 2.6.32, độ trễ này nằm ở đâu đó theo thứ tự 2,8-3,5 us, điều này là hợp lý. Trong kernel 3.2.0, độ trễ này đã tăng lên đến một nơi nào đó theo thứ tự 40-100 us. Tôi đã loại trừ bất kỳ sự khác biệt nào về phần cứng giữa hai máy chủ. Chúng chạy trên phần cứng giống hệt nhau (bộ xử lý ổ cắm kép X5687 {Westmere-EP} chạy ở tốc độ 3,6 GHz với siêu phân luồng, tốc độ nhanh và tất cả các trạng thái C đã tắt). Ứng dụng thử nghiệm thay đổi mối quan hệ của các luồng để chạy chúng trên các lõi vật lý độc lập của cùng một ổ cắm (tức là luồng đầu tiên được chạy trên Core 0 và luồng thứ hai chạy trên Core 1), vì vậy không có luồng nào bị trả lại trên lõi hoặc nảy / giao tiếp giữa các ổ cắm.

Sự khác biệt duy nhất giữa hai máy chủ là một máy đang chạy Ubuntu 10.04 LTS với nhân 2.6.32-28 (hộp chuyển đổi ngữ cảnh nhanh) và máy còn lại đang chạy Ubuntu 12.04 LTS mới nhất với nhân 3.2.0-23 (bối cảnh chậm hộp chuyển đổi). Tất cả các cài đặt BIOS và phần cứng đều giống hệt nhau.

Đã có bất kỳ thay đổi nào trong hạt nhân có thể giải thích cho việc làm chậm vô lý này trong bao lâu để một luồng được lên lịch chạy?

Cập nhật: Nếu bạn muốn chạy thử nghiệm trên máy chủ và bản dựng linux của mình, tôi đã đăng mã lên pastebin để bạn xem xét. Biên dịch với:

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

Chạy với (giả sử bạn có ít nhất một hộp lõi kép):

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

Cập nhật 2 : Sau nhiều lần tìm kiếm thông qua các tham số kernel, các bài đăng về thay đổi kernel và nghiên cứu cá nhân, tôi đã tìm ra vấn đề là gì và đã đăng giải pháp làm câu trả lời cho câu hỏi này.


1
chỉ là một phỏng đoán, nhưng có thể thay đổi một tham số từ /proc/sys/kernel/*có thể hoạt động? Nếu bạn tìm thấy thứ gì đó hoạt động, hãy đưa cấu hình đó vào /etc/sysctl.confhoặc một tệp /etc/sysctl.d/để làm cho nó tồn tại qua các lần khởi động lại.
Carlos Campderrós

1
Tôi đã so sánh / proc / sys / kernel giữa hai máy chủ, nhưng không thấy sự khác biệt có ý nghĩa nào, đặc biệt là trong bất kỳ mục cấu hình liên quan đến lập lịch nào.
Michael Goldshteyn

Tôi mơ hồ nhớ lại một tin đồn rằng RDTSC không nhất thiết phải được đồng bộ hóa đúng cách giữa các lõi, nhưng tôi hy vọng rằng nếu đây là một vấn đề, bạn sẽ thấy thời gian đảo ngược. Bạn đã thử tìm kiếm các mối quan hệ để chạy cả hai luồng trên cùng một lõi và xem điều gì sẽ xảy ra?
David Given

Trên các lõi Intel mới này, RDTSC hoạt động hoàn hảo trên các lõi, đặc biệt là các lõi trên cùng một CPU (tức là cùng một ổ cắm). Điều thú vị là nếu cả hai luồng chạy trên cùng một lõi, độ trễ giảm xuống còn 4-10 chúng tôi trên nhân mới hơn và xấp xỉ. 3 us trên kernel cũ hơn.
Michael Goldshteyn

Chỉ là một nhận xét chung - dựa vào TSC để được đồng bộ hóa là tốt nhất, mặc dù trong trường hợp cụ thể của bạn, vì bạn đang sử dụng hai lõi trên một chip vật lý, nên nó thực sự sẽ hoạt động tốt.
twalberg

Câu trả lời:


95

Giải pháp cho vấn đề hiệu suất đánh thức luồng không hợp lệ trong các hạt nhân gần đây liên quan đến việc chuyển sang intel_idletrình điều khiển cpuidle acpi_idle, trình điều khiển được sử dụng trong các nhân cũ hơn. Đáng buồn thay, intel_idletrình điều khiển bỏ qua cấu hình BIOS của người dùng cho các trạng thái C và nhảy theo giai điệu của riêng nó . Nói cách khác, ngay cả khi bạn vô hiệu hóa hoàn toàn tất cả các trạng thái C trong BIOS của PC (hoặc máy chủ), trình điều khiển này sẽ vẫn buộc chúng hoạt động trong khoảng thời gian ngắn không hoạt động, điều này hầu như luôn xảy ra trừ khi một tiêu chuẩn tổng hợp tiêu tốn toàn bộ lõi (ví dụ: căng thẳng ) đang chạy. Bạn có thể theo dõi quá trình chuyển đổi trạng thái C, cùng với thông tin hữu ích khác liên quan đến tần số bộ xử lý, bằng cách sử dụng công cụ Google i7z tuyệt vời trên hầu hết các phần cứng tương thích.

Để xem trình điều khiển cpuidle nào hiện đang hoạt động trong thiết lập của bạn, chỉ cần đặt current_drivertệp trong cpuidlephần /sys/devices/system/cpunhư sau:

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

Nếu bạn muốn hệ điều hành Linux hiện đại của mình có độ trễ chuyển đổi ngữ cảnh thấp nhất có thể, hãy thêm các tham số khởi động hạt nhân sau để tắt tất cả các tính năng tiết kiệm năng lượng này:

Trên Ubuntu 12.04, bạn có thể thực hiện việc này bằng cách thêm chúng vào GRUB_CMDLINE_LINUX_DEFAULTmục nhập /etc/default/grubvà sau đó chạy update-grub. Các thông số khởi động cần thêm là:

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

Dưới đây là chi tiết đẫm máu về chức năng của ba tùy chọn khởi động:

Đặt intel_idle.max_cstatethành 0 sẽ hoàn nguyên trình điều khiển cpuidle của bạn về acpi_idle(ít nhất là theo tài liệu của tùy chọn) hoặc vô hiệu hóa hoàn toàn. Trên hộp của tôi, nó hoàn toàn bị vô hiệu hóa (tức là hiển thị current_drivertệp trong /sys/devices/system/cpu/cpuidletạo ra kết quả là none). Trong trường hợp này, tùy chọn khởi động thứ hai processor.max_cstate=0là không cần thiết. Tuy nhiên, tài liệu nói rằng việc đặt max_cstate thành 0 cho intel_idletrình điều khiển sẽ hoàn nguyên hệ điều hành vềacpi_idle trình điều khiển. Do đó, tôi đã đưa vào tùy chọn khởi động thứ hai để đề phòng.

Các processor.max_cstatetùy chọn thiết lập trạng thái tối đa C cho acpi_idletài xế không, hy vọng vô hiệu hóa nó là tốt. Tôi không có hệ thống nào có thể kiểm tra điều này, vì loại bỏ intel_idle.max_cstate=0hoàn toàn trình điều khiển cpuidle trên tất cả phần cứng có sẵn cho tôi. Tuy nhiên, nếu quá trình cài đặt của bạn hoàn nguyên intel_idlevề acpi_idlechỉ với tùy chọn khởi động đầu tiên, vui lòng cho tôi biết nếu tùy chọn thứ hai,processor.max_cstate nó đã làm những gì được ghi nhận trong các nhận xét để tôi có thể cập nhật câu trả lời này.

Cuối cùng, tham số cuối cùng trong ba tham số, idle=polllà một con lợn quyền lực thực sự. Nó sẽ vô hiệu hóa C1 / C1E, điều này sẽ loại bỏ bit độ trễ cuối cùng còn lại với chi phí tiêu thụ điện năng nhiều hơn, vì vậy chỉ sử dụng nó khi thực sự cần thiết. Đối với hầu hết điều này sẽ là quá mức cần thiết, vì độ trễ C1 * không lớn như vậy. Sử dụng ứng dụng thử nghiệm của tôi chạy trên phần cứng mà tôi đã mô tả trong câu hỏi ban đầu, độ trễ đã tăng từ 9 chúng tôi xuống 3 chúng tôi. Đây chắc chắn là một mức giảm đáng kể đối với các ứng dụng nhạy cảm với độ trễ cao (ví dụ: giao dịch tài chính, đo lường / theo dõi từ xa có độ chính xác cao, thu thập dữ liệu tần suất cao, v.v.), nhưng có thể không xứng đáng với lượng điện phát sinh đối với đại đa số ứng dụng máy tính để bàn. Cách duy nhất để biết chắc chắn là lập hồ sơ về sự cải thiện hiệu suất của ứng dụng so với

Cập nhật:

Sau khi thử nghiệm bổ sung với các idle=*thông số khác nhau , tôi đã phát hiện ra rằng đặt idlethành mwaitnếu được phần cứng của bạn hỗ trợ là một ý tưởng tốt hơn nhiều. Có vẻ như việc sử dụng các MWAIT/MONITORhướng dẫn cho phép CPU vào C1E mà không có bất kỳ độ trễ đáng chú ý nào được thêm vào thời gian đánh thức luồng. Với idle=mwait, bạn sẽ nhận được nhiệt độ CPU mát hơn (so với idle=poll), sử dụng ít năng lượng hơn và vẫn giữ được độ trễ thấp tuyệt vời của vòng lặp nhàn rỗi thăm dò. Do đó, bộ thông số khởi động được đề xuất cập nhật của tôi cho độ trễ đánh thức luồng CPU thấp dựa trên những phát hiện này là:

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

Việc sử dụng idle=mwaitthay vì idle=pollcũng có thể giúp khởi động Turbo Boost (bằng cách giúp CPU ở dưới mức TDP [Công suất thiết kế nhiệt]) và siêu phân luồng (mà MWAIT là cơ chế lý tưởng để không tiêu thụ toàn bộ lõi vật lý trong khi ở cùng thời gian tránh các trạng thái C cao hơn). Tuy nhiên, điều này vẫn chưa được chứng minh trong thử nghiệm, điều này tôi sẽ tiếp tục làm.

Cập nhật 2:

Các mwaittùy chọn nhàn rỗi đã được lấy ra từ hạt nhân 3.x mới hơn (nhờ ck_ sử dụng để cập nhật). Điều đó khiến chúng tôi có hai lựa chọn:

idle=halt- Vẫn hoạt động tốt mwait, nhưng hãy kiểm tra để chắc chắn rằng đây là trường hợp với phần cứng của bạn. Các HLThướng dẫn là gần như tương đương với mộtMWAIT với gợi ý trạng thái với 0. Vấn đề nằm ở chỗ, một ngắt được yêu cầu để thoát ra khỏi trạng thái HLT, trong khi ghi (hoặc ngắt) bộ nhớ có thể được sử dụng để thoát ra khỏi trạng thái MWAIT. Tùy thuộc vào những gì Nhân Linux sử dụng trong vòng lặp nhàn rỗi của nó, điều này có thể làm cho MWAIT có khả năng hiệu quả hơn. Vì vậy, như tôi đã nói kiểm tra / hồ sơ và xem liệu nó có đáp ứng nhu cầu về độ trễ của bạn không ...

idle=poll - Tùy chọn hiệu suất cao nhất, không tốn điện và nhiệt.


Xin lỗi, nhưng tại sao bạn lại mong đợi trạng thái C được quản lý bởi phần sụn? Trạng thái tạm ngưng là trạng thái thời gian chạy và chúng được hệ điều hành quản lý theo thiết kế. Như bạn đã phát hiện ra, nếu bạn không muốn tạm ngừng thời gian chạy, đừng sử dụng nó.
Andy Ross

6
Xin lỗi, nhưng trạng thái C, EIST và C1E có thể bị tắt trong BIOS. Tôi hy vọng hệ điều hành sẽ tôn trọng cài đặt BIOS của tôi. Điều này đặc biệt đúng, với công cụ và tài liệu khủng khiếp trong trường hợp này.
Michael Goldshteyn

4
Có thể tắt thông qua bios của bạn. Tôi không biết bất cứ điều gì trong một thông số kỹ thuật có liên quan yêu cầu điều đó. Xin lỗi, nhưng "mong đợi" bất cứ điều gì từ BIOS sẽ khiến bạn liên tục gặp khó khăn. Điều tốt nhất mà phần sụn có thể làm trong một PC hiện đại là không có gì. Tôi xin lỗi vì bạn đã ngạc nhiên, nhưng thành thật mà nói đây là lỗi của người dùng. Điểm chuẩn của bạn đo thời gian tạm ngừng và tiếp tục.
Andy Ross

19
Một trong những vai trò của lựa chọn tính năng BIOS là bật / tắt thiết bị. Trong một số trường hợp, các lựa chọn này bắt buộc trên HĐH (ví dụ: USB trên bo mạch chủ, eSATA và NIC). Trong một số trường hợp khác, hệ điều hành phải tôn trọng mong muốn của bạn (ví dụ: EIST, trạng thái C, Siêu phân luồng, Tắt thực thi, AES-NI, Ảo hóa, v.v.). BIOS cung cấp một thiết bị trung tâm / bề mặt lựa chọn tính năng duy nhất trung lập với hệ điều hành. Điều này cho phép người dùng cài đặt nhiều hệ điều hành (có lẽ rất khác nhau) trên máy chủ lưu trữ sử dụng các tính năng phần cứng giống nhau. Tuy nhiên, câu trả lời này là chủ quan nên sẽ phải đồng ý không đồng ý.
Michael Goldshteyn

1
nhàn rỗi = mwait không còn được hỗ trợ trong hạt nhân 3.x gần đây lkml.org/lkml/2013/2/10/21 có lời khuyên thay thế nào không?
ck_

8

Có lẽ thứ chậm hơn là futex, khối xây dựng cho các biến điều kiện. Điều này sẽ làm sáng tỏ:

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

sau đó

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

sẽ hiển thị số micro giây được thực hiện cho các lệnh gọi hệ thống thú vị, được sắp xếp theo thời gian.

Trên 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

Trên 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

Tôi đã tìm thấy báo cáo lỗi 5 năm tuổi này có chứa bài kiểm tra hiệu suất "bóng bàn" để so sánh

  1. mutex libpthread đơn luồng
  2. biến điều kiện libpthread
  3. tín hiệu Unix cũ đơn giản

Tôi đã phải thêm

#include <stdint.h>

để biên dịch, mà tôi đã làm với lệnh này

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

Trên 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.

Trên 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.

Tôi kết luận rằng chuyển đổi ngữ cảnh giữa kernel 2.6.32 và 3.1.9 đã thực sự chậm lại, mặc dù không nhiều như bạn thấy trong kernel 3.2. Tôi nhận ra rằng điều này vẫn chưa trả lời câu hỏi của bạn, tôi sẽ tiếp tục đào.

Chỉnh sửa: Tôi nhận thấy rằng việc thay đổi mức ưu tiên thời gian thực của quy trình (cả hai luồng) sẽ cải thiện hiệu suất trên 3.1.9 để phù hợp với 2.6.32. Tuy nhiên, việc đặt cùng một mức độ ưu tiên trên 2.6.32 khiến nó chạy chậm lại ... hãy xem - Tôi sẽ xem xét kỹ hơn.

Đây là kết quả của tôi bây giờ:

Trên 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.
$ 

Trên 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.
$ 

Tôi đã chạy nó trên Fedora và CentOS, không có Ubuntu. Tôi sẽ đăng kết quả của tôi.
amdn

OK, tôi đã chạy nó trên cả hai máy chủ (tức là và các hạt nhân khác nhau) và kết quả hầu như không có sự khác biệt. Vì vậy, thử nghiệm này không làm nổi bật bất kỳ sự khác biệt nào. Thời gian cuộc gọi futex khác nhau ở chữ số thập phân thứ tư - giảm hiệu suất không đáng kể. Chờ đã, toàn bộ số có tính bằng giây không? Tôi chỉ thấy bạn đăng kết quả của bạn và chúng xuất hiện tương tự như tôi ...
Michael Goldshteyn

Ok, điều đó loại trừ việc triển khai futex - chúng tôi quay lại lý thuyết của bạn về chuyển đổi ngữ cảnh .... vui lòng xóa câu trả lời này vì nó thực sự thuộc về các nhận xét ... Tôi chỉ muốn khả năng định dạng các lệnh.
amdn

Có, thời gian tính bằng giây ... các lệnh gọi đến futex kéo dài hơn một giây là cho luồng đang chờ với điều kiện.
amdn

Vì vậy, nếu bạn thu thập được bất cứ điều gì từ kết quả?
Michael Goldshteyn

1

Bạn cũng có thể thấy bộ xử lý nhấp xuống trong các quy trình gần đây hơn và nhân Linux do trình điều khiển pstate tách biệt với trạng thái c. Vì vậy, ngoài ra, để vô hiệu hóa điều này, bạn tham số hạt nhân sau:

intel_pstate=disable

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.