Có bao nhiêu cấp độ tối ưu hóa GCC?


101

Có bao nhiêu cấp độ tối ưu hóa GCC ?

Tôi đã thử gcc -O1, gcc -O2, gcc -O3 và gcc -O4

Nếu tôi sử dụng một số lượng thực sự lớn, nó sẽ không hoạt động.

Tuy nhiên, tôi đã thử

gcc -O100

và nó được biên dịch.

Có bao nhiêu cấp độ tối ưu hóa?


13
@minitech Bạn đang xem FM nào? Ngay cả với man gccCygwin (12000 dòng lẻ), bạn có thể tìm kiếm -Ovà tìm thấy mọi thứ câu trả lời ở trạng thái bên dưới, và sau đó là một số.
Jens

1
@minmaxavg sau khi đọc nguồn, tôi không đồng ý với bạn: bất cứ điều gì lớn hơn 3là như nhau 3(miễn là nó không inttràn). Hãy xem câu trả lời của tôi .
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

1
Trên thực tế, GCC có nhiều cờ khác để tinh chỉnh tối ưu hóa. -fomit-stack-pointer sẽ thay đổi mã đã tạo.
Basile Starynkevitch

Câu trả lời:


141

Để trở nên phổ biến, có 8 tùy chọn -O hợp lệ khác nhau mà bạn có thể cung cấp cho gcc, mặc dù có một số ý nghĩa tương tự.

Phiên bản gốc của câu trả lời này cho biết có 7 lựa chọn. GCC kể từ đó đã được thêm vào -Ogđể nâng tổng số lên 8

Từ trang người đàn ông:

  • -O (Giống như -O1)
  • -O0 (không tối ưu hóa, mặc định nếu không có mức tối ưu hóa nào được chỉ định)
  • -O1 (tối ưu hóa ở mức tối thiểu)
  • -O2 (tối ưu hóa nhiều hơn)
  • -O3 (tối ưu hóa hơn nữa)
  • -Ofast (tối ưu hóa mạnh mẽ đến mức phá vỡ sự tuân thủ tiêu chuẩn)
  • -Og (Tối ưu hóa trải nghiệm gỡ lỗi. -Og cho phép tối ưu hóa không ảnh hưởng đến việc gỡ lỗi. Đây phải là mức tối ưu hóa được lựa chọn cho chu trình chỉnh sửa-biên dịch-gỡ lỗi tiêu chuẩn, cung cấp mức tối ưu hóa hợp lý trong khi duy trì biên dịch nhanh và trải nghiệm gỡ lỗi tốt. )
  • -Os(Tối ưu hóa cho kích thước. Cho -Osphép tất cả các -O2tối ưu hóa thường không làm tăng kích thước mã. Nó cũng thực hiện các tối ưu hóa hơn nữa được thiết kế để giảm kích thước mã. -OsTắt các cờ tối ưu hóa sau -falign-functions -falign-jumps -falign-loops -falign-labels -freorder-blocks -freorder-blocks-and-partition -fprefetch-loop-arrays -ftree-vect-loop-version:)

Cũng có thể có các tối ưu hóa nền tảng cụ thể, như @pauldoo lưu ý, OS X có -Oz


23
Nếu bạn đang phát triển trên Mac OS X, có một -Ozcài đặt bổ sung là "tối ưu hóa kích thước mạnh mẽ hơn -Os": developer.apple.com/mac/library/DOCUMENTATION/DeveloperTools/…
pauldoo

6
Lưu ý: O3 không nhất thiết tốt hơn O2 ngay cả khi cái tên gợi ý như vậy. Hãy thử cả hai.
johan d

1
@pauldoo trang 404, thay thế bằng archive.org
noɥʇʎԀʎzɐɹƆ

Ngoài ra còn có -Og, đó là tất cả các tùy chọn tối ưu mà không ảnh hưởng gỡ lỗi
einpoklum

47

Hãy giải thích mã nguồn của GCC 5.1 để xem điều gì xảy ra -O100vì nó không rõ ràng trên trang người dùng.

Chúng tôi sẽ kết luận rằng:

  • bất cứ thứ gì ở trên -O3cho đến INT_MAXđều giống như -O3, nhưng điều đó có thể dễ dàng thay đổi trong tương lai, vì vậy đừng dựa vào nó.
  • GCC 5.1 chạy hành vi không xác định nếu bạn nhập các số nguyên lớn hơn INT_MAX.
  • đối số chỉ có thể có các chữ số hoặc nó không thành công. Đặc biệt, điều này loại trừ các số nguyên âm như-O-1

