Ada berapa tingkat pengoptimalan GCC?

101

Ada berapa tingkat pengoptimalan GCC ?

Saya mencoba gcc -O1, gcc -O2, gcc -O3, dan gcc -O4

Jika saya menggunakan jumlah yang sangat besar, itu tidak akan berhasil.

Namun, saya sudah mencoba

gcc -O100

dan itu dikompilasi.

Ada berapa tingkat pengoptimalan?

neuromancer
sumber
13
@minitech FM mana yang Anda lihat? Bahkan dengan man gccdi Cygwin (12000 baris ganjil) Anda dapat mencari -Odan menemukan semua jawaban di bawah status, dan kemudian beberapa.
Jens
1
@minmaxavg setelah membaca sumbernya, saya tidak setuju dengan Anda: sesuatu yang lebih besar dari 3itu sama dengan 3(selama tidak intmeluap). Lihat jawaban saya .
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
1
Sebenarnya, GCC memiliki banyak tanda lain untuk menyempurnakan pengoptimalan. -fomit-stack-pointer akan mengubah kode yang dihasilkan.
Basile Starynkevitch

Jawaban:

141

Untuk menjadi pedantic, ada 8 opsi -O valid berbeda yang dapat Anda berikan ke gcc, meskipun ada beberapa yang memiliki arti yang sama.

Versi asli jawaban ini menyatakan ada 7 pilihan. GCC sejak itu ditambahkan -Ogsehingga totalnya menjadi 8

Dari halaman manual:

  • -O (Sama seperti -O1)
  • -O0 (tidak melakukan optimasi, default jika tidak ada level optimasi yang ditentukan)
  • -O1 (optimalkan minimal)
  • -O2 (optimalkan lebih banyak)
  • -O3 (optimalkan lebih banyak lagi)
  • -Ofast (optimalkan dengan sangat agresif hingga melanggar kepatuhan standar)
  • -Og (Optimalkan pengalaman debugging. -Og memungkinkan pengoptimalan yang tidak mengganggu debugging. Ini harus menjadi tingkat pengoptimalan pilihan untuk siklus edit-kompilasi-debug standar, yang menawarkan tingkat pengoptimalan yang wajar sambil mempertahankan kompilasi cepat dan pengalaman debugging yang baik. )
  • -Os(. Optimalkan untuk ukuran -Osmemungkinkan semua -O2optimasi yang tidak biasanya meningkatkan ukuran kode Hal ini juga melakukan optimasi lebih lanjut yang dirancang untuk mengurangi ukuran kode.. -OsMenonaktifkan flag optimasi berikut: -falign-functions -falign-jumps -falign-loops -falign-labels -freorder-blocks -freorder-blocks-and-partition -fprefetch-loop-arrays -ftree-vect-loop-version)

Mungkin juga ada pengoptimalan khusus platform, seperti yang dicatat @pauldoo, OS X memiliki -Oz

Lembah kecil
sumber
23
Jika Anda mengembangkan di Mac OS X, ada -Ozsetelan tambahan yang "optimalkan ukuran lebih agresif daripada -Os": developer.apple.com/mac/library/DOCUMENTATION/DeveloperTools/…
pauldoo
6
Catatan: O3 belum tentu lebih baik dari O2 meskipun namanya menyarankan demikian. Coba keduanya.
johan d
1
@pauldoo 404 halaman, ganti dengan archive.org
noɥʇʎԀʎzɐɹƆ
Ada juga -Og, yaitu semua opsi pengoptimalan yang tidak mengganggu debugging
einpoklum
47

Mari kita tafsirkan kode sumber GCC 5.1 untuk melihat apa yang terjadi -O100karena tidak jelas pada halaman manual.

Kami akan menyimpulkan bahwa:

  • apa pun di -O3atas INT_MAXsama dengan -O3, tetapi itu dapat dengan mudah berubah di masa depan, jadi jangan mengandalkannya.
  • GCC 5.1 menjalankan perilaku tidak ditentukan jika Anda memasukkan bilangan bulat yang lebih besar dari INT_MAX.
  • argumen hanya dapat terdiri dari angka, atau gagal dengan baik. Secara khusus, ini mengecualikan bilangan bulat negatif seperti-O-1

