ความเข้าใจผิดที่พบบ่อยเกี่ยวกับคอมไพเลอร์
(sbaziotis.com)ความเข้าใจผิดเกี่ยวกับการเพิ่มประสิทธิภาพของคอมไพเลอร์
- การเพิ่มประสิทธิภาพให้โปรแกรมที่ดีที่สุดเสมอหรือ?
- เป้าหมายของคอมไพเลอร์ไม่ใช่การสร้างโปรแกรมที่ดีที่สุดแบบสมบูรณ์ แต่คือการปรับปรุงโปรแกรมที่ถูกทำให้ง่ายขึ้นแล้ว
- การปรับให้ขนาดโค้ดเหมาะสมยังพอทำได้ แต่การปรับเวลาในการรันทำได้ยาก เนื่องจากวัดผลได้ยาก ขาดโครงสร้างย่อยที่เหมาะที่สุด และมีแบบจำลองฮาร์ดแวร์ที่ไม่แม่นยำ
- เวลาในการรันนั้นต่างจากขนาดโค้ดตรงที่วัดได้ไม่แม่นยำนัก ได้รับผลจากหลายปัจจัย และไม่มีโครงสร้างย่อยที่เหมาะที่สุด ตัวอย่างเช่น แม้จะปรับลูปสองอันแยกกันแล้ว แต่หากต้องการให้ทั้งโปรแกรมดีที่สุด อาจจำเป็นต้องรวมลูปทั้งสองเข้าด้วยกัน นอกจากนี้ยังปรับให้เหมาะได้ยากเพราะไม่มีแบบจำลองฮาร์ดแวร์เป้าหมายที่แม่นยำ ตัวอย่างเช่น goSLP สร้างโค้ด SLP vectorization ที่ถูกปรับแบบทั่วทั้งโปรแกรม แต่เพราะแบบจำลองฮาร์ดแวร์ไม่แม่นยำ โปรแกรมที่ได้จึงไม่เพียงไม่ดีที่สุด แต่อาจช้ากว่า LLVM ด้วย
ความเข้าใจผิดเกี่ยวกับการทำนายการแตกแขนง
- น้ำหนักของ branch ถูกใช้โดยตัวทำนาย branch ของ CPU หรือ?
- บนสถาปัตยกรรม x86 คอมไพเลอร์จะไม่สร้าง branch hint
- branch weight ถูกใช้สำหรับการจัดวางบล็อกโค้ดของคอมไพเลอร์ (เช่น ถ้ามีโอกาส branch สูง ก็จะวางบล็อกปลายทางไว้ถัดจากบล็อกปัจจุบันทันทีเพื่อเพิ่ม locality ของ instruction cache)
- ในสถาปัตยกรรม Intel Redwood Cove รุ่นใหม่ branch hint กลับมามีความเกี่ยวข้องอีกครั้ง แต่ในทางปฏิบัติก็ยังพบไม่บ่อยที่คอมไพเลอร์จะสร้าง hint เหล่านี้
ความเข้าใจผิดเกี่ยวกับระดับการเพิ่มประสิทธิภาพ
- -O3 สร้างโค้ดที่เร็วกว่า -O2 มากหรือ?
- สำหรับ Clang ความต่างด้านประสิทธิภาพระหว่าง -O2 กับ -O3 ไม่มากนัก ส่วน GCC มีความต่างอยู่บ้างเพราะ -O2 ของ GCC มีความเชิงรุกน้อยกว่า Clang
- -O3 แทบไม่คำนึงถึงขนาดโค้ด จึงอาจทำให้เกิดปัญหา instruction cache ได้
- ควรตรวจสอบด้วยการทำ benchmark
ความเข้าใจผิดเกี่ยวกับ Javascript interpreter และ JIT compiler
- เหตุผลที่ Javascript interpreter ทำ JIT compilation ตอนรันไทม์ เป็นเพราะไม่รู้ล่วงหน้าว่าเส้นทางไหนจะเป็น hot path ใช่หรือไม่?
- การรู้ว่าเส้นทางไหนร้อนอย่างเดียวไม่เพียงพอ แต่ยังต้องมีข้อมูลชนิดข้อมูลด้วย
- ข้อมูลชนิดข้อมูลจะรู้ได้เฉพาะตอนรันไทม์ ดังนั้น JIT compiler จึงคอมไพล์โค้ดในช่วงรันไทม์
ความเข้าใจผิดเกี่ยวกับความสัมพันธ์ระหว่างคอมไพเลอร์กับอินเทอร์พรีเตอร์
- ถ้ามีคอมไพเลอร์แล้ว ก็ไม่จำเป็นต้องมีอินเทอร์พรีเตอร์หรือ?
- ในกรณีของ C/C++ อินเทอร์พรีเตอร์อาจไม่ได้มีประโยชน์มากนัก แต่ในกรณีอย่าง WebAssembly อินเทอร์พรีเตอร์สามารถให้ข้อดีด้านความสะดวกในการพัฒนาและใช้งาน การดีบัก และความปลอดภัยได้
ความเข้าใจผิดเกี่ยวกับขั้นกลางของคอมไพเลอร์
- ขั้นกลาง (middle-end) เป็นอิสระจากเป้าหมาย/แพลตฟอร์มหรือ?
- ในกรณีของ LLVM ขั้นกลางไม่ได้เป็นอิสระจากเป้าหมาย/แพลตฟอร์มอย่างสมบูรณ์
ความเข้าใจผิดเกี่ยวกับการเพิ่มประสิทธิภาพด้าน data locality
- คอมไพเลอร์ปรับ data locality ให้เหมาะสมหรือ?
- คอมไพเลอร์ปรับ instruction cache locality ได้ แต่แทบไม่ได้ปรับ data locality
- การปรับ data locality ต้องอาศัยการเปลี่ยนแปลงโค้ดขนาดใหญ่ และคอมไพเลอร์ C/C++ ไม่สามารถทำการเปลี่ยนแปลงแบบนั้นได้
- หากต้องการปรับปรุง data locality ควรใช้เทคนิคอย่าง data-oriented design
ความเข้าใจผิดเกี่ยวกับความเร็วในการคอมไพล์
- -O0 ให้การคอมไพล์ที่รวดเร็วหรือ?
- -O0 สร้างโค้ดที่ดีบักได้และคาดเดาพฤติกรรมได้ แต่ไม่ได้รับประกันว่าจะคอมไพล์เร็วเสมอไป
- โดยทั่วไป -O0 จะเร็วกว่า -O2 แต่ก็อาจต่างกันไปตามขนาดโปรเจกต์และตัวคอมไพเลอร์
- หากต้องการคอมไพล์ให้เร็ว อาจพิจารณาข้าม standard compilation pipeline (เช่น TinyCC) หรือสร้าง LLVM IR โดยตรง
ความเข้าใจผิดเกี่ยวกับความเร็วในการคอมไพล์ของเทมเพลต
- เทมเพลตทำให้คอมไพล์ช้าหรือ?
- ที่ C++ template คอมไพล์ช้า เป็นเพราะโมเดลการคอมไพล์ของ C++
- ตัวเทมเพลตเองไม่ได้ทำให้ความเร็วในการคอมไพล์ลดลงอย่างมาก
- Phobos ซึ่งเป็น standard library ของ Dlang ใช้เทมเพลตจำนวนมาก แต่ยังคอมไพล์ได้รวดเร็ว
ความเข้าใจผิดเกี่ยวกับประโยชน์ของการคอมไพล์แยกไฟล์
- การคอมไพล์แยกไฟล์มีคุณค่าเสมอหรือ?
- การคอมไพล์แยกไฟล์อาจทำให้ใช้เวลาเชื่อมลิงก์นาน
- ในหลายโปรเจกต์ การทำ unity build (รวมโค้ดทั้งหมดไว้ในไฟล์เดียว) ให้ประสิทธิภาพที่ดีกว่า
- unity build มีข้อดีเช่น การเพิ่มประสิทธิภาพทั้งโปรแกรม ความเร็วในการคอมไพล์ที่ดีขึ้น และ log ข้อผิดพลาดที่ดีขึ้น
- มีไม่บ่อยนักที่การคอมไพล์แยกไฟล์จะดีกว่า unity build
ความเข้าใจผิดเกี่ยวกับ link-time optimization (LTO)
- ทำไม link-time optimization (LTO) จึงเกิดขึ้นตอนลิงก์?
- LTO ทำเพื่อการเพิ่มประสิทธิภาพทั้งโปรแกรม
- ในทางทฤษฎี การทำทั้งโปรแกรมให้เหมาะสมในขั้นกลางจะสมเหตุสมผลกว่า แต่เนื่องจากปัญหาเชิงปฏิบัติของระบบ build ของ C/C++ (เช่น ความยากในการค้นหา source file และวิเคราะห์ความสัมพันธ์ของการเรียกใช้) จึงไปทำในช่วงลิงก์แทน
- ตัวลิงเกอร์สามารถหา object file ทั้งหมดได้ ดังนั้นคอมไพเลอร์จึงใส่ตัวแทนภาษากลางอย่าง LLVM IR ลงใน object file เพื่อให้ลิงเกอร์เข้าถึงได้
ความเข้าใจผิดเกี่ยวกับการเพิ่มประสิทธิภาพด้วย inlining
- inlining มีประโยชน์หลักเพราะลบคำสั่งเรียกฟังก์ชันใช่หรือไม่?
- การลบคำสั่งเรียกฟังก์ชันเป็นข้อดีอย่างหนึ่ง แต่ข้อดีที่ใหญ่ที่สุดของ inlining คือการเปิดโอกาสให้ทำ optimization อื่น ๆ ได้
- inlining ทำให้เกิดการเพิ่มประสิทธิภาพข้ามฟังก์ชันได้
- เมื่อโค้ดของหลายฟังก์ชันถูกรวมเป็นฟังก์ชันเดียวผ่าน inlining ก็สามารถใช้เทคนิคการเพิ่มประสิทธิภาพภายในฟังก์ชันแบบเดิมได้
ความเข้าใจผิดเกี่ยวกับบทบาทของคีย์เวิร์ด inline
- คีย์เวิร์ด inline เกี่ยวข้องกับ optimization แบบ inlining หรือไม่?
- คีย์เวิร์ด inline ของ C++ เดิมทีใช้เป็น hint ให้ตัว optimizer แต่หลัง C++98 เป็นต้นมา มันมีความหมายเป็น “อนุญาตให้มีหลาย definition”
- ในกรณีของ LLVM ถ้ามีคีย์เวิร์ด inline จะเพิ่มแอตทริบิวต์ inlinehint และเพิ่มค่า threshold ของ inlining แต่ผลกระทบไม่ได้มากนัก
- หากต้องการให้ฟังก์ชันถูก inline เสมอ ควรใช้ตัวกำหนด always_inline
ความเข้าใจผิดเกี่ยวกับสื่อการเรียนรู้คอมไพเลอร์
- LLVM คือคอมไพเลอร์ที่ดีที่สุดสำหรับการเรียนรู้หรือ?
- LLVM มีด้านที่เหมาะสำหรับการศึกษาอยู่บ้าง แต่เพราะรองรับ use case ที่หลากหลาย จึงซับซ้อนและมีขนาดใหญ่มาก
- หากต้องการเรียนรู้การพัฒนาคอมไพเลอร์ ควรเริ่มจากคอมไพเลอร์ที่เล็กและง่ายกว่า เช่น Go compiler, LDC หรือ DMD
ความเข้าใจผิดเกี่ยวกับพฤติกรรมที่ไม่กำหนดไว้ (Undefined Behavior)
-
พฤติกรรมที่ไม่กำหนดไว้มีไว้เพื่อให้ทำ optimization ได้เท่านั้นหรือ?
- พฤติกรรมที่ไม่กำหนดไว้สามารถทำให้ optimization ถูกปิดใช้งานได้เช่นกัน
-
คอมไพเลอร์สามารถ “แค่” กำหนดพฤติกรรมที่ไม่กำหนดไว้ได้หรือ?
- คอมไพเลอร์สามารถกำหนดพฤติกรรมที่ไม่กำหนดไว้ได้ แต่สิ่งนี้อาจส่งผลต่อประสิทธิภาพ
- การที่คอมไพเลอร์กำหนดพฤติกรรมที่ไม่กำหนดไว้ทั้งหมดให้ตรงกับพฤติกรรมของแพลตฟอร์มนั้นเป็นสิ่งที่ดีในอุดมคติ แต่ในความเป็นจริงทำได้ไม่ง่าย
ความเข้าใจผิดเกี่ยวกับการสร้างโค้ดด้วย AI
- การสร้างโค้ดที่แม่นยำ 99% ถือว่าใช้ได้หรือ?
- ความแม่นยำ 99% สำหรับโค้ดที่สร้างโดยคอมไพเลอร์นั้นใช้งานจริงได้ยากมาก
- ความผิดพลาดเพียง 1% ของโค้ดทำให้การดีบักและการบำรุงรักษายากขึ้นมาก
- ในโปรเจกต์ขนาดใหญ่ ความผิดพลาด 1% อาจก่อให้เกิดปัญหาร้ายแรงมาก
- ปัจจุบัน LLM ยังช้ากว่าคอมไพเลอร์มาก จึงไม่เหมาะกับการสร้างโค้ดแบบออนไลน์
ยังไม่มีความคิดเห็น