ระดับการเพิ่มประสิทธิภาพ GCC มีกี่ระดับ?


103

ระดับการเพิ่มประสิทธิภาพGCCมีกี่ระดับ?

ฉันลอง gcc -O1, gcc -O2, gcc -O3 และ gcc -O4

ถ้าฉันใช้จำนวนมากมันจะไม่ได้ผล

อย่างไรก็ตามฉันได้พยายามแล้ว

gcc -O100

และรวบรวม

ระดับการเพิ่มประสิทธิภาพมีกี่ระดับ?


13
@minitech คุณกำลังมองหา FM ไหน? แม้จะใช้man gccCygwin (12000 เส้นคี่) คุณสามารถค้นหา-Oและค้นหาทุกคำตอบด้านล่างได้
Jens

1
@minmaxavg หลังจากอ่านแหล่งที่มาฉันไม่เห็นด้วยกับคุณ: อะไรที่ใหญ่กว่า3ก็เหมือนกับ3(ตราบใดที่มันไม่intล้น) ดูคำตอบของฉัน
Ciro Santilli 郝海东冠状病六四事件

1
จริงๆแล้ว GCC มีแฟล็กอื่น ๆ อีกมากมายสำหรับปรับแต่งการปรับแต่งให้เหมาะสม -fomit-stack-pointer จะเปลี่ยนรหัสที่สร้างขึ้น
Basile Starynkevitch

คำตอบ:


142

เพื่อความอวดดีมีตัวเลือก -O ที่ถูกต้อง 8 แบบที่คุณสามารถมอบให้กับ gcc ได้แม้ว่าจะมีบางตัวที่มีความหมายเหมือนกันก็ตาม

เวอร์ชันดั้งเดิมของคำตอบนี้ระบุว่ามี 7 ตัวเลือก ตั้งแต่นั้นมา GCC ได้เพิ่ม-Ogยอดรวมเป็น 8

จากหน้าคน:

  • -O (เช่นเดียวกับ-O1)
  • -O0 (ไม่ต้องเพิ่มประสิทธิภาพเป็นค่าเริ่มต้นหากไม่ได้ระบุระดับการเพิ่มประสิทธิภาพ)
  • -O1 (ปรับให้เหมาะสมน้อยที่สุด)
  • -O2 (เพิ่มประสิทธิภาพมากขึ้น)
  • -O3 (เพิ่มประสิทธิภาพมากยิ่งขึ้น)
  • -Ofast (เพิ่มประสิทธิภาพอย่างจริงจังจนถึงขั้นทำลายการปฏิบัติตามมาตรฐาน)
  • -Og (ปรับประสบการณ์การดีบักให้เหมาะสม -Og เปิดใช้งานการเพิ่มประสิทธิภาพที่ไม่รบกวนการดีบักควรเป็นระดับการเพิ่มประสิทธิภาพที่เลือกไว้สำหรับวงจรการแก้ไขคอมไพล์ - ดีบักมาตรฐานเสนอระดับการเพิ่มประสิทธิภาพที่เหมาะสมในขณะที่ยังคงการรวบรวมที่รวดเร็วและประสบการณ์การดีบักที่ดี )
  • -Os(. เพิ่มประสิทธิภาพขนาด-Osช่วยให้ทุก-O2การเพิ่มประสิทธิภาพที่ไม่ปกติเพิ่มขนาดรหัสนอกจากนี้ยังดำเนินการเพิ่มประสิทธิภาพต่อการออกแบบมาเพื่อลดขนาดรหัส.. -Osปิดการใช้งานธงเพิ่มประสิทธิภาพดังต่อไปนี้-falign-functions -falign-jumps -falign-loops -falign-labels -freorder-blocks -freorder-blocks-and-partition -fprefetch-loop-arrays -ftree-vect-loop-version)

นอกจากนี้ยังอาจมีการเพิ่มประสิทธิภาพเฉพาะแพลตฟอร์มดังที่ @pauldoo บันทึกไว้ OS X มี -Oz


