1 คะแนน โดย GN⁺ 2025-02-10 | 1 ความคิดเห็น | แชร์ทาง WhatsApp

บทนำ

  • บทความนี้มีจุดประสงค์เพื่อแก้ความเข้าใจผิดเกี่ยวกับการแตกแขนงบน GPU
  • มีเว็บไซต์สอนบางแห่งที่เผยแพร่ข้อมูลผิด จึงต้องการแก้ไขให้ถูกต้อง

ปัญหา

  • ยกตัวอย่างโค้ดที่ใช้ตัวดำเนินการสามทางเพื่อทำงานแบบมีเงื่อนไขในโค้ด GPU
  • บางคนเสนอ "การปรับแต่ง" โดยแทนที่สิ่งนี้ด้วยการคำนวณเชิงเลขคณิต แต่เป็นความเข้าใจที่ผิด
  • ตัวดำเนินการสามทางทำการย้ายค่าแบบมีเงื่อนไข ซึ่งถูกนำไปใช้จริงด้วยการดำเนินการระดับบิตอย่างง่าย
  • การแตกแขนงจริงเกิดขึ้นในโค้ด GPU แต่ไม่ได้ใช้กับการย้ายรีจิสเตอร์ขนาดเล็ก

ปัญหาของการปรับแต่งที่ผิด

  • การปรับแต่งที่เสนอจริง ๆ แล้วทำงานช้ากว่าโค้ดเดิม
  • ฟังก์ชัน step() ถูกทำให้เป็นตัวดำเนินการสามทางอยู่แล้ว จึงเพิ่มการคูณและการบวกที่ไม่จำเป็น
  • ในโค้ดเดิม ค่าจะถูกย้ายโดยตรงตามเงื่อนไข

การวิเคราะห์แมชชีนโค้ด

  • จากแมชชีนโค้ดของคอมไพเลอร์ AMD และ Microsoft สามารถยืนยันได้ว่า GPU ไม่ได้ทำการแตกแขนง
  • ใช้การเปรียบเทียบและบิตมาสก์เพื่อทำการย้ายค่าแบบมีเงื่อนไข

สรุป

  • ข้อเสนอการปรับแต่งที่ใช้ฟังก์ชัน step() เป็นข้อมูลที่ผิด และควรได้รับการแก้ไข

  • ข้อมูลที่ผิดนี้แพร่กระจายมานานกว่า 20 ปี และจำเป็นต้องแก้ไข

  • Inigo Quilez - ศึกษาคอมพิวเตอร์กราฟิกมาตั้งแต่ปี 1994

1 ความคิดเห็น

 
GN⁺ 2025-02-10
ความเห็นบน Hacker News
  • มั่นใจว่าข้อสรุปของบทความต้นฉบับนั้นถูกต้อง แต่ข้อโต้แย้งจะหนักแน่นกว่านี้หากมีการแสดงการสร้างโค้ดของทั้งสองเวอร์ชัน ไม่ใช่แค่เวอร์ชันที่ดีกว่า

    • แสดงโค้ดเครื่องที่ถูกสร้างขึ้นมาเพื่อชี้ให้เห็นว่าเวอร์ชัน "ที่ปรับให้เหมาะสม" นั้นทำงานช้ากว่าเวอร์ชันต้นฉบับอย่างมาก แต่ไม่ได้พิสูจน์ว่าเวอร์ชันที่แย่นั้นแย่กว่าจริง
  • อยากให้มีวิธีที่ดีในการรู้ว่าในกรณีไหน if จะบังคับให้เกิดการแตกแขนงจริง ๆ

    • เหตุผลที่ผู้คนใช้ mix/lerp ที่มีต้นทุนสูงกว่าก็เพราะแม้จะมีโอเวอร์เฮดเล็กน้อย แต่ก็กลัวว่าจะเกิดการแตกแขนง
    • การที่ v = x > y ? a : b; ทำงานได้จริงนั้นเป็นเรื่องดี แต่ก็น่ากังวลที่ if เป็นไวยากรณ์ที่บางครั้งทำให้แตกแขนง บางครั้งก็ไม่ทำ
  • บทความนี้ก็เกี่ยวข้องเช่นกัน: การแก้คำแนะนำที่ผิดเกี่ยวกับการเขียนการแตกแขนงบน GPU

    • ในอดีต การปรับให้เหมาะสมด้วยการหลีกเลี่ยงการแตกแขนงนั้นได้ผล แต่ตอนนี้ไม่ควรทำแบบนั้นแล้ว
    • เนื่องจากโปรเซสเซอร์และคอมไพเลอร์เปลี่ยนไปเรื่อย ๆ การมีหลายรูปแบบแล้วเลือกอันที่เร็วที่สุดตอนรันไทม์จึงเป็นแนวทางที่ดี
  • สงสัยว่าทำไมคอมไพเลอร์ถึงไม่รับรู้ว่าเวอร์ชัน "ที่ปรับให้เหมาะสม" นั้นเทียบเท่ากัน

    • ควรจะเข้าใจ step() และสามารถปรับให้เหมาะสมแยกกันสำหรับกรณี step()=0.0 และ step()==1.0 ได้
  • เคยเจอปัญหานี้เหมือนกัน Claude/ChatGPT ก็เสนอสิ่งนี้เป็นการปรับให้เหมาะสม แต่กลับทำให้ประสิทธิภาพแย่ลง

    • ขอบคุณ Inigo
  • สงสัยว่าจะรู้ได้อย่างไรว่า OpenGL function ถูกจำลองการทำงานแทนที่จะเรียกใช้ความสามารถพื้นฐานของ GPU

  • เวลาที่เขียนโค้ด ต้องอาศัยประสบการณ์เพื่อให้มั่นใจว่าจะไม่มีการแตกแขนงแบบมีเงื่อนไขเกิดขึ้น

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