การเพิ่มประสิทธิภาพทั่วไป
นี่คือการเพิ่มประสิทธิภาพที่ฉันโปรดปราน ฉันได้เพิ่มเวลาดำเนินการและลดขนาดโปรแกรมโดยใช้สิ่งเหล่านี้
ประกาศฟังก์ชันขนาดเล็กเป็นinline
หรือมาโคร
การเรียกใช้ฟังก์ชัน (หรือวิธีการ) แต่ละครั้งจะเกิดค่าใช้จ่ายเช่นการผลักตัวแปรไปยังสแต็ก ฟังก์ชันบางอย่างอาจมีค่าใช้จ่ายในการส่งคืนเช่นกัน ฟังก์ชันหรือวิธีการที่ไม่มีประสิทธิภาพมีข้อความในเนื้อหาน้อยกว่าค่าโสหุ้ยรวม สิ่งเหล่านี้เป็นตัวเลือกที่ดีสำหรับการฝังในไม่ว่าจะเป็น#define
มาโครหรือinline
ฟังก์ชัน (ใช่ฉันรู้ว่าinline
เป็นเพียงข้อเสนอแนะ แต่ในกรณีนี้ฉันถือว่าเป็นการเตือนผู้รวบรวม)
ลบรหัสที่ตายแล้วและซ้ำซ้อน
หากไม่ได้ใช้รหัสหรือไม่มีส่วนในผลลัพธ์ของโปรแกรมให้กำจัดออก
ลดความซับซ้อนของการออกแบบอัลกอริทึม
ฉันเคยลบรหัสแอสเซมบลีและเวลาดำเนินการจำนวนมากออกจากโปรแกรมโดยเขียนสมการพีชคณิตที่กำลังคำนวณจากนั้นทำให้นิพจน์พีชคณิตง่ายขึ้น การใช้นิพจน์พีชคณิตแบบง่ายใช้พื้นที่และเวลาน้อยกว่าฟังก์ชันเดิม
ลูป Unrolling
แต่ละลูปมีค่าใช้จ่ายในการตรวจสอบการเพิ่มและการยกเลิก ในการหาค่าประมาณของปัจจัยประสิทธิภาพให้นับจำนวนคำสั่งในค่าโสหุ้ย (ขั้นต่ำ 3: เพิ่มขึ้นตรวจสอบเริ่มต้นของลูปเริ่มต้น) แล้วหารด้วยจำนวนคำสั่งภายในลูป ตัวเลขยิ่งต่ำยิ่งดี
แก้ไข: ให้ตัวอย่างของการยกเลิกการวนซ้ำก่อนหน้านี้:
unsigned int sum = 0;
for (size_t i; i < BYTES_TO_CHECKSUM; ++i)
{
sum += *buffer++;
}
หลังจากยกเลิกการลงทะเบียน:
unsigned int sum = 0;
size_t i = 0;
**const size_t STATEMENTS_PER_LOOP = 8;**
for (i = 0; i < BYTES_TO_CHECKSUM; **i = i / STATEMENTS_PER_LOOP**)
{
sum += *buffer++; // 1
sum += *buffer++; // 2
sum += *buffer++; // 3
sum += *buffer++; // 4
sum += *buffer++; // 5
sum += *buffer++; // 6
sum += *buffer++; // 7
sum += *buffer++; // 8
}
// Handle the remainder:
for (; i < BYTES_TO_CHECKSUM; ++i)
{
sum += *buffer++;
}
ในข้อดีนี้จะได้รับประโยชน์รอง: มีการดำเนินการคำสั่งเพิ่มเติมก่อนที่โปรเซสเซอร์จะต้องโหลดแคชคำสั่งซ้ำ
ฉันได้ผลลัพธ์ที่น่าทึ่งเมื่อฉันคลายการวนซ้ำเป็น 32 คำสั่ง นี่เป็นหนึ่งในปัญหาคอขวดเนื่องจากโปรแกรมต้องคำนวณการตรวจสอบในไฟล์ 2GB การเพิ่มประสิทธิภาพนี้รวมกับการอ่านบล็อกที่ปรับปรุงประสิทธิภาพจาก 1 ชั่วโมงเป็น 5 นาที การคลายการวนซ้ำยังให้ประสิทธิภาพที่ยอดเยี่ยมในภาษาแอสเซมบลีของฉันmemcpy
เร็วกว่าคอมไพเลอร์memcpy
มาก - TM
การลดif
งบ
โปรเซสเซอร์เกลียดสาขาหรือกระโดดเนื่องจากบังคับให้โปรเซสเซอร์โหลดคิวคำสั่งซ้ำ
เลขคณิตบูลีน ( แก้ไข: ใช้รูปแบบโค้ดกับส่วนของโค้ดตัวอย่างที่เพิ่ม)
แปลงif
คำสั่งเป็นการกำหนดบูลีน โปรเซสเซอร์บางตัวสามารถดำเนินการคำสั่งตามเงื่อนไขโดยไม่ต้องแยกสาขา:
bool status = true;
status = status && /* first test */;
status = status && /* second test */;
การลัดวงจรของตัวดำเนินการตรรกะ AND (&&
) ป้องกันไม่ให้การดำเนินการของการทดสอบถ้าเป็นstatus
false
ตัวอย่าง:
struct Reader_Interface
{
virtual bool write(unsigned int value) = 0;
};
struct Rectangle
{
unsigned int origin_x;
unsigned int origin_y;
unsigned int height;
unsigned int width;
bool write(Reader_Interface * p_reader)
{
bool status = false;
if (p_reader)
{
status = p_reader->write(origin_x);
status = status && p_reader->write(origin_y);
status = status && p_reader->write(height);
status = status && p_reader->write(width);
}
return status;
};
การจัดสรรตัวแปรปัจจัยภายนอกลูป
หากตัวแปรถูกสร้างขึ้นทันทีภายในลูปให้ย้ายการสร้าง / การจัดสรรไปก่อนลูป ในกรณีส่วนใหญ่ไม่จำเป็นต้องจัดสรรตัวแปรระหว่างการวนซ้ำแต่ละครั้ง
นิพจน์ปัจจัยคงที่ภายนอกลูป
หากการคำนวณหรือค่าตัวแปรไม่ขึ้นอยู่กับดัชนีลูปให้ย้ายออกไปนอกลูป (ก่อนหน้า)
I / O ในบล็อก
อ่านและเขียนข้อมูลเป็นกลุ่มใหญ่ (บล็อก) ใหญ่กว่าดีกว่า. ตัวอย่างเช่นการอ่านหนึ่งอ็อกเท็ตในแต่ละครั้งจะมีประสิทธิภาพน้อยกว่าการอ่าน 1024 อ็อกเท็ตด้วยการอ่านครั้งเดียว
ตัวอย่าง:
static const char Menu_Text[] = "\n"
"1) Print\n"
"2) Insert new customer\n"
"3) Destroy\n"
"4) Launch Nasal Demons\n"
"Enter selection: ";
static const size_t Menu_Text_Length = sizeof(Menu_Text) - sizeof('\0');
//...
std::cout.write(Menu_Text, Menu_Text_Length);
ประสิทธิภาพของเทคนิคนี้สามารถแสดงให้เห็นได้ด้วยสายตา :-)
อย่าใช้printf
ครอบครัวสำหรับข้อมูลคงที่
ข้อมูลคงที่สามารถส่งออกโดยใช้การเขียนบล็อก การเขียนที่จัดรูปแบบจะเสียเวลาในการสแกนข้อความเพื่อจัดรูปแบบอักขระหรือประมวลผลคำสั่งในการจัดรูปแบบ ดูตัวอย่างโค้ดด้านบน
ฟอร์แมตเป็นหน่วยความจำแล้วเขียน
รูปแบบไปยังchar
อาร์เรย์ใช้หลายแล้วใช้sprintf
fwrite
นอกจากนี้ยังช่วยให้เค้าโครงข้อมูลแบ่งออกเป็น "ส่วนคงที่" และส่วนตัวแปร คิดว่าจดหมายเวียน
ประกาศข้อความคงที่ (ตัวอักษรสตริง) เป็น static const
เมื่อมีการประกาศตัวแปรโดยไม่มีstatic
คอมไพเลอร์บางตัวอาจจัดสรรพื้นที่บนสแตกและคัดลอกข้อมูลจาก ROM นี่เป็นการดำเนินการสองอย่างที่ไม่จำเป็น สิ่งนี้สามารถแก้ไขได้โดยใช้ไฟล์static
คำนำหน้า
สุดท้าย Code เหมือนคอมไพเลอร์
บางครั้งคอมไพเลอร์สามารถปรับแต่งข้อความขนาดเล็กหลาย ๆ ข้อความได้ดีกว่าเวอร์ชันที่ซับซ้อนเพียงเวอร์ชันเดียว นอกจากนี้การเขียนโค้ดเพื่อช่วยคอมไพเลอร์ปรับแต่งก็ช่วยได้เช่นกัน ถ้าฉันต้องการให้คอมไพเลอร์ใช้คำสั่งการถ่ายโอนบล็อกพิเศษฉันจะเขียนโค้ดที่ดูเหมือนว่าควรใช้คำสั่งพิเศษ