Fokus pada subprogram

Pertama ingat bahwa GCC hanya sebuah front-end untuk cpp, as, cc1, collect2. A quick ./XXX --helpmengatakan itu saja collect2dan cc1mengambil -O, jadi mari kita fokus pada mereka.

Dan:

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

memberikan:

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.

jadi -Oditeruskan ke keduanya cc1dan collect2.

O yang sama. Opt

common.opt adalah format deskripsi opsi CLI khusus GCC yang dijelaskan dalam dokumentasi internal dan diterjemahkan ke C oleh opth-gen.awk dan optc-gen.awk .

Ini berisi baris menarik berikut:

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

yang menentukan semua Oopsi. Perhatikan bagaimana -O<n>berada dalam satu keluarga terpisah dari yang lain Os, Ofastdan Og.

Saat kami membangun, ini menghasilkan options.hfile yang berisi:

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

Sebagai bonus, saat kita menggapai \bO\nbagian dalam common.optkita memperhatikan garis:

-optimize
Common Alias(O)

yang mengajarkan kita bahwa --optimize(tanda hubung ganda karena dimulai dengan tanda hubung -optimizepada .optfile) adalah alias tidak berdokumen -Oyang dapat digunakan sebagai --optimize=3!

Dimana OPT_O digunakan

Sekarang kita grep:

git grep -E '\bOPT_O\b'

yang mengarahkan kita ke dua file:

Mari kita telusuri dulu opts.c

opts.c: default_options_optimization

Semua opts.cpenggunaan terjadi di dalam: default_options_optimization.

Kami grep mundur untuk melihat siapa yang memanggil fungsi ini, dan kami melihat bahwa satu-satunya jalur kode adalah:

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

dan main.cmerupakan titik masuk dari cc1. Baik!

Bagian pertama dari fungsi ini:

  • apakah integral_argumentyang memanggil atoistring yang sesuai OPT_Ountuk mengurai argumen input
  • menyimpan nilai di dalam di opts->x_optimizemana optsa struct gcc_opts.

struct gcc_opts

Setelah melakukan grep dengan sia-sia, kami melihat bahwa ini structjuga dihasilkan di options.h:

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

dari mana x_optimizeberasal dari garis:

Variable
int optimize

hadir di common.opt, dan bahwa options.c:

struct gcc_options global_options;

jadi kami menebak bahwa inilah yang berisi seluruh konfigurasi status global, dan int x_optimizemerupakan nilai pengoptimalan.

255 adalah maksimum internal

in opts.c:integral_argument, atoiditerapkan ke argumen input, begitu INT_MAXjuga batas atasnya. Dan jika Anda meletakkan sesuatu yang lebih besar, tampaknya GCC menjalankan perilaku C tidak terdefinisi. Aduh?

integral_argumentjuga dengan tipis membungkus atoidan menolak argumen jika ada karakter yang bukan digit. Jadi nilai-nilai negatif gagal dengan baik.

Kembali ke opts.c:default_options_optimization, kita melihat baris:

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

sehingga tingkat pengoptimalan dipotong menjadi 255. Saat membaca opth-gen.awksaya menemukan:

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

dan di hasilkan options.h:

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

yang menjelaskan mengapa pemotongan: opsi juga harus diteruskan cl_optimization, yang menggunakan a charuntuk menghemat ruang. Jadi 255 sebenarnya adalah maksimum internal.

opts.c: maybe_default_options

Kembali ke opts.c:default_options_optimization, kami menemukan maybe_default_optionsyang terdengar menarik. Kami memasukinya, dan kemudian di maybe_default_optionmana kami mencapai sakelar besar:

switch (default_opt->levels)
  {

  [...]

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

  [...]

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

Tidak ada >= 4pemeriksaan, yang menunjukkan bahwa 3kemungkinan terbesar.

Lalu kita cari definisi 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.  */
};

Ha! Ini adalah indikator kuat bahwa hanya ada 3 level.

opts.c: default_options_table

opt_levelssangat menarik, sehingga kami grep OPT_LEVELS_3_PLUS, dan menemukan 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 },
    [...]
}

