บริบทจะเปลี่ยนช้าลงมากในเมล็ดลินุกซ์ใหม่


99

เรากำลังต้องการอัพเกรดระบบปฏิบัติการบนเซิร์ฟเวอร์ของเราจาก Ubuntu 10.04 LTS เป็น Ubuntu 12.04 LTS น่าเสียดายที่ดูเหมือนว่าเวลาในการตอบสนองในการรันเธรดที่รันได้นั้นเพิ่มขึ้นอย่างมีนัยสำคัญจาก 2.6 เคอร์เนลเป็น 3.2 เคอร์เนล ในความเป็นจริงตัวเลขเวลาแฝงที่เราได้รับนั้นยากที่จะเชื่อ

ให้ฉันเจาะจงมากขึ้นเกี่ยวกับการทดสอบ เรามีโปรแกรมที่ทำงานสองเธรด เธรดแรกได้รับเวลาปัจจุบัน (ในเห็บโดยใช้ RDTSC) แล้วส่งสัญญาณตัวแปรเงื่อนไขวินาทีละครั้ง เธรดที่สองรอตัวแปรเงื่อนไขและตื่นขึ้นมาเมื่อมีการส่งสัญญาณ จากนั้นจะได้รับเวลาปัจจุบัน (ในเห็บโดยใช้ RDTSC) ความแตกต่างระหว่างเวลาในเธรดที่สองและเวลาในเธรดแรกจะถูกคำนวณและแสดงบนคอนโซล หลังจากนี้เธรดที่สองจะรอตัวแปรเงื่อนไขอีกครั้ง เธรดแรกจะส่งสัญญาณอีกครั้งหลังจากผ่านไปประมาณหนึ่งวินาที

ดังนั้นโดยสรุปเราจะได้รับการสื่อสารแบบเธรดต่อเธรดผ่านการวัดเวลาแฝงตัวแปรเงื่อนไขหนึ่งวินาทีเป็นผล

ในเคอร์เนล 2.6.32 เวลาแฝงนี้อยู่ที่ใดที่หนึ่งตามลำดับของ 2.8-3.5 us ซึ่งสมเหตุสมผล ในเคอร์เนล 3.2.0 เวลาแฝงนี้เพิ่มขึ้นเป็นที่ใดที่หนึ่งตามลำดับ 40-100 เรา ฉันได้ยกเว้นความแตกต่างใด ๆ ในฮาร์ดแวร์ระหว่างโฮสต์ทั้งสอง พวกเขาทำงานบนฮาร์ดแวร์ที่เหมือนกัน (โปรเซสเซอร์ซ็อกเก็ตคู่ X5687 {Westmere-EP} ที่ทำงานที่ 3.6 GHz พร้อมกับไฮเปอร์เธรดความเร็วขั้นตอนและสถานะ C ทั้งหมดปิดอยู่) แอปทดสอบจะเปลี่ยนความสัมพันธ์ของเธรดเพื่อรันบนคอร์ทางกายภาพที่เป็นอิสระของซ็อกเก็ตเดียวกัน (กล่าวคือเธรดแรกทำงานบน Core 0 และเธรดที่สองทำงานบน Core 1) ดังนั้นจึงไม่มีการตีกลับของเธรดบน แกนหรือการตีกลับ / การสื่อสารระหว่างซ็อกเก็ต

ข้อแตกต่างเพียงอย่างเดียวระหว่างโฮสต์ทั้งสองคือโฮสต์หนึ่งใช้ Ubuntu 10.04 LTS พร้อมเคอร์เนล 2.6.32-28 (กล่องสวิตช์บริบทที่รวดเร็ว) และอีกอันกำลังเรียกใช้ Ubuntu 12.04 LTS ล่าสุดพร้อมเคอร์เนล 3.2.0-23 (บริบทช้า กล่องสวิตช์) การตั้งค่า BIOS และฮาร์ดแวร์ทั้งหมดเหมือนกัน

มีการเปลี่ยนแปลงใด ๆ ในเคอร์เนลที่อาจกล่าวถึงการทำงานช้าลงอย่างไร้สาระนี้ในระยะเวลาที่เธรดจะถูกกำหนดให้ทำงานหรือไม่?