Tập trung vào các chương trình con

Đầu tiên hãy nhớ rằng GCC chỉ là một front-end cho cpp, as, cc1, collect2. Nhanh ./XXX --helpnói rằng chỉ collect2cc1lấy -O, vì vậy hãy tập trung vào chúng.

Và:

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

cho:

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.

vì vậy -Ođã được chuyển tiếp cho cả hai cc1collect2.

O chung .opt

common.opt là một định dạng mô tả tùy chọn CLI GCC cụ thể được mô tả trong tài liệu hướng dẫn internals và dịch sang C bằng opth-gen.awkoptc-gen.awk .

Nó chứa những dòng thú vị sau:

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

trong đó chỉ định tất cả các Otùy chọn. Lưu ý như thế nào -O<n>là trong một họ riêng biệt với họ khác Os, OfastOg.

Khi chúng tôi xây dựng, điều này sẽ tạo ra một options.htệp chứa:

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

Như một phần thưởng, trong khi chúng tôi đang tìm kiếm \bO\nbên trong, common.optchúng tôi nhận thấy các dòng:

-optimize
Common Alias(O)

điều này dạy chúng ta rằng --optimize(dấu gạch ngang kép vì nó bắt đầu bằng dấu gạch ngang -optimizetrên .opttệp) là một bí danh không có giấy tờ -Ocó thể được sử dụng làm --optimize=3!

OPT_O được sử dụng ở đâu

Bây giờ chúng tôi grep:

git grep -E '\bOPT_O\b'

dẫn chúng ta đến hai tệp:

Đầu tiên chúng ta hãy theo dõi opts.c

opts.c: default_options_optimization

Tất cả các opts.ctập quán xảy ra bên trong: default_options_optimization.

Chúng tôi grep backtrack để xem ai gọi hàm này và chúng tôi thấy rằng đường dẫn mã duy nhất là:

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

main.clà điểm vào của cc1. Tốt!

Phần đầu tiên của chức năng này:

  • Liệu integral_argumenttrong đó kêu gọi atoitrên chuỗi tương ứng với OPT_Ophân tích lập luận đầu vào
  • lưu trữ giá trị bên trong opts->x_optimizeở đâu optsa struct gcc_opts.

struct gcc_opts

Sau khi nạp vô ích, chúng tôi nhận thấy rằng điều này structcũng được tạo ra tại options.h:

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

từ đâu x_optimizeđến từ các dòng:

Variable
int optimize

hiện tại common.opt, và rằng options.c:

struct gcc_options global_options;

vì vậy chúng tôi đoán rằng đây là thứ chứa toàn bộ trạng thái chung của cấu hình và int x_optimizelà giá trị tối ưu hóa.

255 là mức tối đa nội bộ

in opts.c:integral_argument, atoiđược áp dụng cho đối số đầu vào, INT_MAXgiới hạn trên cũng vậy. Và nếu bạn đặt bất cứ thứ gì lớn hơn, có vẻ như GCC chạy C hành vi không xác định. Ầm ĩ?

integral_argumentcũng kết thúc mỏng atoivà bác bỏ đối số nếu bất kỳ ký tự nào không phải là chữ số. Vì vậy, các giá trị âm không thành công một cách duyên dáng.

Quay lại opts.c:default_options_optimization, chúng ta thấy dòng:

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

để mức độ tối ưu hóa được cắt bớt 255. Trong khi đọc, opth-gen.awktôi đã bắt gặp:

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

và trên được tạo options.h:

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

điều này giải thích lý do tại sao cắt bớt: các tùy chọn cũng phải được chuyển tiếp tới cl_optimization, sử dụng a charđể tiết kiệm dung lượng. Vì vậy, 255 là một tối đa nội bộ thực sự.

opts.c: could_default_options

Quay lại opts.c:default_options_optimization, chúng ta bắt gặp maybe_default_optionscái nào nghe có vẻ thú vị. Chúng tôi nhập nó, và sau đó maybe_default_optionchúng tôi đạt được một công tắc lớn:

switch (default_opt->levels)
  {

  [...]

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

  [...]

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

Không có >= 4séc nào , cho thấy đó 3là số lớn nhất có thể.

Sau đó, chúng tôi tìm kiếm định nghĩa của OPT_LEVELS_3_PLUStrong 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.  */
};

Ha! Đây là một chỉ báo mạnh rằng chỉ có 3 cấp độ.

opts.c: default_options_table

opt_levelsrất thú vị, đến mức chúng tôi thu thập OPT_LEVELS_3_PLUSvà bắt gặp 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 },
    [...]
}