jadi di sinilah -Onpemetaan pengoptimalan khusus yang disebutkan dalam dokumen dikodekan. Bagus!

Pastikan tidak ada lagi kegunaan x_optimize

Penggunaan utama dari x_optimizeadalah untuk mengatur opsi pengoptimalan spesifik lainnya seperti yang -fdefer_popdidokumentasikan di halaman manual. Apakah masih ada lagi

Kami grep, dan temukan beberapa lagi. Jumlahnya kecil, dan setelah pemeriksaan manual kami melihat bahwa setiap penggunaan hanya melakukan paling banyak a x_optimize >= 3, jadi kesimpulan kami berlaku.

lto-wrapper.c

Sekarang kita pergi ke kejadian kedua OPT_O, yaitu masuk lto-wrapper.c.

LTO berarti Pengoptimalan Waktu Tautan, yang seperti namanya akan membutuhkan -Oopsi, dan akan ditautkan collec2(yang pada dasarnya adalah penaut).

Faktanya, baris pertama lto-wrapper.cmengatakan:

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

Dalam file ini, OPT_Okejadian tampaknya hanya menormalkan nilai Ountuk meneruskannya, jadi kita akan baik-baik saja.

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
sumber
38

Tujuh level berbeda:

  • -O0 (default): Tidak ada pengoptimalan.

  • -Oatau -O1(hal yang sama): Optimalkan, tetapi jangan menghabiskan terlalu banyak waktu.

  • -O2: Mengoptimalkan dengan lebih agresif

  • -O3: Mengoptimalkan paling agresif

  • -Ofast: Setara dengan -O3 -ffast-math. -ffast-mathmemicu pengoptimalan floating point yang tidak sesuai standar. Hal ini memungkinkan penyusun untuk berpura-pura bahwa bilangan floating point tepat tak terbatas, dan aljabar pada mereka mengikuti aturan standar aljabar bilangan real. Ini juga memberi tahu kompiler untuk memberi tahu perangkat keras untuk menghapus denormals ke nol dan memperlakukan denormals sebagai nol, setidaknya pada beberapa prosesor, termasuk x86 dan x86-64. Denormals memicu jalur lambat pada banyak FPU, sehingga memperlakukannya sebagai nol (yang tidak memicu jalur lambat) bisa menjadi kemenangan kinerja yang besar.

  • -Os: Mengoptimalkan ukuran kode. Ini sebenarnya dapat meningkatkan kecepatan dalam beberapa kasus, karena perilaku I-cache yang lebih baik.

  • -Og: Mengoptimalkan, tetapi tidak mengganggu proses debug. Hal ini memungkinkan performa yang tidak memalukan untuk build debug dan dimaksudkan untuk menggantikan -O0build debug.

Ada juga opsi lain yang tidak diaktifkan oleh salah satu dari ini, dan harus diaktifkan secara terpisah. Dimungkinkan juga untuk menggunakan opsi pengoptimalan, tetapi nonaktifkan tanda tertentu yang diaktifkan oleh pengoptimalan ini.

Untuk informasi lebih lanjut, lihat situs web GCC.

Demi
sumber
Memang, meskipun adil untuk jawaban lain, baik -Ofast maupun -Og tidak ada saat jawaban itu ditulis.
janneb
Jadi mengapa -O100mengkompilasi?
einpoklum
3
@einpoklum karena GCC memperlakukan semua yang di atas -O3 sama dengan -O3.
Demi
Sayangnya, Anda masih mendapatkan banyak <dioptimalkan> di debugger dengan -Og. Melangkah masih melompat-lompat secara acak. Ini IMHO tidak berguna.
doug65536
3

Empat (0-3): Lihat panduan GCC 4.4.2 . Apa pun yang lebih tinggi hanya -O3, tetapi pada titik tertentu Anda akan melebihi batas ukuran variabel.

Tom
sumber
Saya telah menjelajahi kode sumber dalam jawaban saya dan setuju dengan Anda. Lebih khusus lagi, GCC tampaknya mengandalkan atoiperilaku yang tidak ditentukan, diikuti oleh 255batas internal.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
4
Harap pertimbangkan untuk menghapus jawaban Anda, karena (setidaknya hari-hari ini) salah.
einpoklum