Go 1.27 ทดลองใช้ SIMD ชน NumPy ผลลัพธ์ชี้ขาดที่หน่วยความจำแคช
การทดสอบ Go 1.27 พาสตรีม SIMD ชน NumPy ด้วยดัชนีค้นหาเวกเตอร์ เผยผลลัพธ์สูสีนอกแคชแต่พ่ายแพ้เมื่อข้อมูลเข้า L3 แคช

ภาพประกอบจากคลังภาพสต็อก ไม่ใช่ภาพจากเหตุการณ์จริง
- Go 1.27 เพิ่มแพ็กเกจ SIMD ทดลองในไลบรารีมาตรฐาน
- ผลทดสอบความเร็วกับ NumPy เผยแพ้ชนะกันที่ขนาดแคชไม่ใช่ภาษา
- เมื่อข้อมูลอยู่นอกแคช Go และ NumPy ทำความเร็วได้สูสีกัน
- การควบคุมการทำงานของเธรดและฮาร์ดแวร์ส่งผลอย่างมากต่อผลลัพธ์
ภาษา Go เวอร์ชัน 1.27 ได้เปิดตัวแพ็กเกจ SIMD เข้ามาในไลบรารีมาตรฐานในลักษณะทดลอง โดยซ่อนไว้หลังแฟล็ก ซึ่งบทความส่วนใหญ่ที่ผ่านมามักกล่าวถึงแค่ตัว API เท่านั้น แต่น้อยครั้งที่จะมีใครทดสอบว่ามันช่วยเพิ่มประสิทธิภาพในสถานการณ์จริงเมื่อใด นักพัฒนาจึงได้ทดลองเปรียบเทียบประสิทธิภาพระหว่าง Go กับ NumPy ในงานเดียวกัน นั่นคือการสร้างดัชนีค้นหาลำโพง (speaker-search index) ซึ่งประกอบด้วยเวกเตอร์จำนวน 346,000 เวกเตอร์ ขนาด 192 มิติ และมีการคูณถึง 66 ล้านครั้งต่อหนึ่งคำค้นหา
ผลลัพธ์ที่ได้กลับไม่ใช่เรื่องของภาษา Go หรือ NumPy แต่อย่างใด เมื่อขนาดข้อมูลอยู่ที่ 253 เมกะไบต์ ซึ่งใหญ่เกินกว่าจะใส่ลงในแคชใดๆ ได้ โปรแกรมทั้งสองจึงต้องเสียเวลาส่วนใหญ่ไปกับการรอหน่วยความจำ เมื่อชนกำแพงนี้ คุณภาพของโค้ดจึงไม่ใช่ตัวตัดสินอีกต่อไป โค้ดเพียงยี่สิบสมองของแพ็กเกจใหม่เอี่ยมสามารถทำผลงานได้สูสีกับชุดคำสั่งแอสเซมบลีที่ได้รับการปรับแต่งมาอย่างยาวนานหลายปี

ภาพประกอบจากคลังภาพสต็อก ไม่ใช่ภาพจากเหตุการณ์จริง
อย่างไรก็ตาม เมื่อลดขนาดข้อมูลลงเหลือ 31 เมกะไบต์ ซึ่งข้อมูลสามารถเข้าไปอยู่ใน L3 แคชได้ คอขวดจะกลับมาอยู่ที่การคำนวณทางคณิตศาสตร์ และในจุดนี้เองที่การปรับแต่งมาอย่างยาวนานของ OpenBLAS แสดงผลลัพธ์ออกมาทันที ทำให้ NumPy ทำความเร็วได้เหนือกว่าอย่างเห็นได้ชัด สิ่งที่เป็นตัวตัดสินจึงไม่ใช่ภาษาที่ใช้เขียน แต่เป็นเรื่องของข้อมูลว่าสามารถเข้าไปอยู่ในแคชได้หรือไม่
ในเชิงสถาปัตยกรรมคอมพิวเตอร์ หน่วยความจำแคช (Cache Memory) ระดับ L3 ถือเป็นหัวใจสำคัญในการลดเวลาที่ซีพียูต้องรอข้อมูลจากแรมหลัก (RAM) การที่อัลกอริทึมจัดการข้อมูลให้อยู่ในแคชได้ (Cache Locality) จะช่วยก้าวกระโดดประสิทธิภาพการประมวลผลได้อย่างมหาศาล แม้ภาษาโปรแกรมจะมีระดับความเร็วต่างกัน แต่เมื่อข้อจำกัดย้ายไปอยู่ที่แบนด์วิดท์ของหน่วยความจำ (Memory Bandwidth) ความต่างของภาษาจะลดความสำคัญลงทันที
เบื้องหลังการทดสอบนี้ นักพัฒนาเกือบจะสรุปผลผิดพลาดไปถึงสองครั้ง ครั้งแรกเกิดจากการที่ OpenBLAS กระจายงานไปทุกคอร์โดยอัตโนมัติในขณะที่โปรแกรม Go รันบนเธรดเดียว จนกระทั่งมีการกำหนดตัวแปรสภาพแวดล้อม OMP_NUM_THREADS และ OPENBLAS_NUM_THREADS ให้เป็น 1 จึงทำให้เห็นภาพที่แท้จริง ครั้งที่สองเกิดจากการรันบนเครื่องที่มีกระบวนการอื่นทำงานอยู่เบื้องหลังถึงสิบกระบวนการจนซีพียูเต็ม 100% โดยไม่รู้ตัว ทำให้ต้องสร้างเครื่องมือทดสอบที่ล็อกคอร์ ปิดสลับรอบการทำงาน และตัดค่าเวลาที่ดีที่สุดออกเพื่อป้องกันความแปรปรวน
ที่มา: Dev.to
พบข้อมูลผิดพลาดในบทความนี้? แจ้งปัญหาบทความนี้
ความคิดเห็น
แสดงความคิดเห็น