ฉันอยากรู้สิ่งเดียวกันดังนั้นฉันจึงวัดมัน ในกล่องของฉัน (AMD FX (tm) -8150 โปรเซสเซอร์แปดคอร์ที่ 3.612361 GHz) การล็อคและปลดล็อก mutex ที่ปลดล็อคที่อยู่ในสายแคชของตัวเองและแคชไว้แล้วใช้เวลา 47 นาฬิกา (13 ns)
เนื่องจากการซิงโครไนซ์ระหว่างสองคอร์ (ฉันใช้ CPU # 0 และ # 1) ฉันสามารถโทรล็อค / ปลดล็อคคู่ได้เพียงครั้งเดียวทุกๆ 102 ns ในสองเธรดดังนั้นทุกๆ 51 ns ซึ่งหนึ่งสามารถสรุปได้ว่าใช้เวลาประมาณ 38 ns เพื่อกู้คืนหลังจากเธรดปลดล็อกก่อนที่เธรดถัดไปจะสามารถล็อกได้อีกครั้ง
โปรแกรมที่ฉันใช้ตรวจสอบสิ่งนี้สามารถพบได้ที่นี่:
https://github.com/CarloWood/ai-statefultask-testsuite/blob/b69b112e2e91d35b56a39f41809d3e3de2f9e4b8/src/mutex_test.cxx
โปรดทราบว่ามันมีค่าฮาร์ดโค้ดที่เฉพาะเจาะจงสำหรับกล่องของฉัน (ค่า Xrange, Yrange และ rdtsc) ดังนั้นคุณอาจต้องทดลองกับมันก่อนที่มันจะทำงานให้คุณ
กราฟที่สร้างในสถานะนั้นคือ:
สิ่งนี้แสดงผลลัพธ์ของการวัดประสิทธิภาพบนโค้ดต่อไปนี้:
uint64_t do_Ndec(int thread, int loop_count)
{
uint64_t start;
uint64_t end;
int __d0;
asm volatile ("rdtsc\n\tshl $32, %%rdx\n\tor %%rdx, %0" : "=a" (start) : : "%rdx");
mutex.lock();
mutex.unlock();
asm volatile ("rdtsc\n\tshl $32, %%rdx\n\tor %%rdx, %0" : "=a" (end) : : "%rdx");
asm volatile ("\n1:\n\tdecl %%ecx\n\tjnz 1b" : "=c" (__d0) : "c" (loop_count - thread) : "cc");
return end - start;
}
การเรียก rdtsc สองครั้งจะวัดจำนวนนาฬิกาที่ใช้ในการล็อคและปลดล็อค `mutex '(ด้วยโอเวอร์เฮดของ 39 นาฬิกาสำหรับการโทร rdtsc บนกล่องของฉัน) asm ที่สามคือการวนรอบหน่วงเวลา ขนาดของการวนรอบหน่วงเวลามีขนาดเล็กกว่า 1 สำหรับเธรด 1 มากกว่าสำหรับเธรด 0 ดังนั้นเธรด 1 จะเร็วกว่าเล็กน้อย
ฟังก์ชั่นดังกล่าวเรียกว่าในวง จำกัด ขนาด 100,000 แม้ว่าฟังก์ชั่นจะเร็วกว่าเล็กน้อยสำหรับเธรด 1 ทั้งสองลูปซิงโครไนซ์เนื่องจากการเรียกไปยัง mutex สิ่งนี้สามารถมองเห็นได้ในกราฟจากข้อเท็จจริงที่ว่าจำนวนนาฬิกาที่วัดได้สำหรับคู่ล็อค / ปลดล็อกนั้นมีขนาดใหญ่กว่าสำหรับเธรด 1 เล็กน้อยเพื่อพิจารณาความล่าช้าที่สั้นลงในลูปด้านล่าง
ในกราฟด้านบนจุดด้านล่างขวาคือการวัดที่มีความล่าช้า loop_count 150 จากนั้นติดตามจุดที่ด้านล่างไปทางซ้ายวน loop_count จะลดลงหนึ่งการวัดแต่ละครั้ง เมื่อกลายเป็น 77 ฟังก์ชันจะถูกเรียกทุก ๆ 102 ns ในทั้งสองเธรด หากภายหลัง loop_count ถูกลดลงยิ่งไปกว่านั้นมันเป็นไปไม่ได้ที่จะซิงโครไนซ์เธรดและ mutex เริ่มถูกล็อคจริงเกือบตลอดเวลาทำให้เกิดการเพิ่มจำนวนของนาฬิกาที่ใช้ในการล็อค / ปลดล็อก นอกจากนี้เวลาเฉลี่ยของการเรียกใช้ฟังก์ชันเพิ่มขึ้นเนื่องจากสิ่งนี้ ดังนั้นพล็อตจะชี้ขึ้นและไปทางขวาอีกครั้ง
จากนี้เราสามารถสรุปได้ว่าการล็อกและปลดล็อก mutex ทุก ๆ 50 ns ไม่ใช่ปัญหาในกล่องของฉัน
สรุปโดยสรุปของฉันคือคำตอบสำหรับคำถามของ OP คือการเพิ่ม mutexes ให้มากขึ้นจะดีขึ้นตราบใดที่ผลลัพธ์นั้นขัดแย้งกันน้อยลง
พยายามล็อก mutexes ให้สั้นที่สุด เหตุผลเดียวที่จะทำให้พวกเขา - พูด - นอกวงจะเป็นว่าถ้าวนรอบเร็วกว่าทุก ๆ 100 ns (หรือมากกว่าจำนวนกระทู้ที่ต้องการเรียกใช้วนรอบนั้นในเวลาเดียวกัน 50 ns) หรือเมื่อ 13 ns ครั้ง ขนาดลูปจะล่าช้ากว่าความล่าช้าที่คุณได้รับจากการช่วงชิง
แก้ไข: ฉันมีความรู้มากขึ้นเกี่ยวกับเรื่องนี้และเริ่มสงสัยข้อสรุปที่ฉันนำเสนอที่นี่ ก่อนอื่น CPU 0 และ 1 กลายเป็นไฮเปอร์เธรด แม้ว่าเอเอ็มดีอ้างว่ามี 8 คอร์จริง แต่ก็มีบางอย่างที่น่าจับตามองเพราะความล่าช้าระหว่างคอร์สองคอร์นั้นใหญ่กว่ามาก (เช่น 0 และ 1 ในรูปแบบคู่เช่นเดียวกับ 2 และ 3, 4 และ 5 และ 6 และ 7 ) ประการที่สอง std :: mutex ถูกนำไปใช้ในทางที่มันหมุนล็อคบิตก่อนที่จะทำการเรียกระบบเมื่อมันล้มเหลวในการรับล็อคทันทีบน mutex (ซึ่งไม่ต้องสงสัยเลยว่าช้ามาก) ดังนั้นสิ่งที่ฉันวัดได้ที่นี่คือซิตตัสที่สมบูรณ์แบบที่สุดและในการฝึกการล็อคและปลดล็อคอาจใช้เวลามากขึ้นต่อการล็อค / ปลดล็อก
บรรทัดด้านล่าง mutex ถูกนำไปใช้กับ atomics ในการซิงโครไนซ์อะตอมมิกระหว่างแกนบัสภายในจะต้องถูกล็อคซึ่งทำให้สายแคชตรงกันสำหรับรอบนาฬิกาหลายร้อยรอบ ในกรณีที่ไม่สามารถล็อคได้ต้องทำการเรียกระบบเพื่อให้เธรดเข้าสู่โหมดสลีป เห็นได้ชัดว่าช้ามาก (การเรียกของระบบอยู่ในลำดับ 10 mircoseconds) ปกติแล้วนั่นไม่ใช่ปัญหาจริงๆเพราะเธรดต้องนอนหลับอยู่ดี - แต่อาจเป็นปัญหากับการช่วงชิงที่สูงซึ่งเธรดไม่สามารถรับการล็อกได้ในขณะที่หมุนปกติและระบบจะเรียก แต่สามารถ ใช้เวลาล็อคไม่นานหลังจากนั้น ตัวอย่างเช่นถ้าหลายเธรดล็อกและปลดล็อก mutex ในลูปแบบคับและแต่ละล็อกจะล็อกเป็นเวลา 1 ไมโครวินาทีหรือมากกว่านั้น จากนั้นพวกเขาอาจจะชะลอตัวลงอย่างมากโดยความจริงที่ว่าพวกเขาจะนอนหลับตลอดเวลาและตื่นขึ้นมาอีกครั้ง นอกจากนี้เมื่อเธรดสลีปและเธรดอื่นต้องปลุกเธรดนั้นจะต้องทำการเรียกระบบและล่าช้าประมาณ 10 ไมโครวินาที ความล่าช้านี้เกิดขึ้นขณะปลดล็อก mutex เมื่อเธรดอื่นกำลังรอ mutex นั้นในเคอร์เนล (หลังจากการหมุนใช้เวลานานเกินไป)