vì vậy đây là nơi mà -Onánh xạ tối ưu hóa cụ thể được đề cập trong tài liệu được mã hóa. Đẹp!

Đảm bảo rằng không còn cách sử dụng x_optimize nữa

Cách sử dụng chính của x_optimizelà để đặt các tùy chọn tối ưu hóa cụ thể khác -fdefer_popnhư được ghi lại trên trang chủ. Còn nữa không?

Chúng tôi grep, và tìm thấy một số khác. Số lượng nhỏ, và khi kiểm tra thủ công, chúng tôi thấy rằng mọi cách sử dụng chỉ thực hiện nhiều nhất là a x_optimize >= 3, vì vậy kết luận của chúng tôi là đúng.

lto-wrapper.c

Bây giờ chúng ta đi đến sự xuất hiện thứ hai của OPT_O, đã ở lto-wrapper.c.

LTO có nghĩa là Tối ưu hóa thời gian liên kết, như tên cho thấy sẽ cần một -Otùy chọn và sẽ được liên kết với collec2(về cơ bản là một trình liên kết).

Trên thực tế, dòng đầu tiên lto-wrapper.cnói:

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

Trong tệp này, các OPT_Olần xuất hiện dường như chỉ chuẩn hóa giá trị của Ođể chuyển nó về phía trước, vì vậy chúng ta sẽ ổn.


38

Bảy cấp độ khác biệt:

  • -O0 (mặc định): Không có tối ưu hóa.

  • -Ohoặc -O1(điều tương tự): Tối ưu hóa, nhưng không tốn quá nhiều thời gian.

  • -O2: Tối ưu hóa mạnh mẽ hơn

  • -O3: Tối ưu hóa mạnh mẽ nhất

  • -Ofast: Tương đương với -O3 -ffast-math. -ffast-mathkích hoạt tối ưu hóa dấu chấm động không tuân thủ tiêu chuẩn. Điều này cho phép trình biên dịch giả sử rằng các số dấu phẩy động là vô cùng chính xác và đại số trên chúng tuân theo các quy tắc tiêu chuẩn của đại số số thực. Nó cũng yêu cầu trình biên dịch ra lệnh cho phần cứng chuyển các giá trị bằng 0 và coi các giá trị là 0, ít nhất là trên một số bộ xử lý, bao gồm x86 và x86-64. Denormals kích hoạt một đường dẫn chậm trên nhiều FPU và do đó, coi chúng là 0 (không kích hoạt đường dẫn chậm) có thể là một chiến thắng hiệu suất lớn.

  • -Os: Tối ưu hóa cho kích thước mã. Điều này thực sự có thể cải thiện tốc độ trong một số trường hợp, do hành vi I-cache tốt hơn.

  • -Og: Tối ưu hóa, nhưng không can thiệp vào việc gỡ lỗi. Điều này cho phép hiệu suất không đáng xấu hổ cho các bản dựng gỡ lỗi và được thiết kế để thay thế -O0cho các bản dựng gỡ lỗi.

Ngoài ra còn có các tùy chọn khác không được bật bởi bất kỳ tùy chọn nào trong số này và phải được bật riêng. Cũng có thể sử dụng tùy chọn tối ưu hóa, nhưng vô hiệu hóa các cờ cụ thể được tối ưu hóa này kích hoạt.

Để biết thêm thông tin, hãy xem trang web của GCC.


Thật vậy, mặc dù công bằng với các câu trả lời khác, cả -Ofast và -Og đều không tồn tại khi những câu trả lời đó được viết ra.
janneb

Vậy tại sao lại -O100biên dịch?
einpoklum

3
@einpoklum vì GCC coi mọi thứ trên -O3 đều bằng -O3.
Demi

Thật không may, bạn vẫn nhận được rất nhiều <tối ưu hóa> trong trình gỡ lỗi với -Og. Bước vẫn nhảy xung quanh một cách ngẫu nhiên. IMHO vô dụng.
doug65536

3

Bốn (0-3): Xem hướng dẫn sử dụng GCC 4.4.2 . Bất cứ thứ gì cao hơn chỉ là -O3, nhưng đến một lúc nào đó bạn sẽ vượt quá giới hạn kích thước thay đổi.


Tôi đã khám phá mã nguồn trong câu trả lời của mình và đồng ý với bạn. Về cơ bản hơn, GCC dường như dựa trên atoihành vi không xác định, theo sau là 255giới hạn nội bộ.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

4
Vui lòng xem xét xóa câu trả lời của bạn, vì nó (ít nhất là trong những ngày này) không chính xác.
einpoklum
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.