อัปเดต: หากคุณต้องการเรียกใช้การทดสอบบนโฮสต์และบิวด์ลินุกซ์ของคุณฉันได้โพสต์รหัสไปยัง 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 : หลังจากค้นหาพารามิเตอร์เคอร์เนลเป็นจำนวนมากโพสต์เกี่ยวกับการเปลี่ยนแปลงเคอร์เนลและการวิจัยส่วนตัวฉันพบว่าปัญหาคืออะไรและได้โพสต์วิธีแก้ปัญหาเป็นคำตอบสำหรับคำถามนี้


1
เป็นเพียงการคาดเดา แต่การเปลี่ยนพารามิเตอร์จาก/proc/sys/kernel/*อาจใช้งานได้? หากคุณพบสิ่งที่ใช้งานได้ให้ใส่การกำหนดค่านั้นใน/etc/sysctl.confหรือไฟล์/etc/sysctl.d/เพื่อให้ยังคงอยู่ในระหว่างการรีบูต
Carlos Campderrós

1
ฉันเปรียบเทียบ / proc / sys / kernel ระหว่างสองโฮสต์ แต่ไม่เห็นความแตกต่างที่มีความหมายโดยเฉพาะอย่างยิ่งในรายการคอนฟิกูเรชันที่เกี่ยวข้องกับการจัดกำหนดการ
Michael Goldshteyn

ฉันจำข่าวลืออย่างคลุมเครือว่า RDTSC ไม่จำเป็นต้องซิงโครไนซ์ระหว่างคอร์อย่างถูกต้อง แต่ฉันคาดหวังว่าหากนี่เป็นปัญหาคุณจะเห็นการย้อนกลับของเวลา คุณเคยลองเล่นซอเพื่อเรียกใช้เธรดทั้งสองบนแกนเดียวกันและดูว่าเกิดอะไรขึ้น?
David Given

บนคอร์ Intel ใหม่นี้ RDTSC ทำงานได้อย่างไร้ที่ติบนคอร์โดยเฉพาะคอร์บน CPU เดียวกัน (เช่นซ็อกเก็ตเดียวกัน) ที่น่าสนใจคือถ้าทั้งสองเธรดทำงานบนแกนเดียวกันเวลาแฝงจะลดลงเหลือ 4-10 us ในเคอร์เนลที่ใหม่กว่าและประมาณ 3 เราในเคอร์เนลที่เก่ากว่า
Michael Goldshteyn

เป็นเพียงความคิดเห็นทั่วไป - การใช้ TSC ที่จะซิงโครไนซ์นั้นดีที่สุดแม้ว่าในกรณีเฉพาะของคุณเนื่องจากคุณใช้สองคอร์ในชิปจริงหนึ่งตัวจึงควรใช้งานได้
twalberg

คำตอบ:


95

วิธีแก้ปัญหาประสิทธิภาพการปลุกเธรดที่ไม่ดีในเคอร์เนลล่าสุดเกี่ยวข้องกับการเปลี่ยนไปใช้intel_idleไดรเวอร์ cpuidle จากacpi_idleไดรเวอร์ที่ใช้ในเคอร์เนลรุ่นเก่า น่าเศร้าที่intel_idleคนขับไม่สนใจการกำหนดค่า BIOS ของผู้ใช้สำหรับ C-รัฐและเต้นรำในการปรับแต่งของตัวเอง กล่าวอีกนัยหนึ่งแม้ว่าคุณจะปิดใช้งานสถานะ C ทั้งหมดใน BIOS ของพีซี (หรือเซิร์ฟเวอร์) ของพีซีของคุณอย่างสมบูรณ์ไดรเวอร์นี้จะยังคงบังคับให้เปิดใช้งานในช่วงเวลาที่ไม่มีการใช้งานสั้น ๆ ซึ่งมักเกิดขึ้นเกือบตลอดเวลาเว้นแต่จะมีการใช้เกณฑ์มาตรฐานสังเคราะห์ทั้งหมด (เช่นความเครียด ) กำลังวิ่ง. คุณสามารถตรวจสอบการเปลี่ยนสถานะ C พร้อมกับข้อมูลที่เป็นประโยชน์อื่น ๆ ที่เกี่ยวข้องกับความถี่ของโปรเซสเซอร์โดยใช้เครื่องมือ Google i7z ที่ยอดเยี่ยมบนฮาร์ดแวร์ที่เข้ากันได้ส่วนใหญ่

หากต้องการดูว่าไดรเวอร์ cpuidle ใดที่ใช้งานอยู่ในการตั้งค่าของคุณเพียงแค่ cat current_driverไฟล์ในcpuidleส่วน/sys/devices/system/cpuต่อไปนี้:

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

หากคุณต้องการให้ระบบปฏิบัติการ Linux ที่ทันสมัยของคุณมีเวลาแฝงในการสลับบริบทต่ำที่สุดให้เพิ่มพารามิเตอร์การบูตเคอร์เนลต่อไปนี้เพื่อปิดใช้งานคุณสมบัติการประหยัดพลังงานทั้งหมดเหล่านี้:

บน 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_cstateเป็นศูนย์จะทำให้ไดรเวอร์ cpuidle ของคุณเปลี่ยนกลับไปเป็นacpi_idle(อย่างน้อยตามเอกสารของตัวเลือก) หรือปิดใช้งานโดยสิ้นเชิง ในกล่องของฉันมันถูกปิดใช้งานอย่างสมบูรณ์ (เช่นการแสดงcurrent_driverไฟล์ในการ/sys/devices/system/cpu/cpuidleสร้างผลลัพธ์none) ในกรณีนี้ตัวเลือกการบูตที่สองprocessor.max_cstate=0ไม่จำเป็น อย่างไรก็ตามเอกสารระบุว่าการตั้งค่า max_cstate เป็นศูนย์สำหรับintel_idleไดรเวอร์ควรเปลี่ยน OS กลับเป็นacpi_idleไดรเวอร์ ดังนั้นฉันจึงใส่ตัวเลือกการบูตที่สองไว้ในกรณี

processor.max_cstateตัวเลือกชุดรัฐสูงสุด C สำหรับacpi_idleคนขับรถไปที่ศูนย์หวังว่าปิดการใช้งานเป็นอย่างดี ฉันไม่มีระบบที่ฉันสามารถทดสอบได้เนื่องจากintel_idle.max_cstate=0ทำให้ไดรเวอร์ซีพียูหลุดออกจากฮาร์ดแวร์ทั้งหมดที่มีให้ฉัน อย่างไรก็ตามหากการติดตั้งของคุณทำให้คุณเปลี่ยนกลับจากintel_idleเป็นacpi_idleเพียงตัวเลือกการบูตครั้งแรกโปรดแจ้งให้เราทราบว่าตัวเลือกที่สองprocessor.max_cstateทำในสิ่งที่บันทึกไว้ในความคิดเห็นเพื่อให้ฉันสามารถอัปเดตคำตอบนี้ได้

สุดท้ายสุดท้ายของพารามิเตอร์สามตัว idle=pollเป็นหมูไฟที่แท้จริง มันจะปิดใช้งาน C1 / C1E ซึ่งจะลบบิตของเวลาแฝงที่เหลืออยู่สุดท้ายออกไปด้วยค่าใช้จ่ายของการใช้พลังงานที่มากขึ้นดังนั้นให้ใช้อันนั้นเมื่อจำเป็นจริงๆเท่านั้น ส่วนใหญ่แล้วจะใช้งานมากเกินไปเนื่องจากเวลาแฝงของ C1 * ไม่ได้มีขนาดใหญ่ทั้งหมด การใช้แอปพลิเคชันทดสอบของฉันที่ทำงานบนฮาร์ดแวร์ที่ฉันอธิบายไว้ในคำถามเดิมเวลาในการตอบสนองเปลี่ยนจาก 9 เราเป็น 3 เรา นี่เป็นการลดลงอย่างมากสำหรับแอปพลิเคชั่นที่มีความไวต่อความหน่วงสูง (เช่นการซื้อขายทางการเงินการส่งข้อมูลทางไกล / การติดตามที่มีความแม่นยำสูงการได้มาซึ่งข้อมูลที่มีความถี่สูง ฯลฯ ... ) แต่อาจไม่คุ้มค่ากับการใช้พลังงานไฟฟ้าที่เกิดขึ้นสำหรับคนส่วนใหญ่ แอปเดสก์ท็อป วิธีเดียวที่จะรู้ได้อย่างแน่นอนคือการกำหนดรายละเอียดการปรับปรุงประสิทธิภาพเทียบกับแอปพลิเคชันของคุณ

อัปเดต:

หลังจากการทดสอบเพิ่มเติมด้วยidle=*พารามิเตอร์ต่างๆฉันได้ค้นพบว่าการตั้งค่าidleเป็นmwaitถ้าฮาร์ดแวร์ของคุณรองรับเป็นความคิดที่ดีกว่ามาก ดูเหมือนว่าการใช้MWAIT/MONITORคำแนะนำจะทำให้ CPU เข้าสู่ C1E ได้โดยไม่ต้องเพิ่มเวลาแฝงที่สังเกตเห็นได้ในเวลาปลุกเธรด ด้วยidle=mwaitคุณจะได้รับอุณหภูมิ CPU ที่เย็นลง (เมื่อเทียบกับ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การเรียนการสอนเป็นเกือบเทียบเท่ากับMWAITกับรัฐคำใบ้ 0. ปัญหาอยู่ในความจริงที่ว่าขัดจังหวะจะต้องได้รับจากรัฐ HLT ในขณะที่เขียนหน่วยความจำ (หรือขัดจังหวะ) สามารถนำมาใช้จะได้รับจากรัฐ MWAIT ขึ้นอยู่กับสิ่งที่เคอร์เนล Linux ใช้ในการวนรอบที่ไม่ได้ใช้งานสิ่งนี้สามารถทำให้ MWAIT มีประสิทธิภาพมากขึ้น ดังที่ฉันกล่าวว่าการทดสอบ / โปรไฟล์และดูว่าตรงกับความต้องการเวลาแฝงของคุณหรือไม่ ...

และ

idle=poll - ตัวเลือกประสิทธิภาพสูงสุดด้วยค่าใช้จ่ายของพลังงานและความร้อน


ขออภัยทำไมคุณถึงคาดหวังให้สถานะ C ถูกจัดการโดยเฟิร์มแวร์ สถานะการระงับคือสถานะรันไทม์และได้รับการจัดการโดยระบบปฏิบัติการโดยการออกแบบ ตามที่คุณค้นพบหากคุณไม่ต้องการให้รันไทม์หยุดชั่วคราวอย่าใช้มัน
Andy Ross

6
ขออภัยสามารถปิดสถานะ C, EIST และ C1E ใน BIOS ได้ ฉันคาดหวังว่าระบบปฏิบัติการจะเคารพการตั้งค่า BIOS ของฉัน นี่เป็นเรื่องจริงโดยเฉพาะอย่างยิ่งเนื่องจากเครื่องมือและเอกสารประกอบที่น่ากลัวในกรณีนี้
Michael Goldshteyn

4
ปิดผ่าน bios ของคุณอาจจะ ฉันไม่รู้อะไรเลยในข้อมูลจำเพาะที่เกี่ยวข้องซึ่งต้องการสิ่งนั้น ขออภัย "คาดหวังว่า" อะไรจาก BIOS เป็นไปกัดคุณซ้ำแล้วซ้ำอีก สิ่งที่ดีที่สุดที่เฟิร์มแวร์สามารถทำได้ในพีซียุคใหม่คืออะไร ฉันขอโทษที่ทำให้คุณประหลาดใจ แต่จริงๆแล้วนี่เป็นข้อผิดพลาดของผู้ใช้ เกณฑ์มาตรฐานของคุณกำลังวัดระยะเวลาพักและกลับมาทำงาน
Andy Ross

19
หนึ่งในบทบาทของการเลือกคุณสมบัติ BIOS คือการเปิด / ปิดอุปกรณ์ ในบางกรณีการเลือกเหล่านี้ถูกบังคับบน OS (เช่น USB บนเมนบอร์ด eSATA และ NICs) ในส่วนอื่น ๆ ระบบปฏิบัติการคาดว่าจะเคารพความปรารถนาของคุณ (เช่น EIST, C state, Hyperthreading, Execute Disable, AES-NI, Virtualization ฯลฯ ... ) BIOS จัดเตรียมพื้นผิวการเลือกอุปกรณ์ / คุณสมบัติส่วนกลางเดียวที่เป็นกลางของ OS สิ่งนี้ช่วยให้ผู้ใช้สามารถติดตั้งระบบปฏิบัติการหลายระบบ (อาจแตกต่างกันอย่างมาก) บนโฮสต์ซึ่งทั้งหมดใช้คุณสมบัติฮาร์ดแวร์เดียวกัน อย่างไรก็ตามคำตอบนี้เป็นแบบอัตนัยดังนั้นจะต้องเห็นด้วยกับไม่เห็นด้วย
Michael Goldshteyn

1
idle = mwait ไม่ได้รับการสนับสนุนใน 3.x kernel ล่าสุดlkml.org/lkml/2013/2/10/21มีคำแนะนำอื่นใดอีกหรือไม่
ck_

8

บางทีสิ่งที่ช้ากว่าคือ 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 mutex
  2. ตัวแปรเงื่อนไข libpthread
  3. สัญญาณ Unix เก่าธรรมดา

ฉันต้องเพิ่ม

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

ฉันสรุปได้ว่าระหว่างสวิตช์บริบทเคอร์เนล 2.6.32 และ 3.1.9 ได้ชะลอตัวลงอย่างแน่นอนแม้ว่าจะไม่มากเท่าที่คุณสังเกตในเคอร์เนล 3.2 ฉันรู้ว่าสิ่งนี้ยังไม่ตอบคำถามของคุณฉันจะขุดต่อไป

แก้ไข: ฉันพบว่าการเปลี่ยนลำดับความสำคัญแบบเรียลไทม์ของกระบวนการ (ทั้งสองเธรด) ช่วยเพิ่มประสิทธิภาพใน 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.
$ 

ฉันใช้งานบน Fedora และ CentOS ไม่มี Ubuntu ฉันจะโพสต์ผลของฉัน
amdn

ตกลงฉันรันมันบนโฮสต์ทั้งสอง (เช่นและเมล็ดที่แตกต่างกัน) และผลลัพธ์ก็แทบจะไม่มีความแตกต่างกันเลย ดังนั้นการทดสอบนี้ไม่ได้เน้นความแตกต่างใด ๆ เวลาในการโทรของ futex แตกต่างกันในทศนิยมตำแหน่งที่สี่ซึ่งเป็นการลดประสิทธิภาพลงเล็กน้อย เอ่อเดี๋ยวก่อนตัวเลขทั้งหมดเป็นวินาทีหรือเปล่า ฉันเพิ่งเห็นคุณโพสต์ผลลัพธ์ของคุณและดูเหมือนกับของฉัน ...
Michael Goldshteyn

โอเคนั่นออกกฎการใช้งาน futex - เรากลับไปที่ทฤษฎีการสลับบริบทของคุณแล้ว .... อย่าลังเลที่จะลบคำตอบนี้เนื่องจากมันอยู่ในความคิดเห็นจริงๆ ... ฉันแค่ต้องการความสามารถในการจัดรูปแบบคำสั่ง
amdn

ใช่เวลาเป็นวินาที ... การเรียกใช้ futex ที่นานกว่าหนึ่งวินาทีนั้นเป็นไปสำหรับเธรดที่รอเงื่อนไข
amdn

แล้วถ้ามีอะไรที่คุณเก็บจากผลลัพธ์ล่ะ?
Michael Goldshteyn

1

คุณอาจเห็นโปรเซสเซอร์คลิกลงในกระบวนการล่าสุดและเคอร์เนล Linux เนื่องจากไดรเวอร์pstateซึ่งแยกจาก c-state นอกจากนี้หากต้องการปิดใช้งานคุณต้องใช้พารามิเตอร์เคอร์เนลต่อไปนี้:

intel_pstate=disable

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.