23
หากคุณกำลังพัฒนาบน Mac OS X จะมีการ-Ozตั้งค่าเพิ่มเติมซึ่ง "ปรับขนาดให้เหมาะสมยิ่งขึ้นกว่าเดิม-Os": developer.apple.com/mac/library/DOCUMENTATION/DeveloperTools/…
pauldoo

6
หมายเหตุ: O3 ไม่จำเป็นต้องดีกว่า O2 แม้ว่าชื่อจะแนะนำเช่นนั้นก็ตาม ลองทั้งสองอย่าง
johan d

1
หน้า @pauldoo 404 แทนที่ด้วย archive.org
noɥʇʎԀʎzɐɹƆ

นอกจากนี้ยังมี-Ogซึ่งเป็นตัวเลือกการเพิ่มประสิทธิภาพทั้งหมดที่ไม่รบกวนการดีบัก
einpoklum

50

ลองตีความซอร์สโค้ดของ GCC 5.1

เราจะพยายามทำความเข้าใจว่าเกิดอะไรขึ้น-O100เนื่องจากยังไม่ชัดเจนในหน้าคน

เราจะสรุปได้ว่า:

  • สิ่งที่อยู่เหนือ-O3ขึ้นไปINT_MAXก็เหมือนกับ-O3แต่สิ่งนั้นอาจเปลี่ยนแปลงได้ง่ายในอนาคตดังนั้นอย่าพึ่งพามัน
  • GCC 5.1 เรียกใช้พฤติกรรมที่ไม่ได้กำหนดหากคุณป้อนจำนวนเต็มมากกว่าINT_MAX.
  • อาร์กิวเมนต์มีได้เฉพาะตัวเลขหรือล้มเหลวอย่างสง่างาม โดยเฉพาะอย่างยิ่งสิ่งนี้ไม่รวมจำนวนเต็มลบเช่น-O-1

มุ่งเน้นไปที่โปรแกรมย่อย

ครั้งแรกจำได้ว่า GCC เป็นเพียง front-end สำหรับcpp, as, ,cc1 collect2คำ./XXX --helpพูดสั้น ๆว่าเท่านั้นcollect2และcc1รับ-Oดังนั้นเรามามุ่งเน้นไปที่พวกเขา

และ:

gcc -v -O100 main.c |& grep 100

ให้:

COLLECT_GCC_OPTIONS='-O100' '-v' '-mtune=generic' '-march=x86-64'
/usr/local/libexec/gcc/x86_64-unknown-linux-gnu/5.1.0/cc1 [[noise]] hello_world.c -O100 -o /tmp/ccetECB5.

จึง-Oถูกส่งต่อไปยังทั้งสองcc1และcollect2.

O เหมือนกันเลือก

common.optเป็นรูปแบบคำอธิบาย GCC ที่เฉพาะเจาะจงตัวเลือก CLI อธิบายไว้ในเอกสาร internalsและแปลไปที่ C โดยopth-gen.awkและoptc-gen.awk

ประกอบด้วยบรรทัดที่น่าสนใจดังต่อไปนี้:

O
Common JoinedOrMissing Optimization
-O<number>  Set optimization level to <number>

Os
Common Optimization
Optimize for space rather than speed

Ofast
Common Optimization
Optimize for speed disregarding exact standards compliance

Og
Common Optimization
Optimize for debugging experience rather than speed or size

ซึ่งระบุOตัวเลือกทั้งหมด หมายเหตุวิธีการ-O<n>อยู่ในครอบครัวที่แยกต่างหากจากที่อื่น ๆOs, และOfastOg

เมื่อเราสร้างสิ่งนี้จะสร้างoptions.hไฟล์ที่มี:

OPT_O = 139,                               /* -O */
OPT_Ofast = 140,                           /* -Ofast */
OPT_Og = 141,                              /* -Og */
OPT_Os = 142,                              /* -Os */

เป็นโบนัสในขณะที่เรากำลังโลภ\bO\nภายในcommon.optเราสังเกตเห็นบรรทัด:

-optimize
Common Alias(O)

ซึ่งสอนเราว่า--optimize(เส้นประสองชั้นเพราะมันขึ้นต้นด้วยเครื่องหมายขีด-optimizeบน.optไฟล์) เป็นนามแฝงที่ไม่มีเอกสาร-Oซึ่งสามารถใช้เป็น--optimize=3!

ที่ใช้ OPT_O

ตอนนี้เรา grep:

git grep -E '\bOPT_O\b'

ซึ่งชี้ให้เราเห็นสองไฟล์:

ก่อนอื่นเรามาติดตามกัน opts.c

opts.c: default_options_optimization

การopts.cใช้งานทั้งหมดเกิดขึ้นภายใน: default_options_optimization.

เรา grep backtrack เพื่อดูว่าใครเรียกใช้ฟังก์ชันนี้และเราเห็นว่าเส้นทางรหัสเท่านั้นคือ:

  • main.c:main
  • toplev.c:toplev::main
  • opts-global.c:decode_opts
  • opts.c:default_options_optimization

และเป็นจุดเริ่มต้นของmain.c cc1ดี!

ส่วนแรกของฟังก์ชันนี้:

  • ไม่integral_argumentซึ่งเรียกatoiในสตริงที่สอดคล้องกับOPT_Oการแยกการโต้แย้งการป้อนข้อมูล
  • เก็บค่าไว้ภายใน opts->x_optimizeโดยที่optsa struct gcc_opts.

โครงสร้าง gcc_opts

หลังจาก grepping ในไร้สาระเราสังเกตเห็นว่าเรื่องนี้structยังถูกสร้างขึ้นที่options.h:

struct gcc_options {
    int x_optimize;
    [...]
}

x_optimizeมาจากบรรทัดไหน:

Variable
int optimize

อยู่ในcommon.optและที่options.c:

struct gcc_options global_options;

ดังนั้นเราจึงเดาว่านี่คือสิ่งที่มีสถานะส่วนกลางของการกำหนดค่าทั้งหมดและ int x_optimizeเป็นค่าการปรับให้เหมาะสม

255 คือค่าสูงสุดภายใน

ในopts.c:integral_argument, atoiถูกนำไปใช้อาร์กิวเมนต์ป้อนข้อมูลเพื่อINT_MAXเป็นขอบเขตบน และถ้าคุณใส่อะไรที่ใหญ่กว่านั้นดูเหมือนว่า GCC จะเรียกใช้พฤติกรรมที่ไม่ได้กำหนด C อุ๊ย?

integral_argumentนอกจากนี้ยังห่อatoiและปฏิเสธข้อโต้แย้งอย่างเบาบางหากอักขระใด ๆ ไม่ใช่ตัวเลข ค่าลบจึงล้มเหลวอย่างสง่างาม

กลับไปที่opts.c:default_options_optimizationเราเห็นบรรทัด:

if ((unsigned int) opts->x_optimize > 255)
  opts->x_optimize = 255;

255เพื่อให้ระดับการเพิ่มประสิทธิภาพถูกตัดออกไป ในขณะที่อ่านopth-gen.awkฉันเจอ:

# All of the optimization switches gathered together so they can be saved and restored.
# This will allow attribute((cold)) to turn on space optimization.

และที่สร้างขึ้นoptions.h:

struct GTY(()) cl_optimization
{
  unsigned char x_optimize;

ซึ่งอธิบายว่าเหตุใดการตัดทอน: ต้องส่งต่อตัวเลือกไปcl_optimizationซึ่งใช้ไฟล์charเพื่อประหยัดเนื้อที่ ดังนั้น 255 จึงเป็นค่าสูงสุดภายในจริง

opts.c: might_default_options

กลับไปที่opts.c:default_options_optimizationเราเจอmaybe_default_optionsสิ่งที่น่าสนใจ เราเข้าไปในนั้นจากนั้นmaybe_default_optionเราจะไปถึงสวิตช์ขนาดใหญ่:

switch (default_opt->levels)
  {

  [...]

  case OPT_LEVELS_1_PLUS:
    enabled = (level >= 1);
    break;

  [...]

  case OPT_LEVELS_3_PLUS:
    enabled = (level >= 3);
    break;

ไม่มีการ>= 4ตรวจสอบใดๆ ซึ่งบ่งชี้ว่า3เป็นวิธีที่ใหญ่ที่สุด

จากนั้นเราค้นหาคำจำกัดความของOPT_LEVELS_3_PLUSin common-target.h:

enum opt_levels
{
  OPT_LEVELS_NONE, /* No levels (mark end of array).  */
  OPT_LEVELS_ALL, /* All levels (used by targets to disable options
                     enabled in target-independent code).  */
  OPT_LEVELS_0_ONLY, /* -O0 only.  */
  OPT_LEVELS_1_PLUS, /* -O1 and above, including -Os and -Og.  */
  OPT_LEVELS_1_PLUS_SPEED_ONLY, /* -O1 and above, but not -Os or -Og.  */
  OPT_LEVELS_1_PLUS_NOT_DEBUG, /* -O1 and above, but not -Og.  */
  OPT_LEVELS_2_PLUS, /* -O2 and above, including -Os.  */
  OPT_LEVELS_2_PLUS_SPEED_ONLY, /* -O2 and above, but not -Os or -Og.  */
  OPT_LEVELS_3_PLUS, /* -O3 and above.  */
  OPT_LEVELS_3_PLUS_AND_SIZE, /* -O3 and above and -Os.  */
  OPT_LEVELS_SIZE, /* -Os only.  */
  OPT_LEVELS_FAST /* -Ofast only.  */
};

ฮา! นี่เป็นตัวบ่งชี้ที่ชัดเจนว่ามีเพียง 3 ระดับเท่านั้น

opts.c: default_options_table

opt_levelsเป็นเรื่องที่น่าสนใจมากที่เรา grep OPT_LEVELS_3_PLUSและเจอopts.c:default_options_table:

static const struct default_options default_options_table[] = {
    /* -O1 optimizations.  */
    { OPT_LEVELS_1_PLUS, OPT_fdefer_pop, NULL, 1 },
    [...]

    /* -O3 optimizations.  */
    { OPT_LEVELS_3_PLUS, OPT_ftree_loop_distribute_patterns, NULL, 1 },
    [...]
}

ดังนั้นนี่คือที่ที่การ-Onแมปการเพิ่มประสิทธิภาพเฉพาะเจาะจงที่กล่าวถึงในเอกสารจะถูกเข้ารหัส ดี!

ตรวจสอบให้แน่ใจว่าไม่มีการใช้ x_optimize อีกต่อไป

การใช้งานหลักx_optimizeคือการตั้งค่าตัวเลือกการเพิ่มประสิทธิภาพเฉพาะอื่น ๆ เช่น-fdefer_popตามที่ระบุไว้ใน man page มีอีกมั้ย?

เราgrepและพบอีกสองสามอย่าง จำนวนน้อยและจากการตรวจสอบด้วยตนเองเราจะเห็นว่าทุกการใช้งานทำเพียง a มากที่สุดx_optimize >= 3เท่านั้นดังนั้นข้อสรุปของเราจึงมี

lto-wrapper.c

ตอนนี้เราไปสำหรับการเกิดขึ้นที่สองของซึ่งอยู่ในOPT_Olto-wrapper.c

LTO หมายถึงการเพิ่มประสิทธิภาพเวลาลิงก์ซึ่งตามชื่อที่แนะนำจะต้องมี-Oตัวเลือกและจะเชื่อมโยงกับcollec2(ซึ่งโดยพื้นฐานแล้วคือตัวเชื่อมโยง)

ในความเป็นจริงบรรทัดแรกlto-wrapper.cกล่าวว่า:

/* Wrapper to call lto.  Used by collect2 and the linker plugin.

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


38

เจ็ดระดับที่แตกต่างกัน:

  • -O0 (ค่าเริ่มต้น): ไม่มีการปรับให้เหมาะสม

  • -Oหรือ-O1(สิ่งเดียวกัน): เพิ่มประสิทธิภาพ แต่อย่าใช้เวลามากเกินไป

  • -O2: เพิ่มประสิทธิภาพในเชิงรุกมากขึ้น

  • -O3: ปรับให้เหมาะสมที่สุด

  • -Ofast: เทียบเท่ากับ-O3 -ffast-math. -ffast-mathทริกเกอร์การเพิ่มประสิทธิภาพจุดลอยตัวที่ไม่เป็นไปตามมาตรฐาน สิ่งนี้ช่วยให้คอมไพเลอร์สามารถแสร้งทำเป็นว่าตัวเลขทศนิยมนั้นมีความแม่นยำไม่สิ้นสุดและพีชคณิตนั้นเป็นไปตามกฎมาตรฐานของพีชคณิตจำนวนจริง นอกจากนี้ยังบอกคอมไพเลอร์ให้บอกฮาร์ดแวร์ให้ล้าง denormals เป็นศูนย์และถือว่า denormals เป็นศูนย์อย่างน้อยในโปรเซสเซอร์บางตัวเช่น x86 และ x86-64 Denormals ทำให้เกิดเส้นทางที่ช้าใน FPU จำนวนมากดังนั้นการปฏิบัติต่อพวกเขาเป็นศูนย์ (ซึ่งไม่ทำให้เกิดเส้นทางที่ช้า) อาจเป็นชัยชนะที่ยิ่งใหญ่

  • -Os: ปรับขนาดโค้ดให้เหมาะสม สิ่งนี้สามารถปรับปรุงความเร็วได้จริงในบางกรณีเนื่องจากพฤติกรรมของ I-cache ดีขึ้น

  • -Og: เพิ่มประสิทธิภาพ แต่ไม่รบกวนการดีบัก สิ่งนี้เปิดใช้งานประสิทธิภาพที่ไม่น่าอายสำหรับบิวด์ดีบักและมีจุดมุ่งหมายเพื่อแทนที่-O0สำหรับการดีบักบิวด์

นอกจากนี้ยังมีตัวเลือกอื่น ๆ ที่ไม่ได้เปิดใช้งานโดยตัวเลือกเหล่านี้และต้องเปิดใช้งานแยกกัน นอกจากนี้ยังสามารถใช้ตัวเลือกการเพิ่มประสิทธิภาพ แต่ปิดใช้งานแฟล็กเฉพาะที่เปิดใช้งานโดยการเพิ่มประสิทธิภาพนี้

สำหรับข้อมูลเพิ่มเติมโปรดดูเว็บไซต์ GCC


อันที่จริงแม้ว่าจะยุติธรรมกับคำตอบอื่น ๆ แต่ก็ไม่มี -Ofast หรือ -Og เกิดขึ้นเมื่อคำตอบเหล่านั้นถูกเขียนขึ้น
janneb

แล้วทำไม-O100คอมไพล์ล่ะ?
einpoklum

3
@einpoklum เพราะ GCC ถือว่าทุกอย่างที่อยู่เหนือ -O3 เท่ากับ -O3
Demi

น่าเสียดายที่คุณยังคงได้รับ <optimized out> มากมายในดีบักเกอร์ที่มี -Og การก้าวยังคงกระโดดไปรอบ ๆ แบบสุ่ม IMHO ไร้ประโยชน์
doug65536

3

สี่ (0-3): ดูจีซี 4.4.2 คู่มือ สิ่งที่สูงกว่าคือ -O3 แต่เมื่อถึงจุดหนึ่งคุณจะล้นขีด จำกัด ขนาดตัวแปร


ฉันได้สำรวจซอร์สโค้ดในคำตอบของฉันและเห็นด้วยกับคุณ GCC ดูเหมือนจะอาศัยatoiพฤติกรรมที่ไม่ได้กำหนดมากขึ้นตามด้วย255ขีด จำกัด ภายใน
Ciro Santilli 郝海东冠状病六四事件

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