สรุป: การค้นหาและการใช้ประโยชน์จากความเท่าเทียม (ระดับคำสั่ง)ในโปรแกรมแบบเธรดเดียวนั้นทำในฮาร์ดแวร์ล้วนๆโดยซีพียูหลักที่ใช้งานอยู่ และมีเพียงคำแนะนำสองสามร้อยคำเท่านั้นที่ไม่ได้เรียงลำดับใหม่จำนวนมาก
โปรแกรมแบบเธรดเดี่ยวไม่ได้รับประโยชน์จากซีพียูแบบมัลติคอร์ยกเว้นว่าสิ่งอื่น ๆสามารถทำงานบนคอร์อื่นแทนการสละเวลาจากงานเธรดเดี่ยว
ระบบปฏิบัติการจัดระเบียบคำแนะนำของกระทู้ทั้งหมดในลักษณะที่พวกเขาไม่ได้รอซึ่งกันและกัน
ระบบปฏิบัติการไม่ได้ดูด้านในสตรีมคำแนะนำของเธรด เพียงกำหนดตารางเวลาเธรดให้กับแกน
ที่จริงแล้วแต่ละคอร์จะเรียกใช้ฟังก์ชั่นตัวกำหนดตารางเวลาของระบบปฏิบัติการเมื่อต้องการทราบว่าต้องทำอย่างไรต่อไป การกำหนดตารางเวลาเป็นอัลกอริทึมแบบกระจาย เพื่อให้เข้าใจถึงเครื่องมัลติคอร์ที่ดีขึ้นให้คิดถึงแต่ละคอร์ว่าใช้เคอร์เนลแยกกัน เช่นเดียวกับโปรแกรมแบบมัลติเธรดเคอร์เนลจะถูกเขียนเพื่อให้รหัสบนคอร์หนึ่งสามารถโต้ตอบกับโค้ดบนคอร์อื่นเพื่ออัปเดตโครงสร้างข้อมูลที่ใช้ร่วมกันได้อย่างปลอดภัย (เช่นรายการเธรดที่พร้อมใช้งาน)
อย่างไรก็ตามระบบปฏิบัติการที่มีส่วนเกี่ยวข้องในการช่วยให้กระบวนการแบบมัลติเธรดใช้ประโยชน์จากความเท่าเทียมด้ายระดับซึ่งจะต้องสัมผัสด้วยตนเองอย่างชัดเจนโดยการเขียนโปรแกรมแบบมัลติเธรด (หรือคอมไพเลอร์อัตโนมัติขนานกับOpenMPหรือบางสิ่งบางอย่าง)
จากนั้น Front-end ของ CPU จะจัดระเบียบคำแนะนำเหล่านั้นเพิ่มเติมโดยกระจายเธรดหนึ่งเธรดไปยังแต่ละคอร์และกระจายคำสั่งที่เป็นอิสระจากแต่ละเธรดในทุกรอบที่เปิด
ซีพียูคอร์ใช้คำสั่งเพียงสตรีมเดียวหากไม่ได้หยุด (หลับจนกว่าจะมีการขัดจังหวะครั้งถัดไปเช่นการขัดจังหวะตัวจับเวลา) บ่อยครั้งที่เป็นเธรด แต่ก็อาจเป็นตัวจัดการขัดจังหวะเคอร์เนลหรือรหัสเคอร์เนลเบ็ดเตล็ดหากเคอร์เนลตัดสินใจที่จะทำสิ่งอื่นที่ไม่ใช่แค่กลับไปยังเธรดก่อนหน้าหลังจากจัดการและขัดจังหวะหรือการเรียกระบบ
ด้วย HyperThreading หรือการออกแบบ SMT อื่น ๆ แกนประมวลผลทางกายภาพจะทำหน้าที่เหมือนแกน "ตรรกะ" หลายตัว ความแตกต่างเพียงอย่างเดียวจากมุมมองของระบบปฏิบัติการระหว่าง CPU แบบ quad-core-with-hyperthreading (4c8t) และเครื่อง 8-core ธรรมดา (8c8t) คือระบบปฏิบัติการ HT-aware จะพยายามกำหนดเวลาเธรดเพื่อแยกคอร์ทางกายภาพดังนั้น ไม่แข่งขันกัน ระบบปฏิบัติการที่ไม่ทราบเกี่ยวกับการทำไฮเปอร์เธรดจะเห็น 8 คอร์ (ยกเว้นว่าคุณปิดใช้งาน HT ในไบออสจากนั้นจะตรวจจับ 4 เท่านั้น)
คำว่า " front-end" หมายถึงส่วนหนึ่งของ CPU หลักที่เรียกรหัสเครื่องถอดรหัสคำแนะนำและปัญหาพวกเขาเป็นส่วนหนึ่งออกจากคำสั่งของแกน แต่ละคอร์มีส่วนหน้าของตัวเองและเป็นส่วนหนึ่งของแกนโดยรวม คำแนะนำในการดึงข้อมูลเป็นสิ่งที่ CPU กำลังทำงานอยู่
ภายในส่วนที่ล้าสมัยของแกนคำสั่ง (หรือ uops) จะถูกส่งไปยังพอร์ตดำเนินการเมื่อตัวถูกดำเนินการอินพุตพร้อมใช้งานและมีพอร์ตดำเนินการฟรี นี้ไม่ได้ที่จะเกิดขึ้นในการสั่งซื้อโปรแกรมดังนั้นนี้เป็นวิธีที่ซีพียู OOO สามารถใช้ประโยชน์จากความเท่าเทียมการเรียนการสอนในระดับภายในหัวข้อเดียว
หากคุณแทนที่ "core" ด้วย "execution unit" ในความคิดของคุณคุณก็ใกล้จะถูกต้องแล้ว ใช่ซีพียูแจกจ่ายคำสั่ง / uops อิสระไปยังหน่วยดำเนินการแบบคู่ขนาน (แต่มีคำศัพท์ที่ผสมกันเนื่องจากคุณพูดว่า "front-end" เมื่อจริง ๆ แล้วมันเป็นตัวกำหนดเวลาการเรียนรู้ของ CPU หรือที่รู้จักว่าสถานีจองจองที่เลือกคำสั่งพร้อมที่จะดำเนินการ)
การดำเนินการที่ไม่เป็นไปตามคำสั่งสามารถค้นหา ILP ได้ในระดับท้องถิ่นมากเพียงสองสามร้อยคำสั่งไม่ใช่ระหว่างสองลูปอิสระ (เว้นแต่ว่าสั้น)
ตัวอย่างเช่น asm ที่เทียบเท่ากับสิ่งนี้
int i=0,j=0;
do {
i++;
j++;
} while(42);
จะทำงานเร็วเท่ากับลูปเดียวกันการเพิ่มเพียงหนึ่งตัวนับบน Intel Haswell i++
ขึ้นอยู่กับค่าก่อนหน้าของเท่านั้นi
ในขณะที่j++
ขึ้นอยู่กับค่าก่อนหน้าของj
ดังนั้นโซ่การพึ่งพาทั้งสองสามารถทำงานในแบบคู่ขนานโดยไม่ทำลายภาพลวงตาของทุกสิ่งที่ถูกดำเนินการตามลำดับของโปรแกรม
ใน x86 ลูปจะมีลักษณะดังนี้:
top_of_loop:
inc eax
inc edx
jmp .loop
Haswell มีพอร์ตการดำเนินการจำนวนเต็ม 4 พอร์ตและทั้งหมดมีหน่วยบวกดังนั้นมันจึงสามารถรักษาปริมาณงานได้มากถึง 4 inc
คำสั่งต่อนาฬิกาหากเป็นอิสระ (ด้วยความหน่วง = 1 ดังนั้นคุณต้องการเพียง 4 รีจิสเตอร์เพื่อให้ได้ปริมาณงานสูงสุดโดยเก็บ 4 inc
คำแนะนำในการบินตัดกันด้วย vector-FP MUL หรือ FMA: ความหน่วง = 5 ปริมาณ = 0.5 ต้องการตัวสะสมเวกเตอร์ 10 ตัวเพื่อให้ 10 FMA เพื่อให้ได้ปริมาณงานสูงสุดและเวกเตอร์แต่ละอันมีขนาด 256b โดยถือ 8 ความแม่นยำเดี่ยวลอย)
สาขาที่นำมาเป็นคอขวดด้วย: ลูปจะใช้เวลาอย่างน้อยหนึ่งตลอดทั้งนาฬิกาต่อการวนซ้ำเนื่องจากทรูพุตของสาขาที่ จำกัด จะถูก จำกัด ที่ 1 ต่อนาฬิกา ฉันสามารถเพิ่มคำแนะนำอีกหนึ่งอย่างในลูปโดยไม่ลดประสิทธิภาพเว้นแต่ว่ามันจะอ่าน / เขียนeax
หรือedx
ในกรณีนี้มันจะทำให้โซ่การพึ่งพานั้นยาวขึ้น การใส่คำสั่งเพิ่มเติมอีก 2 คำในลูป (หรือคำสั่งมัลติ - uop ที่ซับซ้อนหนึ่งอัน) จะสร้างคอขวดบน front-end เนื่องจากมันสามารถออก 4 uops ต่อนาฬิกาในคอร์ที่ล้าสมัยเท่านั้น (ดูคำถามและคำตอบ SO นี้สำหรับรายละเอียดบางอย่างเกี่ยวกับสิ่งที่เกิดขึ้นกับลูปที่ไม่ได้มีหลาย 4 uops: loop-buffer และ uop cache ทำให้สิ่งต่าง ๆ น่าสนใจ)
ในกรณีที่ซับซ้อนมากขึ้นการค้นหาความเท่าเทียมต้องดูที่หน้าต่างคำแนะนำที่กว้างขึ้น (เช่นอาจมีลำดับ 10 คำสั่งซึ่งทั้งหมดขึ้นอยู่กับแต่ละอื่น ๆ แล้วบางคนเป็นอิสระ)
ความจุบัฟเฟอร์สั่งซื้อใหม่เป็นหนึ่งในปัจจัยที่ จำกัด ขนาดหน้าต่างที่ไม่ได้ตามคำสั่ง บน Intel Haswell มี 192 uops (และคุณสามารถวัดได้ด้วยการทดลองพร้อมกับความสามารถในการเปลี่ยนชื่อการลงทะเบียน (ขนาดไฟล์ลงทะเบียน)) แกน CPU ที่ใช้พลังงานต่ำเช่น ARM มีขนาด ROB ที่เล็กกว่ามากหากพวกมันทำการประมวลผลที่ไม่เป็นระเบียบเลย
นอกจากนี้โปรดทราบว่าซีพียูจะต้องได้รับการวางท่อเช่นเดียวกับที่ไม่เรียบร้อย ดังนั้นจึงจำเป็นต้องดึงข้อมูลและถอดรหัสคำแนะนำล่วงหน้าก่อนที่จะถูกดำเนินการโดยควรมีปริมาณงานเพียงพอที่จะเติมบัฟเฟอร์หลังจากหายไปในรอบการดึงข้อมูลใด ๆ กิ่งไม้เป็นเรื่องยากเพราะเราไม่รู้ว่าจะดึงจากที่ไหนถ้าเราไม่รู้ว่าสาขาไหนไป นี่คือเหตุผลที่การคาดคะเนสาขาเป็นสิ่งสำคัญ (และทำไมซีพียูสมัยใหม่ใช้การประมวลผลแบบเก็งกำไร: พวกเขาเดาว่าจะให้สาขาใดไปและเริ่มดึงข้อมูล / ถอดรหัส / ดำเนินการกระแสคำสั่งนั้นเมื่อตรวจพบการวินิจฉัยผิดพวกเขาจะย้อนกลับสู่สถานะที่รู้จักกันดีและดำเนินการจากนั้น)
หากคุณต้องการอ่านเพิ่มเติมเกี่ยวกับ CPU internals มีลิงก์บางส่วนใน Stackoverflow x86 tag wikiรวมถึงคู่มือ microarch ของ Agner Fogและรายละเอียดการเขียนของ David Kanter พร้อมไดอะแกรมของ Intel และ AMD CPU จากการเขียนไมโครสถาปัตยกรรม Intel Haswellของเขานี่เป็นไดอะแกรมสุดท้ายของท่อทั้งหมดของแกน Haswell (ไม่ใช่ชิปทั้งหมด)
นี้เป็นบล็อกไดอะแกรมของเดี่ยว CPU หลัก ซีพียูแบบ quad-core มี 4 สิ่งเหล่านี้บนชิปแต่ละตัวมีแคช L1 / L2 ของตัวเอง (การแชร์แคช L3, ตัวควบคุมหน่วยความจำและการเชื่อมต่อ PCIe กับอุปกรณ์ระบบ)
ฉันรู้ว่านี่ซับซ้อนอย่างท่วมท้น บทความของ Kanter ยังแสดงบางส่วนของสิ่งนี้เพื่อพูดคุยเกี่ยวกับส่วนหน้าแยกจากหน่วยปฏิบัติงานหรือแคชตัวอย่างเช่น