จะป้องกันไม่ให้ gcc เพิ่มประสิทธิภาพข้อความบางส่วนใน C ได้อย่างไร?


108

ในการทำให้หน้าสกปรก (การเปิดบิตสกปรกในรายการตารางหน้า) ฉันแตะไบต์แรกของหน้าดังนี้:

pageptr[0] = pageptr[0];

แต่ในทางปฏิบัติ gcc จะเพิกเฉยต่อคำสั่งโดยการกำจัดร้านค้าที่ตายแล้ว เพื่อป้องกันไม่ให้ gcc ปรับให้เหมาะสมฉันเขียนคำสั่งใหม่ดังนี้:

volatile int tmp;
tmp = pageptr[0];
pageptr[0] = tmp;

ดูเหมือนว่าเคล็ดลับจะใช้งานได้ แต่ค่อนข้างน่าเกลียด ฉันต้องการทราบว่ามีคำสั่งหรือไวยากรณ์ใดที่มีผลเหมือนกันหรือไม่? และฉันไม่ต้องการใช้-O0ธงเพราะมันจะนำมาซึ่งโทษประสิทธิภาพที่ดีเช่นกัน


8
@Mark -O0 จะหยุดการเพิ่มประสิทธิภาพ แต่ยังทำให้ประสิทธิภาพของโปรแกรมช้าลงด้วย ฉันแค่ต้องการป้องกันการเพิ่มประสิทธิภาพของข้อมูลโค้ดนี้: P
ZelluX

ฉันอยากจะเพิ่มว่าที่ผ่านมาแม้การใช้-O0ไม่ได้ป้องกัน "การเพิ่มประสิทธิภาพ" รหัสที่ตายแล้วเช่นเมื่อ GCC ตรวจพบว่ารหัสบางรหัสไม่มีผลใด ๆ ก็เพียงแค่ลบออก AFAIK นี่เป็นเวทีมาก่อน-O0... แต่นั่นเป็นเพียงประสบการณ์ของฉัน
smoothware

คำตอบ:


91

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

// Assuming pageptr is unsigned char * already...
unsigned char *pageptr = ...;
((unsigned char volatile *)pageptr)[0] = pageptr[0];

ตัวระบุvolatileประเภทสั่งให้คอมไพเลอร์เข้มงวดเกี่ยวกับที่เก็บหน่วยความจำและโหลด จุดประสงค์ประการหนึ่งvolatileคือเพื่อให้คอมไพเลอร์ทราบว่าการเข้าถึงหน่วยความจำมีผลข้างเคียงดังนั้นจึงต้องรักษาไว้ ในกรณีนี้การจัดเก็บมีผลข้างเคียงที่ทำให้เกิดข้อผิดพลาดของเพจและคุณต้องการให้คอมไพเลอร์รักษาข้อบกพร่องของเพจ

ด้วยวิธีนี้โค้ดโดยรอบยังสามารถปรับให้เหมาะสมได้และโค้ดของคุณสามารถพกพาไปยังคอมไพเลอร์อื่น ๆ ที่ไม่เข้าใจไวยากรณ์#pragmaหรือ__attribute__ไวยากรณ์ของ GCC


2
ฉันจะบอกว่านี่เป็นวิธีที่ดีกว่าในการปิดการเพิ่มประสิทธิภาพ คุณยังคงได้รับประโยชน์จากการเพิ่มประสิทธิภาพอื่น ๆ โดยใช้วิธีนี้
Ben S

3
วิธีการแก้ปัญหา Dietrich Epp จะทำงานได้ไม่อยู่ภายใต้การARM4.1 คอมไพเลอร์ แม้แต่โซลูชันของ ZelluX ก็ไม่ทำงาน วิธีทางเลือกที่จะทำให้งานนี้ ARM4.1 อยู่ใน ZelluX วิธีการแก้ปัญหาให้ ' ชั่วคราว ' a ตัวแปรผันผวนทั่วโลก
Preetham Nanjappa

1
ค่อนข้างแย่สำหรับคอมไพเลอร์ดังกล่าว
Alexey Frunze

1
@Shocker: GCC ยังคงสามารถปรับตัวแปรให้เหมาะสมได้โดยไม่ต้องเพิ่มประสิทธิภาพการเข้าถึงหน่วยความจำจริง ซึ่งเป็นประเด็นที่แตกต่างกัน
Dietrich Epp

2
@jww: การใช้งานนี้เหมาะกับสิ่งที่อธิบายไว้ในโพสต์บล็อกนั้น volatileหมายความว่าการเข้าถึงหน่วยความจำจะต้องเกิดขึ้นตามที่เขียนไว้ซึ่งตรงกับที่เราต้องการ กล่าวอีกนัยหนึ่งคือเราได้ไตร่ตรองอย่างรอบคอบแล้วและหมายความว่าเราคิดว่ามันหมายถึงอะไร
Dietrich Epp

185

คุณสามารถใช้ได้

#pragma GCC push_options
#pragma GCC optimize ("O0")

your code

#pragma GCC pop_options

เพื่อปิดใช้งานการเพิ่มประสิทธิภาพตั้งแต่ GCC 4.4

ดูเอกสาร GCC หากคุณต้องการรายละเอียดเพิ่มเติม


3
อย่างไรก็ตามเป็นที่น่าสังเกตว่าสิ่งนี้ใช้ได้กับฟังก์ชันทั้งหมดเท่านั้นไม่ใช่ในสถิติเฉพาะ: gcc.gnu.org/onlinedocs/gcc-4.8.2/gcc/… "แต่ละฟังก์ชันที่กำหนดหลังจากจุดนี้จะเหมือนกับว่าแอตทริบิวต์ (( เพิ่มประสิทธิภาพ ("STRING"))) สำหรับฟังก์ชันนั้น "
Ciro Santilli 郝海东冠状病六四事件法轮功

134

แทนที่จะใช้ pragmas ใหม่คุณยังสามารถใช้__attribute__((optimize("O0")))ตามความต้องการของคุณ สิ่งนี้มีข้อดีคือใช้กับฟังก์ชันเดียวและไม่ใช่ฟังก์ชันทั้งหมดที่กำหนดไว้ในไฟล์เดียวกัน

ตัวอย่างการใช้งาน:

void __attribute__((optimize("O0"))) foo(unsigned char data) {
    // unmodifiable compiler code
}

3
จะเกิดอะไรขึ้นถ้าฉันไม่ได้ใช้-Olevelตัวเลือก แต่ฉันใช้ตัวเลือกแต่ละตัวมันจะเปิดแยกต่างหาก? (ในกรณีของฉันฉันไม่สามารถตรวจสอบว่าเป็นตัวเลือกที่เพิ่มประสิทธิภาพของแต่ละบุคคลที่จะทำลายรหัส)
user2284570
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.