0Pricing
C++ Academy · บทเรียน

การทำนายการแยกแขนงและลูปร้อน

ช่วยให้ CPU ทำนายการแยกแขนง และเขียนลูปที่คอมไพเลอร์ปรับให้เหมาะสมได้

การทำนายการแยกแขนงและลูปร้อน เป็นบทเรียน C++ Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน C++ Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส C++ Academy มีบทเรียนทั้งหมด 4 บทเรียน

ตัวทำนายสาขา

CPU สมัยใหม่จะทำนายคำสั่งถัดไปก่อนที่คำสั่งก่อนหน้าจะทำงานเสร็จ เมื่อทำนายผิด ไปป์ไลน์จะหยุดชะงัก ทำให้เสียเวลา 10–20 รอบสัญญาณนาฬิกา

สาขาที่คาดเดาได้

สาขาที่เกือบจะไปในทิศทางเดียวเสมอ หรือเป็นไปตามรูปแบบที่ชัดเจน จะถูกทำนายได้ดี ส่วนสาขาแบบสุ่มส่งผลร้ายแรง

ข้อมูลที่เรียงลำดับช่วยได้

การวนดูข้อมูลที่เรียงลำดับพร้อมเงื่อนไขมักเร็วกว่าแบบไม่เรียงลำดับ เพราะตัวทำนายจะเรียนรู้รูปแบบได้

// Often much faster on sorted data
std::sort(v.begin(), v.end());
int sum = 0;
for (int x : v) {
    if (x > 128) sum += x;
}

โค้ดไร้สาขา

แทนที่สาขาด้วยการคำนวณทางเลขคณิตเมื่อทำได้ CPU จะประเมินทั้งสองเส้นทางแล้วเลือกผลลัพธ์โดยไม่ใช้สาขา

// Branchy
int max(int a, int b) { return (a > b) ? a : b; }

// Branchless (often equivalent in machine code)
int max(int a, int b) { return a + (b - a) * (b > a); }

std::max เป็นตัวเลือกที่ดีกว่า

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

คำใบ้ Likely และ Unlikely

C++20 เพิ่ม [[likely]] และ [[unlikely]] เพื่อให้คำใบ้แก่คอมไพเลอร์

if (error_condition) [[unlikely]] {
    handle_error();
}

การคลี่ลูป

การทำงานมากขึ้นต่อการวนหนึ่งรอบจะลดความถี่ของสาขา คอมไพเลอร์สมัยใหม่จะคลี่ลูปเอง ใช้ #pragma unroll เฉพาะเมื่อวัดผลแล้วพบว่าช่วยได้

หลีกเลี่ยงงานหลายรูปแบบในลูป

ลูปที่มีสองกรณีสลับกันแบบสุ่มจะทำให้การทำนายล้มเหลว เมื่อทำได้ ให้แยกเป็นสองลูป โดยแต่ละลูปรองรับหนึ่งกรณี

// Slow: random switching
for (auto& x : v) {
    if (x.type == A) process_A(x);
    else            process_B(x);
}

// Faster: partition first
std::partition(v.begin(), v.end(), [](auto& x) { return x.type == A; });
for (size_t i = 0; i < boundary; ++i) process_A(v[i]);
for (size_t i = boundary; i < v.size(); ++i) process_B(v[i]);

แทรกฟังก์ชันที่ทำงานหนัก

ค่าใช้จ่ายของการเรียกฟังก์ชันอาจสูงพอ ๆ กับตัวฟังก์ชันเองในลูปที่ทำงานหนัก คำใบ้ inline ช่วยได้ ส่วน __attribute__((always_inline)) (GCC/Clang) จะบังคับเข้มงวดยิ่งกว่า

อย่าเชื่อสัญชาตญาณ

คอมไพเลอร์และ CPU ฉลาดมาก ควรวัดผลก่อนปรับให้เหมาะสม โค้ดไร้สาขาที่ “ดูเหมือนชัดเจน” อาจช้ากว่าโค้ดที่มีสาขา หลังจากตัวทำนายเรียนรู้รูปแบบแล้ว

SIMD สำหรับลูปแบบกว้าง

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

การปรับให้เหมาะสมโดยอาศัยโปรไฟล์ (PGO)

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

ตรวจสอบความเข้าใจ

เหตุใดการเรียงข้อมูลก่อนลูปกรองข้อมูลจึงอาจทำให้การทำงาน เร็วขึ้น ในบางครั้ง

สรุป

สาขาที่ทำนายผิดทำให้เสียรอบสัญญาณนาฬิกา ทำให้สาขาคาดเดาได้ง่าย ข้อมูลที่เรียงลำดับช่วยได้ ใช้คำใบ้ likely/unlikely แบ่งงานเพื่อให้ลูปมีรูปแบบสม่ำเสมอ และเชื่อใจคอมไพเลอร์ให้ปรับโค้ด เว้นแต่การทำโปรไฟล์จะแสดงเป็นอย่างอื่น

คำถามที่พบบ่อย

บทเรียน “การทำนายการแยกแขนงและลูปร้อน” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “การทำนายการแยกแขนงและลูปร้อน” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส C++ Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส C++ Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การทำนายการแยกแขนงและลูปร้อน”

ช่วยให้ CPU ทำนายการแยกแขนง และเขียนลูปที่คอมไพเลอร์ปรับให้เหมาะสมได้ คุณปฏิบัติ C++ Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน C++ Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน C++ Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน

บทเรียน “การทำนายการแยกแขนงและลูปร้อน” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน C++ Academy นี้ได้ไหม

ได้ บทเรียน C++ Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. โครงสร้างข้อมูลที่เป็นมิตรต่อแคช
  2. การทำนายการแยกแขนงและลูปร้อน
  3. การทำโปรไฟล์ด้วย perf vtune และ Sanitizers
  4. การวัดประสิทธิภาพระดับย่อยด้วย Google Benchmark
← กลับไปที่ C++ Academy