Bağlam, yeni linux çekirdeklerinde çok daha yavaş değişiyor


99

Sunucularımızdaki işletim sistemini Ubuntu 10.04 LTS'den Ubuntu 12.04 LTS'ye yükseltmek istiyoruz. Ne yazık ki, çalıştırılabilir hale gelen bir iş parçacığını çalıştırma gecikmesi 2.6 çekirdekten 3.2 çekirdeğe doğru önemli ölçüde artmış gibi görünüyor. Aslında, aldığımız gecikme sayılarına inanmak zor.

Test hakkında daha net konuşmama izin verin. İki iş parçacığı çalıştıran bir programımız var. İlk iş parçacığı geçerli zamanı alır (RDTSC kullanılarak yapılan işaretler halinde) ve ardından saniyede bir koşul değişkenini işaret eder. İkinci iş parçacığı durum değişkeninde bekler ve sinyal verildiğinde uyanır. Daha sonra o anki saati alır (RDTSC kullanarak tik olarak). İkinci iş parçacığındaki zaman ile birinci iş parçacığındaki zaman arasındaki fark hesaplanır ve konsolda görüntülenir. Bundan sonra ikinci iş parçacığı koşul değişkeninde bir kez daha bekler. Yaklaşık bir ikinci geçişten sonra ilk iş parçacığı tarafından tekrar sinyal verilecektir.

Özetle, sonuç olarak saniyede bir koşul değişken gecikme ölçümü aracılığıyla iş parçacığına bir iletişim elde ediyoruz .

