หลักการทำงานของ Simultaneous Multithreading
(blog.codingconfessions.com)- SMT คือเทคนิคที่ให้คอร์ CPU หนึ่งคอร์ออกคำสั่งจากหลายเธรดในรอบสัญญาณเดียวกัน เพื่อเติมทรัพยากรการประมวลผลที่ว่างอยู่ให้มากขึ้น เมื่อการทำ parallelism ระดับคำสั่งอย่างเดียวไม่เพียงพอ
- Hyper-Threading ของ Intel เป็นการใช้งานแบบสองเธรดต่อคอร์ โดยทำสำเนาสถานะสถาปัตยกรรม ทำให้ระบบปฏิบัติการมองเห็นคอร์กายภาพหนึ่งคอร์เหมือนเป็น logical processor สองตัว
- การใช้งานจริงไม่ได้เพิ่มทรัพยากรทุกอย่างเป็นสองเท่าอย่างง่าย ๆ แต่ทำสำเนา instruction pointer, ITLB, RAT แชร์ trace cache และ TLB และ แบ่งเท่า ๆ กัน สำหรับ uop queue, physical register และ reorder buffer
- ประโยชน์ด้านประสิทธิภาพขึ้นอยู่กับ workload หากสองเธรดแย่งใช้แคชกันอาจช้าลงได้ ส่วนเธรดที่ร่วมมือกันและส่งข้อมูลให้กันอาจเร็วขึ้นได้เพราะมี shared cache
- ทรัพยากรที่แชร์กันและ speculative execution อาจนำไปสู่ช่องโหว่ด้านความปลอดภัยได้ ดังนั้นในสภาพแวดล้อมที่อ่อนไหวด้านความปลอดภัย หรือ workload ที่ต้องการประสิทธิภาพสูงสุดและ latency ต่ำสุด การ ปิดใช้งาน SMT จึงเป็นทางเลือกที่ใช้งานได้จริง
เหตุผลที่ต้องมี SMT
- โปรเซสเซอร์สมัยใหม่มีรีจิสเตอร์หลายร้อยตัว, load/store unit หลายตัว และ arithmetic unit หลายตัว และใช้เทคนิค parallelism ระดับคำสั่ง เช่น pipelining, โครงสร้าง superscalar และการประมวลผลแบบ out-of-order เพื่อใช้ทรัพยากรเหล่านี้
- pipeline แบ่งการประมวลผลคำสั่งออกเป็นหลายขั้น และส่งคำสั่งไปยังขั้นถัดไปในแต่ละรอบสัญญาณ โดยใน pipeline ลึก 5 ขั้น หลังจากรอบสัญญาณที่ 5 เป็นต้นไป อาจมีคำสั่งกำลังดำเนินอยู่พร้อมกันได้สูงสุด 5 คำสั่ง
- โปรเซสเซอร์แบบ superscalar สามารถออกคำสั่งได้หลายคำสั่งในหนึ่งรอบสัญญาณ และโปรเซสเซอร์ Intel Core i7 รุ่นใหม่ ๆ สามารถออกคำสั่งได้ 4 คำสั่งต่อรอบสัญญาณ
- ในโปรแกรมจริงมักหาคำสั่งที่เป็นอิสระต่อกันมากพอได้ยาก จึงเกิดช่วงเวลาที่ทรัพยากรการประมวลผลว่างอยู่
- การสูญเปล่าแนวนอน เกิดขึ้นเมื่อภายในเธรดเดียวหาคำสั่งที่เป็นอิสระต่อกันได้ไม่พอที่จะเติม issue width ให้เต็ม
- การสูญเปล่าแนวตั้ง เกิดขึ้นเมื่อคำสั่งถัด ๆ ไปขึ้นกับคำสั่งที่กำลังรันอยู่ ทำให้ในหนึ่งรอบสัญญาณไม่สามารถออกคำสั่งใดได้เลย
- multithreading แบบดั้งเดิมออกคำสั่งจากเธรดเดียวต่อรอบสัญญาณ แล้วสลับไปยังเธรดอื่นในรอบถัดไป จึงลดการสูญเปล่าแนวตั้งได้ แต่ยังคงมีการสูญเปล่าแนวนอนและ overhead จากการสลับ context
- SMT ออกคำสั่งจากหลายเธรดในรอบสัญญาณเดียวกันโดยไม่ต้องสลับ context ทำให้เติมทรัพยากรการประมวลผลได้ในสัดส่วนที่สูงขึ้น
- Hyper-Threading ซึ่งเป็นการใช้งาน SMT ของ Intel ถูกจำกัดไว้ที่สองเธรดต่อคอร์
โครงสร้างพื้นฐานของ SMT แบบ Intel
- โปรเซสเซอร์ทั่วไปที่ไม่ใช่ SMT สามารถรันคำสั่งของเธรดเดียวได้ในแต่ละครั้ง
- แต่ละเธรดมี สถานะสถาปัตยกรรม ซึ่งรวมถึงค่ารีจิสเตอร์, program counter, control register ฯลฯ
- หากต้องการรันคำสั่งของสองเธรดพร้อมกัน ต้องสามารถแทนสถานะของสองเธรดได้พร้อมกัน ดังนั้นการใช้งาน SMT จึงทำสำเนา สถานะสถาปัตยกรรม ของโปรเซสเซอร์
- ด้วยการทำสำเนานี้ โปรเซสเซอร์กายภาพหนึ่งตัวจึงปรากฏต่อระบบปฏิบัติการเป็น logical processor สองตัว และระบบปฏิบัติการสามารถ schedule เธรดไปยังแต่ละตัวได้
- buffer และทรัพยากรประมวลผลระดับ microarchitecture จะถูกทำสำเนา แชร์ หรือแบ่งกัน ตามปัจจัยอย่างต้นทุน พลังงาน และพื้นที่ชิป
- ประเด็นที่พูดถึงส่วนใหญ่คือการใช้งาน SMT ของ Intel และอิงจาก white paper ของ Intel ปี 2002
สามส่วนของ CPU microarchitecture
- โปรเซสเซอร์ให้ ISA เป็นอินเทอร์เฟซสาธารณะแก่นักโปรแกรม โดย ISA รวมถึงชุดคำสั่งและรีจิสเตอร์ที่คำสั่งสามารถใช้ได้
- microarchitecture คือการใช้งานภายในที่อาจแตกต่างกันได้แม้ระหว่างโปรเซสเซอร์รุ่นที่รองรับ ISA เดียวกัน
- microarchitecture ของโปรเซสเซอร์สมัยใหม่แบ่งได้กว้าง ๆ เป็นสามส่วน
- frontend: รวม instruction control unit ที่ดึงและถอดรหัสคำสั่งของโปรแกรมที่จะรันถัดไป
- backend: รวมทรัพยากรประมวลผล เช่น physical register, arithmetic unit, load/store unit และจัดสรรทรัพยากรให้คำสั่งที่ถอดรหัสแล้วเพื่อ schedule การประมวลผล
- retirement unit: นำผลลัพธ์ของคำสั่งที่รันแล้วไปสะท้อนในสถานะสถาปัตยกรรมของโปรเซสเซอร์ในขั้นสุดท้าย
SMT ใน frontend
- instruction pointer ติดตามที่อยู่ของคำสั่งที่จะดึงถัดไป
- โปรเซสเซอร์ที่รองรับ SMT มี instruction pointer สองชุดเพื่อติดตามคำสั่งถัดไปของสองโปรแกรมอย่างอิสระ
- trace cache เก็บ trace ของคำสั่งที่เพิ่งถอดรหัสไว้ เพื่อลดต้นทุนการถอดรหัสและ latency ของการรันคำสั่งที่ถูกเรียกซ้ำ
- logical processor สองตัวแชร์กันแบบไดนามิกตามความจำเป็น
- หากเธรดหนึ่งรันคำสั่งมากกว่า ก็อาจครอบครอง entry ใน trace cache มากกว่า
- แต่ละ entry ถูก tag ด้วยข้อมูลเธรดเพื่อแยกคำสั่งของสองเธรด
- การเข้าถึง trace cache จะถูก arbitrate ระหว่าง logical processor สองตัวในทุกรอบสัญญาณ
- เมื่อเกิด trace cache miss frontend จะค้นหาคำสั่งที่ที่อยู่นั้นใน L1 instruction cache และหากเกิด L1 instruction cache miss ก็ต้องดึงจากแคชระดับถัดไปหรือหน่วยความจำหลัก
- L1 instruction cache แคชข้อมูลด้วย virtual address แต่การเข้าถึงหน่วยความจำหลักต้องใช้ physical address
- ITLB เก็บ virtual address ที่เพิ่งแปลงแล้ว เพื่อแปลง virtual address เป็น physical address
- ในโปรเซสเซอร์ที่รองรับ SMT แต่ละ logical processor มี ITLB cache ของตัวเอง
- logic สำหรับดึงคำสั่งจากหน่วยความจำหลักทำงานแบบ first come first served แต่จะจอง request slot อย่างน้อยหนึ่งช่องให้แต่ละ logical processor เพื่อให้ทั้งสองตัวเดินหน้าต่อได้
- คำสั่งที่มาจากหน่วยความจำหลักจะถูกเก็บไว้ใน streaming buffer ขนาดเล็กก่อนการถอดรหัส และในโปรเซสเซอร์ที่รองรับ SMT buffer นี้ก็ถูกทำสำเนาแยกตาม logical processor ด้วย
- หลังจากดึงมาแล้ว คำสั่งจะถูกถอดรหัสเป็น uop ที่เล็กและง่ายกว่า
- uop จะเข้าไปยัง uop queue ซึ่งทำหน้าที่เป็นขอบเขตระหว่าง frontend และ backend ของ CPU
- uop queue ถูกแชร์อย่างเท่าเทียมระหว่าง logical processor สองตัว และการแบ่งแบบคงที่นี้ทำให้ logical processor ทั้งสองเดินหน้าได้อย่างอิสระ
SMT ใน backend
- backend นำ micro-instruction จาก uop queue มารัน แต่ไม่ได้ยึดติดกับลำดับเดิมของโปรแกรมเท่านั้น และทำ out-of-order execution
- คำสั่งของโปรแกรมที่อยู่ใกล้กันมักขึ้นต่อกัน และหากมีงานที่ latency สูงอย่างการอ่านหน่วยความจำหลัก คำสั่งที่ขึ้นต่อกันก็ต้องรอด้วย
- out-of-order execution engine รันคำสั่งที่อยู่ด้านหลังให้เร็วกว่าลำดับเดิม เพื่อลดการสูญเปล่าของทรัพยากร
- allocator ระบุทรัพยากรที่ micro-instruction ต้องใช้และจัดสรรตามความพร้อมใช้งาน
- ในหนึ่งรอบสัญญาณจะจัดสรรทรัพยากรให้ micro-instruction ของ logical processor หนึ่งตัว และในรอบถัดไปจะสลับไปยัง logical processor อีกตัว
- หากใน uop queue มี micro-instruction ของ logical processor เพียงตัวเดียว หรือ logical processor ตัวหนึ่งใช้ทรัพยากรในส่วนของตัวเองหมดแล้ว allocator จะใช้ทุกรอบสัญญาณให้ logical processor อีกตัว
- ทรัพยากรหลักของ backend เป็นส่วนผสมของการทำสำเนา การแชร์ และการแบ่ง
- X86-64 ในระดับ ISA มี general-purpose integer register เพียง 16 ตัว แต่ในระดับ microarchitecture มี physical integer register หลายร้อยตัว และ floating-point register ในจำนวนใกล้เคียงกัน
- ในโปรเซสเซอร์ที่รองรับ SMT physical register จะถูกแบ่งเท่า ๆ กันให้ logical processor สองตัว
- load buffer และ store buffer ที่ใช้กับงานอ่าน/เขียนหน่วยความจำก็ถูกแบ่งเท่า ๆ กันให้ logical processor สองตัวเช่นกัน
Register renaming, scheduling และ commit
- เพื่อ out-of-order execution backend จะทำ register renaming
- เนื่องจากในระดับ ISA มี architectural register จำนวนน้อย คำสั่งของโปรแกรมจึงนำรีจิสเตอร์เดียวกันกลับมาใช้ซ้ำในคำสั่งอิสระหลายคำสั่ง
- out-of-order execution engine เปลี่ยน logical register เดิมให้เป็นหนึ่งใน physical register เพื่อให้รันขนานกับการรันก่อนหน้าได้
- mapping นี้ถูกเก็บไว้ใน register alias table หรือ RAT
- logical processor สองตัวมีชุด architectural register ของตัวเอง ดังนั้น RAT ก็มีสำเนาของตัวเองเช่นกัน
- คำสั่งที่ผ่านขั้นตอน register renaming และ allocator จะเข้าไปใน ready queue
- queue หนึ่งสำหรับคำสั่งอ่าน/เขียนหน่วยความจำ และอีก queue สำหรับคำสั่งทั่วไป
- ในคอร์ที่รองรับ SMT queue เหล่านี้จะถูกแบ่งเท่า ๆ กันให้ logical processor สองตัว
- โปรเซสเซอร์มี instruction scheduler หลายตัวทำงานขนานกัน
- ในแต่ละรอบสัญญาณ คำสั่งบางส่วนใน ready queue จะถูกส่งไปยัง scheduler
- queue จะส่งคำสั่งของ logical processor หนึ่งตัวในรอบสัญญาณหนึ่ง และสลับไปยัง logical processor อีกตัวในรอบถัดไป
- scheduler ไม่สนใจ logical processor และส่ง micro-instruction ที่ operand และ execution unit ที่จำเป็นพร้อมแล้วไปประมวลผลทันที
- เพื่อความเป็นธรรม จะมีข้อจำกัดจำนวน active entry ที่ logical processor หนึ่งตัวสามารถมีได้ใน scheduler queue
- ผลลัพธ์ของคำสั่งที่รันเสร็จจะเข้าไปยัง reorder buffer
- แม้คำสั่งจะถูกรันแบบ out-of-order แต่ต้อง commit เข้าสู่สถานะสถาปัตยกรรมของโปรเซสเซอร์ตามลำดับเดิมของโปรแกรม
- ในคอร์ที่รองรับ SMT reorder buffer จะถูกแบ่งเท่า ๆ กันให้ logical processor สองตัว
- retirement unit ติดตามว่าคำสั่งพร้อม commit เข้าสู่สถานะสถาปัตยกรรมแล้วหรือยัง และ retire ตามลำดับโปรแกรมที่ถูกต้อง
- ในคอร์ที่รองรับ SMT จะสลับประมวลผลระหว่าง micro-instruction ของแต่ละ logical processor
- หาก logical processor ตัวหนึ่งไม่มี micro-instruction ให้ retire ก็จะใช้ bandwidth ทั้งหมดให้ logical processor อีกตัว
- หลัง retire คำสั่งแล้ว อาจต้องเขียนไปยัง L1 cache และ logic สำหรับเลือกการเขียนนี้ก็สลับระหว่าง logical processor สองตัวในทุกรอบสัญญาณเช่นกัน
ผลของ memory subsystem และ cache
- TLB ที่แปลง virtual address ของคำขอข้อมูลเป็น physical address จะถูกแชร์แบบไดนามิกตามความจำเป็นโดย logical processor สองตัว
- entry ของ TLB ถูก tag ด้วย logical processor id เพื่อแยกรายการของ logical processor สองตัว
- CPU แต่ละคอร์มี private L1 cache ของตัวเอง
- L2 cache อาจเป็น private หรือแชร์ระหว่างคอร์ ขึ้นอยู่กับ microarchitecture
- หากมี L3 cache จะถูกแชร์ระหว่างคอร์
- cache ไม่รับรู้ถึงการมีอยู่ของ logical processor
- เนื่องจาก L1 cache และในบางกรณี L2 cache เป็น private ต่อคอร์ จึงเก็บข้อมูลของ logical processor สองตัวไว้ร่วมกันตามความจำเป็น
- หากสองเธรดใช้แคชอย่างหนัก จะเกิด data collision และ eviction ทำให้ประสิทธิภาพลดลงได้
- หากสองเธรดทำงานกับชุดข้อมูลเดียวกัน shared cache อาจเพิ่มประสิทธิภาพได้
เกณฑ์การเลือกด้านประสิทธิภาพและความปลอดภัย
- แม้จะรันเพียงเธรดเดียวบนคอร์ที่รองรับ SMT buffer และทรัพยากรประมวลผลจำนวนมากก็ยังคงอยู่ในสภาพที่แชร์หรือถูกแบ่งระหว่าง logical processor สองตัว ทำให้อาจลดศักยภาพประสิทธิภาพของเธรดเดี่ยวลง
- บน logical processor ที่ไม่ได้ใช้งาน ระบบปฏิบัติการจะรัน idle loop และ loop นี้ก็อาจใช้ทรัพยากรที่ logical processor อีกตัวสามารถใช้เพื่อให้ได้ประสิทธิภาพสูงสุด
- ในโปรเซสเซอร์ Intel Core เมื่อมีเพียงเธรดเดียวรันบนคอร์ ดูเหมือนว่าจะไม่มีการแชร์หรือแบ่งทรัพยากร และ Intel ถือว่าสิ่งนี้เป็นการปรับปรุงที่นำมาใช้ในเจเนอเรชันนั้น
- เมื่อสองเธรดรันบน logical processor สองตัวของคอร์ที่รองรับ SMT รูปแบบการเข้าถึงแคช จะเป็นตัวกำหนดประสิทธิภาพ
- หากสองเธรดแข่งขันกันใช้แคช ก็จะ evict ข้อมูลของกันและกัน ทำให้ประสิทธิภาพลดลง
- หากเป็นแบบร่วมมือกัน เช่น ข้อมูลที่เธรดหนึ่งผลิตถูกอีกเธรดหนึ่งบริโภค การแชร์ข้อมูลในแคชจะช่วยปรับปรุงประสิทธิภาพ
- หากสองเธรดไม่ได้แย่งใช้แคชกัน ก็สามารถเพิ่มอัตราการใช้ทรัพยากรของคอร์ CPU ได้โดยไม่ลดประสิทธิภาพของกันและกัน
- ผู้เชี่ยวชาญจำนวนมากมองว่า สำหรับโปรแกรมที่ต้องการประสิทธิภาพสูงสุดแบบสัมบูรณ์ ควรปิด SMT เพื่อให้เธรดเดียวใช้ทรัพยากรทั้งหมดได้
- SMT ยังมาพร้อม ปัญหาด้านความปลอดภัย ด้วย
- ทรัพยากรที่แชร์กันและ speculative execution อาจเปิดโอกาสให้ข้อมูลที่อ่อนไหวรั่วไหลไปยังผู้โจมตี
- เอกสารของ Oracle Linux และ Red Hat เชื่อมโยงไปยังตัวอย่างประเด็นความปลอดภัยที่เกี่ยวกับ SMT
- คำแนะนำทั่วไปคือให้ปิดใช้งาน SMT บนระบบ
- ยังมีข่าวลือว่า Intel อาจถอด Hyper-Threading ออกจากโปรเซสเซอร์รุ่นถัดไปอย่าง Arrow Lake
1 ความคิดเห็น
ความคิดเห็นจาก Hacker News
ถ้าเข้าใจ SMT แบบง่ายมาก ๆ สิ่งที่เห็นภาพคือ มันช่วยให้ ALU อันมีค่ายังคงถูกใช้งานต่อไปได้ในขณะที่เธรดหยุดรอเพราะ cache miss
LPDDR ในโน้ตบุ๊กรุ่นเก่า ๆ ช้ากว่านี้ และจำนวนคอร์ก็ยังน้อย จึงน่าจะมีคุณค่ามากกว่า แต่ทุกวันนี้บ่อยครั้งมีคอร์มากกว่างานที่สเกลได้ เลยรู้สึกถึงคุณค่าน้อยลง
บางครั้งก็หลีกเลี่ยง cache contention ด้วยการไม่จัดงานไปไว้บนคอร์เดียวกับเธรดสำคัญ เพราะรู้ว่าคอขวดอยู่ที่ประสิทธิภาพแบบเธรดเดียว
ก่อนหน้านี้เคยทดสอบคอร์ Efficient/Performance กับคอร์ SMT ในการเรนเดอร์แบบมัลติเธรดของ DirectX 12 และบน i7-12700K เวลาเรนเดอร์ฉากซับซ้อนแทบไม่ต่างกันระหว่างใช้เฉพาะ P-core, ใช้ P+SMT และใช้ P+E+SMT อย่างไรก็ตามบน Xbox Series X การทดสอบเดียวกันเร็วขึ้นเล็กน้อยเมื่อจัดงานลง SMT ด้วย
SMT จะเด่นเมื่อรอ I/O หรือทำงานจำนวนเต็มง่าย ๆ ถ้าทั้งสองเธรดสามารถทำให้ FPU เต็มได้ทั้งคู่ โดยทั่วไป SMT จะช้าลงเพราะต้องมีการแท็กเพิ่มเติมเพื่อระบุความเป็นเจ้าของข้อมูลภายใน CPU
ประเด็นหลักไม่ได้อยู่ที่ cache miss เท่าไร แต่อยู่ที่การปล่อยให้คอร์ไปทำอย่างอื่นระหว่างรอให้การเขียนเสร็จ
ดังนั้นโค้ดบางแบบจึงสเกลไม่ดี ส่วนบางแบบก็ได้ความเร็วเพิ่มขึ้นเกือบเป็นเชิงเส้น
บางทีการปล่อยให้โปรเซสเซอร์พวกนี้งีบสั้น ๆ อาจดีกว่าก็ได้
ความกว้างบัส จำนวนการส่งต่อวินาที การจัดคิว และพลังงานต่อการส่ง/จัดเก็บบิตดีขึ้น แต่ถ้าโปรแกรมต้องการข้อมูลที่ไม่มีอยู่ในแคชและการทำนายก็พลาด สุดท้าย RAM latency ก็ยังเป็นปัญหา
ว่ากันว่า CPU Arrow Lake รุ่นถัดไปของ Intel จะถอด Hyper-Threading หรือ SMT ออกไปทั้งหมด
ผลลัพธ์ด้านประสิทธิภาพขึ้นกับแอปพลิเคชันมากมาโดยตลอด ดังนั้นการทำให้เรียบง่ายลงอาจดีกว่า
มีการถกเถียงล่าสุดเรื่องมันมีความหมายเมื่อไรและที่ไหนอยู่ที่นี่: https://news.ycombinator.com/item?id=39097124
ยังไม่มั่นใจว่าเรามาถึงจุดนั้นแล้วจริง ๆ แต่คอร์ P/E ของ Intel เป็นทางเลือกที่มุ่งสู่เป้าหมายคล้ายกัน และค่อนข้างสมเหตุสมผลบนเดสก์ท็อปที่มีงานแบบเธรดเดียว/เธรดน้อยจำนวนมาก ดูเหมือนจะมีคุณค่าตรงที่ไม่ต้องจัดการความแตกต่างระหว่าง SMT กับ E-core ในการปรับแต่งแอปพลิเคชันด้วย
ในทางกลับกัน AMD วางแผนจะรักษาคอร์ที่โดยรวมเป็นเนื้อเดียวกันไว้ต่อไปสักระยะและใช้ SMT ต่อไป กลยุทธ์ไหนดีกว่าจริง ๆ คงตัดสินแบบง่าย ๆ ได้ยาก เพราะขึ้นกับแต่ละแอปพลิเคชันอย่างมาก
ดังนั้นจึงตัดสินใจจำกัดจำนวนเธรดไว้ที่
std::thread::hardware_concurrency() / 2 - 1หรือก็คือ จำนวนคอร์ - 1 กำลังจัดการกับstd::vectorอยู่แม้ตอนที่ทำงานได้ดี การปรับปรุงก็มีแค่ระดับเปอร์เซ็นต์สองหลัก และยังมีช่วงที่แย่ลงในหลายเจเนอเรชันต่อเนื่องด้วย เลยไม่เข้าใจว่าทำไมยังพยายามต่อไป
ทุกครั้งที่อ่านว่า ฟีเจอร์ระดับล่างของ CPU แบบนี้ทำงานอย่างไร ก็รู้สึกทึ่ง
สมัยมหาวิทยาลัยเคยเรียนวิชาประมาณ “พื้นฐานฮาร์ดแวร์คอมพิวเตอร์” แต่จริง ๆ น่าจะเรียกว่า “พื้นฐานการออกแบบ CPU” มากกว่า เราสร้าง adder, latch, flip-flop ฯลฯ จาก logic gate และพอจบเทอมก็สามารถออกแบบโปรเซสเซอร์พื้นฐานมาก ๆ ในระดับ gate ได้
แต่จินตนาการไม่ค่อยออกว่าจะคิดค้นสิ่งอย่าง register renaming หรือ out-of-order execution ขึ้นมาได้อย่างไร สิ่งเหล่านี้ก็ออกแบบในระดับ gate ด้วยหรือเปล่า? หรือมีภาษาและ “compiler” ที่ช่วยจัดวาง gate/ทรานซิสเตอร์ให้ใช้อยู่?
งานทั้งหมดทำด้วยภาษาอธิบายฮาร์ดแวร์ชื่อ Verilog ซึ่งช่วยให้เขียนโดย抽象องค์ประกอบหลาย ๆ อย่างได้
ความเข้าใจผิดใหญ่ ๆ อย่างหนึ่งที่ผู้ใช้มักมีเกี่ยวกับ SMT คือ โมเดลทางความคิด ที่จินตนาการว่ามี “คอร์จริง” หนึ่งคอร์กับคอร์อีกหนึ่งที่ด้อยกว่า
ในทุกแง่มุมที่สังเกตได้ ทั้งสองเธรดเท่าเทียมกัน
สุดท้ายถ้ามองเฉพาะประสิทธิภาพ ในเชิงแนวคิดมันใกล้เคียงกับการมีคอร์แบบเธรดเดียวสัก 1.25 คอร์ หรือมีตามสัดส่วนนั้นขึ้นกับแอปพลิเคชันมากกว่า
ผมมองว่าเหตุผลหลักที่นำ E-core มาใช้ไม่ใช่เรื่องการใช้พลังงานหรือประสิทธิภาพเท่าไร แต่เป็นเรื่องความร้อนและพื้นที่ die ดังนั้นผมจึงซื้อชิปที่ไม่มี E-core เสมอ และคิดว่าทางนั้นดีกว่า
สงสัยว่าควรค้นหาบทความเทคนิคละเอียด ๆ แบบนี้อย่างไร
ลองค้นด้วยหัวข้อนี้ตรง ๆ แล้ว แต่ก็เป็นไปตามคาด เพราะเป็นเทคโนโลยีสำหรับผู้ใช้ปลายทาง ผลการค้นหาจึงมีแต่ บทความสำหรับผู้ใช้ ที่แทบไม่ได้อธิบายอะไรให้ชัดเจน
แต่ URL ที่ให้มาส่วนใหญ่เป็น hallucination
ผมตรวจจากแท็บส่วนตัวใหม่ของ Firefox บนอุปกรณ์อีกเครื่อง แม้จะกันการติดตามหรือแคชได้ไม่หมด แต่คิดว่าเป็นค่าประมาณที่สมเหตุสมผลทีเดียว
คำอธิบายที่ว่า “บนคอร์ CPU ที่เปิด SMT บัฟเฟอร์และทรัพยากรสำหรับประมวลผลจำนวนมากต้องถูกแชร์ระหว่างโปรเซสเซอร์เชิงตรรกะสองตัว ดังนั้นแม้จะมีเธรดเดียวที่กำลังรันอยู่บนคอร์ SMT ทรัพยากรเหล่านั้นก็ไม่พร้อมให้เธรดนั้นใช้ และทำให้ประสิทธิภาพที่เป็นไปได้ลดลง” ตอนนี้ไม่เป็นความจริงแล้ว
ในโหมด SMT จะมีการแบ่ง ROB, แบนด์วิดท์ fetch/decode ฯลฯ แต่ผมเคยเห็นคอร์ SMT หลายแบบที่เมื่อไม่ได้อยู่ใน SMT ก็เปิดให้ใช้ทั้งหมดได้
เป้าหมายหลักของ SMT คือการเพิ่มอัตราการใช้งานของ เอนจินประมวลผลแบบ superscalar ให้สูงสุด
เลยสงสัยว่าแนวโน้มแบบนี้หมายความว่าผู้คนคิดว่า superscalar ไม่สำคัญเท่าเมื่อก่อนแล้วหรือไม่
โดยรวมเป็นบทสรุปที่ดี แต่บางจุดรู้สึกว่าปน ๆ กันอยู่บ้าง
อยากรู้ เคล็ดลับจากงานจริง ที่คนวงในใช้กันมากกว่านี้ แม้จะจำกัดเฉพาะส่วนที่ไม่เกี่ยวกับความปลอดภัยก็ตาม
สถาปัตยกรรม Bulldozer ของ AMD ที่น่าสงสารเคยถูกด่าหนักเพราะไม่มี SMT แต่ตอนนี้ทุกคนกลับกำลังถอยห่างจาก SMT
แน่นอนว่ารู้ว่า Bulldozer มีปัญหาอีกมากมายที่ไม่ใช่แค่การไม่มี SMT จริง ๆ แล้วมันใกล้เคียงกับโครงสร้างแบบตรงกันข้าม ที่หลายคอร์แชร์สิ่งอย่าง ALU เดียวกันมากกว่า ถึงอย่างนั้นถ้าดึงประสิทธิภาพเพิ่มได้อีกสักหน่อย ก็อาจถือว่าเห็นอะไรล่วงหน้าไปบ้างก็ได้
Power10 ปัจจุบันรองรับ SMT8 ที่มี 8 เธรดต่อคอร์ได้อย่างมีประสิทธิภาพ และเมื่อดูจากความพยายามที่พัฒนาการออกแบบซึ่งเน้น SMT มาหลายปี ก็ไม่น่าคิดว่าพวกเขาจะทิ้งมัน
สิ่งที่ควรรู้คือ หน่วยคำนวณ ของ GPU ก็มักใช้ SMT ในระดับประมาณ 7–10 เธรดต่อ CU เช่นกัน
วิธีนี้ช่วยซ่อน latency ได้
ในทุก clock cycle จะเลือกคำสั่งของเธรดที่ต้องการทรัพยากรซึ่งไม่ได้ยุ่งอยู่ จากหลายเธรดที่พร้อมใช้งาน แล้วเริ่มคำสั่งนั้น GPU ส่วนใหญ่ไม่ได้เริ่มหลายคำสั่งต่อหนึ่งคล็อก แม้หลายคำสั่งอาจดำเนินไปพร้อมกันได้หลังจากเริ่มแล้วก็ตาม ต่อให้เริ่มหลายคำสั่งต่อคล็อกได้ ก็อาจต้องเป็นคลาสคำสั่งแยกกันที่ใช้ทรัพยากรประมวลผลต่างกัน เช่น คำสั่ง scalar กับคำสั่ง vector
SMT หรือ simultaneous multithreading คือวิธีที่ในทุก clock cycle จะมีคำสั่งจำนวนมากจากทุกเธรดเริ่มพร้อมกัน และคำสั่งเหล่านั้นแข่งขันกันเพื่อใช้ execution unit หลายตัวของ CPU แบบ superscalar เพื่อทำให้ execution unit ให้ได้มากที่สุดไม่ว่างงาน สำหรับแต่ละหน่วยประมวลผลแบบขนาน เช่น integer adder ทั้ง 6 ตัวของ CPU สมัยใหม่ จะมีการตัดสินใจแยกกันว่าจะรันคำสั่งใดจากคิวที่บรรจุคำสั่งของเธรดพร้อมกันทั้งหมด