Çekirdek 2.6.32'de, bu gecikme makul olan 2.8-3.5 us seviyesinde bir yerde. Çekirdek 3.2.0'da, bu gecikme 40-100 us civarında bir yere yükseldi. İki ana bilgisayar arasındaki donanım farklarını dışladım. Aynı donanımda çalışırlar (hiper iş parçacığı, speedstep ve tüm C durumları kapalı olarak 3.6 GHz'de çalışan çift soketli X5687 {Westmere-EP} işlemciler). Test uygulaması, iş parçacıklarını aynı soketin bağımsız fiziksel çekirdeklerinde çalıştırmak için yakınlığını değiştirir (yani, ilk iş parçacığı Çekirdek 0 üzerinde çalıştırılır ve ikinci iş parçacığı Çekirdek 1 üzerinde çalıştırılır), bu nedenle çekirdekler veya soketler arasında sıçrayan / iletişim.

İki ana bilgisayar arasındaki tek fark, birinin 2.6.32-28 çekirdeğiyle Ubuntu 10.04 LTS'yi (hızlı bağlam değiştirme kutusu) çalıştırması ve diğerinin en son Ubuntu 12.04 LTS'yi çekirdek 3.2.0-23 ile çalıştırmasıdır (yavaş bağlam anahtar kutusu). Tüm BIOS ayarları ve donanımı aynıdır.

Çekirdekte, bir iş parçacığının çalışması için planlanmasının ne kadar sürdüğü bu saçma yavaşlamanın nedenini açıklayabilecek herhangi bir değişiklik oldu mu?

Güncelleme: Testi ana bilgisayar ve linux yapınızda çalıştırmak isterseniz , kodu incelemeniz için pastebin'e gönderdim . Şununla derleyin:

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

İle çalıştırın (en az bir çift çekirdekli kutunuz olduğunu varsayarak):

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

Güncelleme 2 : Çekirdek parametreleri üzerinde çok fazla araştırma yaptıktan, çekirdek değişiklikleri ve kişisel araştırmalarla ilgili yazılar yazdıktan sonra sorunun ne olduğunu anladım ve bu sorunun cevabı olarak çözümü gönderdim.


1
sadece bir tahmin, ancak bir parametreyi değiştirmek /proc/sys/kernel/*işe yarayabilir mi? Çalışan bir şey bulursanız, yeniden başlatma /etc/sysctl.confsırasında /etc/sysctl.d/kalması için bu yapılandırmayı veya bir dosyayı yerleştirin .
Carlos Campderrós

1
İki ana bilgisayar arasında / proc / sys / kernel'i karşılaştırdım, ancak özellikle zamanlamayla ilgili herhangi bir yapılandırma öğesinde anlamlı bir fark görmedim.
Michael Goldshteyn

RDTSC'nin çekirdekler arasında mutlaka düzgün şekilde senkronize edilmediğine dair bir söylenti hatırlıyorum, ancak bu bir sorun olsaydı zamanın tersine döndüğünü görmenizi beklerdim. Her iki iş parçacığını da aynı çekirdek üzerinde çalıştırmak için eğilimleri kurcalamayı ve ne olduğunu görmeyi denediniz mi?
David

Intel çekirdeklerinde bu yeni, RDTSC çekirdekler arasında, özellikle aynı CPU üzerindeki çekirdeklerde (yani aynı soket) kusursuz bir şekilde çalışır. İlginç bir şekilde, her iki iş parçacığı da aynı çekirdek üzerinde çalıştırılırsa, gecikme süreleri yeni çekirdekte 4-10 bize ve yaklaşık olarak. 3 eski çekirdekte bize.
Michael Goldshteyn

Sadece genel bir yorum - senkronize edilecek TSC'lere güvenmek en iyi ihtimalle şüphelidir, ancak sizin özel durumunuzda, bir fiziksel yongada iki çekirdek kullandığınız için aslında işe yaraması gerekir.
twalberg

Yanıtlar:


95

Son çekirdeklerdeki kötü iş parçacığı uyandırma performansı sorununun çözümü , eski çekirdeklerde kullanılan sürücüden intel_idlecpuidle sürücüsüne geçişle ilgilidir acpi_idle. Ne yazık ki, intel_idlesürücü C-durumları için kullanıcının BIOS yapılandırmasını görmezden geliyor ve kendi ayarına göre dans ediyor . Başka bir deyişle, bilgisayarınızın (veya sunucunun) BIOS'undaki tüm C durumlarını tamamen devre dışı bıraksanız bile, bu sürücü, kısa devre dışı kalma süreleri sırasında bunları çalışmaya zorlayacaktır. ) çalışıyor. En uyumlu donanımlarda harika Google i7z aracını kullanarak işlemci frekanslarıyla ilgili diğer yararlı bilgilerle birlikte C durum geçişlerini izleyebilirsiniz .

Kurulumunuzda şu anda hangi cpuidle sürücüsünün etkin olduğunu görmek için, aşağıdaki bölümdeki current_driverdosyayı seçin :cpuidle/sys/devices/system/cpu

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

Modern Linux işletim sisteminizin mümkün olan en düşük bağlam anahtarı gecikmesine sahip olmasını istiyorsanız, tüm bu güç tasarrufu özelliklerini devre dışı bırakmak için aşağıdaki çekirdek önyükleme parametrelerini ekleyin:

Ubuntu 12.04'te, bunu GRUB_CMDLINE_LINUX_DEFAULTgirişe ekleyerek /etc/default/grubve ardından çalıştırarak yapabilirsiniz update-grub. Eklenecek önyükleme parametreleri şunlardır:

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

İşte üç önyükleme seçeneğinin ne işe yaradığına dair kanlı ayrıntılar:

intel_idle.max_cstateSıfıra ayarlamak , cpuidle sürücünüzü acpi_idle(en azından seçeneğin belgelerine göre) döndürür veya tamamen devre dışı bırakır. Kutumda tamamen devre dışı bırakılmış (yani, current_driverdosyanın içinde görüntülenmesi /sys/devices/system/cpu/cpuidlebir çıktı üretir none). Bu durumda ikinci önyükleme seçeneği processor.max_cstate=0gereksizdir. Bununla birlikte, dokümantasyon, intel_idlesürücü için max_cstate'in sıfıra ayarlanmasının işletim sistemini sürücüye döndürmesi gerektiğini belirtir acpi_idle. Bu nedenle, her ihtimale karşı ikinci önyükleme seçeneğini koydum.

processor.max_cstateOpsiyon için maksimum C durumunu ayarlar acpi_idleumarım de onu devre dışı bırakarak, sıfıra sürücüsü. Bunu test edebileceğim bir sistemim yok çünkü intel_idle.max_cstate=0cpuidle sürücüsünü kullanabileceğim tüm donanımlarda tamamen devre dışı bırakıyor. Yükleme size geri dönme eğilimi yaparsa Ancak, intel_idlehiç acpi_idlesadece ilk önyükleme seçeneği ile, ikinci seçenek, bana bildirin lütfen processor.max_cstateben bu cevabı güncelleme böylece yorumlarda yapmak belgelendi şeyi yaptı.

Son olarak, üç parametrenin sonuncusu, idle=pollgerçek bir güç domuzudur. Çok daha fazla güç tüketimi pahasına kalan son gecikme süresini ortadan kaldıracak olan C1 / C1E'yi devre dışı bırakacaktır, bu nedenle bunu yalnızca gerçekten gerekli olduğunda kullanın. Çoğu için, C1 * gecikmesi o kadar büyük olmadığından, bu aşırı olacaktır. Asıl soruda anlattığım donanım üzerinde çalışan test uygulamamı kullandığım zaman gecikme 9 bizden 3 bize çıktı. Bu kesinlikle gecikmeye duyarlı uygulamalar için (örn. Finansal ticaret, yüksek hassasiyetli telemetri / izleme, yüksek frekanslı veri toplama, vb.) Önemli bir azalmadır, ancak büyük çoğunluğu için maruz kalınan elektrik gücü darbesine değmeyebilir. masaüstü uygulamaları. Kesin olarak bilmenin tek yolu, uygulamanızın performansına karşı performansındaki iyileşmenin profilini çıkarmaktır.

Güncelleme:

Çeşitli ek testlerden sonra idle=*parametreler, ben bu ayarı keşfettim idleiçin mwaitdonanımınız destekliyorsa çok daha iyi bir fikirdir. Görünüşe göre MWAIT/MONITORkomutların kullanımı , iş parçacığı uyanma süresine fark edilebilir herhangi bir gecikme olmaksızın CPU'nun C1E'ye girmesine izin veriyor. İle idle=mwait, daha düşük CPU sıcaklıkları (ile karşılaştırıldığında idle=poll), daha az güç kullanımı elde edecek ve yine de bir yoklama boşta döngüsünün mükemmel düşük gecikmelerini koruyacaksınız. Bu nedenle, bu bulgulara dayalı olarak düşük CPU iş parçacığı uyanma gecikmesi için güncellenmiş önerilen önyükleme parametreleri setim:

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

Bunun idle=mwaityerine seçeneğinin kullanılması, idle=pollTurbo Boost'un başlatılmasına (CPU'nun TDP [Termal Tasarım Gücü] 'nün altında kalmasına yardımcı olarak) ve hiper iş parçacığı (MWAIT'in aynı anda tüm bir fiziksel çekirdeği tüketmemek için ideal mekanizma olduğu) yardımcı olabilir. daha yüksek C durumlarından kaçınma zamanı). Bununla birlikte, bunu yapmaya devam edeceğim testlerde henüz kanıtlanmadı.

Güncelleme 2:

mwaitBoşta seçenek olmuştur yeni 3.x çekirdekleri çıkarılır (güncelleme için kullanıcı ck_ sayesinde). Bu bize iki seçenek bırakıyor:

idle=halt- İyi çalışmalı mwait, ancak donanımınızda durumun böyle olduğundan emin olmak için test edin. HLTKullanıcı, bir hemen hemen eşit olması MWAITdurumu ipucu 0 Bellek yazma (ya da kesme) mwait durumunda dışarı almak için kullanılabilir iken bir kesme bir HLT devlet elde etmek için gerekli olduğu aslında sorun yalan ile. Linux Kernel'in boş döngüsünde ne kullandığına bağlı olarak, bu MWAIT'i potansiyel olarak daha verimli hale getirebilir. Yani, test / profil dediğim gibi ve gecikme ihtiyaçlarınızı karşılayıp karşılamadığını görün ...

ve

idle=poll - Güç ve ısı pahasına en yüksek performans seçeneği.


Pardon ama neden C durumlarının üretici yazılımı tarafından yönetilmesini bekliyordunuz? Askıya alma durumları çalışma zamanı durumlarıdır ve tasarım gereği işletim sistemi tarafından yönetilirler. Keşfettiğin gibi, çalışma zamanının askıya alınmasını istemiyorsanız kullanmayın.
Andy Ross

6
Üzgünüz, ancak C durumları, EIST ve C1E BIOS'ta kapatılabilir. İşletim sisteminin BIOS ayarlarıma saygı duymasını bekliyorum. Bu durumdaki korkunç alet ve dokümantasyon göz önüne alındığında, bu özellikle doğrudur.
Michael Goldshteyn

4
Bios'unuz aracılığıyla kapatılmış olabilir. İlgili bir şartnamede bunu gerektiren hiçbir şey bilmiyorum. Üzgünüm, ancak BIOS'tan herhangi bir şey "beklemek" sizi defalarca ısırır. Firmware'in modern bir bilgisayarda yapabileceği en iyi şey hiçbir şeydir. Şaşırdığın için üzgünüm ama açıkçası bu kullanıcı hatası. Karşılaştırmanız askıya alma ve devam ettirme sürelerini ölçüyordu.
Andy Ross

19
BIOS özelliği seçiminin rollerinden biri, aygıtları etkinleştirmek / devre dışı bırakmaktır. Bazı durumlarda, bu seçimler işletim sisteminde zorunlu kılınır (örneğin, ana kart üzerindeki USB, eSATA ve NIC'ler). Diğerlerinde, işletim sisteminin isteklerinize saygı göstermesi beklenir (örneğin, EIST, C durumları, Hyperthreading, Execute Disable, AES-NI, Virtualization, vb.). BIOS, işletim sistemi nötr olan tek bir merkezi aygıt / özellik seçim yüzeyi sağlar. Bu, kullanıcının aynı donanım özelliklerini kullanan ana bilgisayara birden çok (belki de çok farklı) işletim sistemi yüklemesine olanak tanır. Bununla birlikte, bu cevap özneldir, bu yüzden katılmadığınızı kabul etmeniz gerekecektir.
Michael Goldshteyn

1
idle = mwait artık son 3.x çekirdeğinde desteklenmemektedir lkml.org/lkml/2013/2/10/21 herhangi bir alternatif tavsiye?
ck_

8

Belki de yavaşlayan şey, koşul değişkenleri için yapı taşı olan futex'tir. Bu biraz ışık tutacak:

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

sonra

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

ilginç sistem çağrıları için alınan mikrosaniyeleri zamana göre sıralanmış olarak gösterecektir.

2.6.32 çekirdek üzerinde

$ 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

Çekirdek 3.1.9'da

$ 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

Karşılaştıran bir "ping pong" performans testi içeren bu 5 yıllık hata raporunu buldum

  1. tek iş parçacıklı libpthread mutex
  2. libpthread koşul değişkeni
  3. düz eski Unix sinyalleri

Eklemek zorunda kaldım

#include <stdint.h>

bu komutla yaptığım derlemek için

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

2.6.32 çekirdek üzerinde

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

Çekirdek 3.1.9'da

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

Kernel 2.6.32 ile 3.1.9 arasındaki bağlam anahtarının gerçekten yavaşladığı sonucuna vardım, ancak çekirdek 3.2'de gözlemlediğiniz kadar olmasa da. Bunun henüz sorunuzu yanıtlamadığını fark ettim, araştırmaya devam edeceğim.

Düzenleme: İşlemin gerçek zamanlı önceliğini (her iki iş parçacığı) değiştirmenin 3.1.9'daki performansı 2.6.32'ye uyacak şekilde iyileştirdiğini buldum. Bununla birlikte, 2.6.32'ye aynı önceliğin atanması onu yavaşlatır ... git şekil - Ben daha çok inceleyeceğim.

İşte şimdi sonuçlarım:

2.6.32 çekirdek üzerinde

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

Çekirdek 3.1.9'da

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

Fedora ve CentOS üzerinde çalıştırdım, Ubuntu'm yok. Sonuçlarımı göndereceğim.
amdn

Tamam, onu her iki ana bilgisayarda (yani ve farklı çekirdeklerde) çalıştırdım ve sonuçlar neredeyse hiç uyumsuzluk göstermiyor. Bu nedenle, bu test herhangi bir farklılığı vurgulamadı. Futex çağrı süresi, dördüncü ondalık basamakta farklılık gösterir - performansta önemsiz bir azalma. Err bekleyin, tam sayılar saniye cinsinden mi? Sonuçlarınızı
paylaştığınızı

Tamam, bu futex uygulamasını ortadan kaldırıyor - bağlam değiştirme teorinize geri döndük .... gerçekten yorumlara ait olduğu için bu cevabı silmekten çekinmeyin ... Sadece komutları biçimlendirme yeteneğini istedim.
amdn

Evet, süreler saniye cinsindendir ... bir saniyeden uzun süren futex çağrıları, durumu bekleyen iş parçacığı içindir.
amdn

Peki sonuçlardan bir şey çıkarırsanız ne olur?
Michael Goldshteyn

1

Ayrıca , c-durumlarından ayrı olan pstate sürücüsü nedeniyle daha yeni işlemlerde ve Linux çekirdeklerinde işlemcilerin tıklandığını görebilirsiniz . Buna ek olarak, bunu devre dışı bırakmak için aşağıdaki kernel parametresini kullanacaksınız:

intel_pstate=disable

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.