Kaç tane GCC optimizasyon seviyesi var?


102

Kaç tane GCC optimizasyon seviyesi var?

Gcc -O1, gcc -O2, gcc -O3 ve gcc -O4'ü denedim

Gerçekten büyük bir sayı kullanırsam işe yaramaz.

Ancak denedim

gcc -O100

ve derlendi.

Kaç optimizasyon seviyesi var?


13
@minitech Hangi FM'e bakıyorsunuz? man gccCygwin'de (12000 tek satır) bile, -Oaşağıda belirtilen her şeyi arayabilir ve bulabilirsiniz.
Jens

1
@minmaxavg kaynağı okuduktan sonra, size katılmıyorum: 3aynı olandan daha büyük herhangi bir şey (taşmadığı 3sürece int). Cevabımı gör .
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

1
Aslında, GCC'nin optimizasyonlara ince ayar yapmak için başka birçok bayrağı vardır. -fomit-stack-pointer üretilen kodu değiştirecek.
Basile Starynkevitch

Yanıtlar:


142

Bilgiçlik taslamak gerekirse, gcc'ye verebileceğiniz 8 farklı geçerli -O seçeneği vardır, ancak aynı anlama gelenler de vardır.

Bu cevabın orijinal versiyonu 7 seçenek olduğunu belirtti. GCC o zamandan beri -Ogtoplamı 8'e çıkarmak için ekledi

Gönderen adam sayfası:

  • -O (Aynı -O1)
  • -O0 (optimizasyon yapma, optimizasyon seviyesi belirtilmemişse varsayılan)
  • -O1 (minimum düzeyde optimize edin)
  • -O2 (daha fazla optimize edin)
  • -O3 (daha fazla optimize edin)
  • -Ofast (standart uyumluluğu bozma noktasına kadar çok agresif bir şekilde optimize edin)
  • -Og (Hata ayıklama deneyimini optimize edin. -Og, hata ayıklamayı engellemeyen optimizasyonları mümkün kılar. Hızlı derlemeyi ve iyi bir hata ayıklama deneyimini korurken makul bir optimizasyon düzeyi sunan, standart düzenleme-derleme-hata ayıklama döngüsü için tercih edilen optimizasyon seviyesi olmalıdır. )
  • -Os(. Boyut optimize -Ostüm sağlayan -O2.. Aynı zamanda kod boyutunu azaltmak için tasarlanmış ileri optimizasyonlar gerçekleştirir tipik kod boyutunu artırmaz optimizasyonlar -Osaşağıdaki optimizasyon bayrakları devre dışı bırakır: -falign-functions -falign-jumps -falign-loops -falign-labels -freorder-blocks -freorder-blocks-and-partition -fprefetch-loop-arrays -ftree-vect-loop-version)

@Pauldoo'nun belirttiği gibi, platforma özel optimizasyonlar da olabilir, OS X'in -Oz


23
Mac OS X üzerinde geliştirme yapıyorsanız -Oz, "boyut için daha agresif bir şekilde optimize et" olan ek bir ayar vardır -Os: developer.apple.com/mac/library/DOCUMENTATION/DeveloperTools/…
pauldoo

6
Not: Adından da anlaşılsa bile O3'ün O2'den daha iyi olması gerekmez. İkisini de dene.
johan d

1
@pauldoo 404 sayfası, archive.org ile değiştirin
noɥʇʎԀʎzɐɹƆ

Orada da -Ogayıklama karışmaz tüm optimizasyon seçenekleri olan
einpoklum

49

GCC 5.1'in kaynak kodunu yorumlayalım

-O100Man sayfasında net olmadığı için neler olduğunu anlamaya çalışacağız .

Şu sonuca varacağız:

  • Yukarıdaki şey -O3için yukarı INT_MAXaynıdır -O3, ama bu kolayca gelecekte değişebilir bu yüzden güvenmeyin.
  • GCC 5.1'den büyük tamsayılar girerseniz, tanımsız davranışı çalıştırır INT_MAX.
  • bağımsız değişken yalnızca rakamlara sahip olabilir veya mükemmel bir şekilde başarısız olur. Özellikle, bu gibi negatif tam sayılar hariçtir-O-1

Alt programlara odaklanın

İlk GCC için sadece bir ön uç olduğunu unutmayın cpp, as, cc1, collect2. Hızlı bir ./XXX --helpsadece bunu söyler collect2ve cc1alır -O, o yüzden onlara odaklanalım.

Ve:

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

verir:

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.

bu yüzden -Oher ikisine de iletildi cc1ve collect2.

O ortak. Opt

common.opt tarif edilen bir GCC belirli CLI seçenek açıklama biçimi iç donanım belgelerine göre C ve çevrilmiş opth-gen.awk ve optc-gen.awk .

Aşağıdaki ilginç satırları içerir:

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

tüm Oseçenekleri belirtir . Nasıl Not -O<n>diğerinden ayrı ailede olduğu Os, Ofastve Og.

Oluşturduğumuzda, bu options.h, şunları içeren bir dosya oluşturur :

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

Bonus olarak, \bO\niçeriye girerken common.optşu satırları görüyoruz:

-optimize
Common Alias(O)

olanı bize öğretir --optimize(çift çizgi bir çizgi ile başlar, çünkü -optimizeüzerinde .optdosyası) için bir belgesiz takma -Oolarak kullanılabilir --optimize=3!

OPT_O'nun kullanıldığı yerler

Şimdi grep:

git grep -E '\bOPT_O\b'

bu da bizi iki dosyaya işaret ediyor:

Önce takip edelim opts.c

opts.c: default_options_optimization

Tüm opts.ckullanımlar içeride olur: default_options_optimization.

Bu işlevi kimin çağırdığını görmek için geriye doğru izleriz ve tek kod yolunun şu olduğunu görürüz:

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

ve main.cgiriş noktasıdır cc1. İyi!

Bu işlevin ilk bölümü:

  • mu integral_argumentçağrıları atoikarşılık gelen dize üzerinde OPT_Ogiriş argüman ayrıştırmak için
  • değeri a opts->x_optimizeolduğu yerde saklar .optsstruct gcc_opts

struct gcc_opts

Boşuna uğraştıktan sonra, bunun şu structanda da üretildiğini fark ettik options.h:

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

x_optimizeçizgiler nereden geliyor:

Variable
int optimize

mevcut common.optve şu options.c:

struct gcc_options global_options;

bu nedenle, tüm konfigürasyon genel durumunu içeren şeyin bu int x_optimizeolduğunu ve optimizasyon değerinin bu olduğunu tahmin ediyoruz .

255 dahili bir maksimumdur

in opts.c:integral_argument, atoigirdi bağımsız değişkenine uygulanır, dolayısıyla INT_MAXbir üst sınır da uygulanır. Ve daha büyük bir şey koyarsanız, GCC C tanımsız davranışı çalıştırıyor gibi görünüyor. Ah?

integral_argumentayrıca atoiherhangi bir karakter rakam değilse, argümanı ince bir şekilde sarar ve reddeder. Yani negatif değerler zarafetle başarısız olur.

Geri dönelim opts.c:default_options_optimization, şu satırı görüyoruz:

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

optimizasyon düzeyinin kısaltılması için 255. Okurken opth-gen.awkkarşılaştım:

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

ve oluşturulan options.h:

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

Bu, neden kesmenin nedenini açıklar: seçenekler de yönlendirilmelidir cl_optimization, bu charda yer kazanmak için a kullanır . Yani 255 aslında dahili bir maksimumdur.

opts.c: might_default_options

Geri opts.c:default_options_optimizationdöndüğümüzde, maybe_default_optionshangi kulağa ilginç geldiğini görüyoruz . Giriyoruz ve sonra maybe_default_optionbüyük bir anahtara ulaşıyoruz:

switch (default_opt->levels)
  {

  [...]

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

  [...]

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

Bunun mümkün olan en büyük >= 4olduğunu gösteren hiçbir kontrol yoktur 3.

Sonra tanımında aramak OPT_LEVELS_3_PLUSiçinde 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! Bu, yalnızca 3 seviye olduğunun güçlü bir göstergesidir.

opts.c: default_options_table

opt_levelso kadar ilginç ki grep OPT_LEVELS_3_PLUSve karşımıza çıkıyor 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 },
    [...]
}

bu nedenle -On, belgelerde belirtilen belirli optimizasyon eşlemesinin kodlandığı yer burasıdır . Güzel!

X_optimize için başka kullanım olmadığından emin olun

Ana kullanımı , man sayfasında belgelendiği x_optimizegibi diğer belirli optimizasyon seçeneklerini ayarlamaktı -fdefer_pop. Daha var mı

Biz grepve birkaç tane daha buluyoruz. Sayı küçüktür ve manuel incelemede her kullanımın yalnızca en fazla a yaptığını görüyoruz x_optimize >= 3, dolayısıyla sonucumuz geçerlidir.

lto-wrapper.c

Şimdi OPT_O, içinde olan ikinci oluşumuna gidiyoruz lto-wrapper.c.

LTO, adından da anlaşılacağı gibi bir -Oseçeneğe ihtiyaç duyacak ve bağlantılı olacak collec2(temelde bir bağlayıcıdır) Bağlantı Süresi Optimizasyonu anlamına gelir .

Aslında, ilk satır şunu lto-wrapper.csöylüyor:

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

Bu dosyada, OPT_Oolaylar sadece Oonu iletmenin değerini normalleştiriyor gibi görünüyor , bu yüzden iyi olmalıyız.


38

Yedi farklı seviye:

  • -O0 (varsayılan): Optimizasyon yok.

  • -Oveya -O1(aynı şey): Optimize edin, ancak çok fazla zaman harcamayın.

  • -O2: Daha agresif bir şekilde optimize edin

  • -O3: En agresif şekilde optimize edin

  • -Ofast: Eşdeğeri -O3 -ffast-math. -ffast-mathstandartlarla uyumlu olmayan kayan nokta optimizasyonlarını tetikler. Bu, derleyicinin kayan nokta sayılarının sonsuz derecede hassas olduğunu ve üzerlerindeki cebirin gerçek sayı cebirinin standart kurallarını izlediğini varsaymasına olanak tanır. Ayrıca derleyiciye, donanıma denormalleri sıfırlamasını ve en azından x86 ve x86-64 dahil olmak üzere bazı işlemcilerde normalleri sıfır olarak değerlendirmesini söylemesini söyler. Denormals, birçok FPU'da yavaş bir yol tetikler ve bu nedenle onları sıfır olarak ele almak (bu yavaş yolu tetiklemez) büyük bir performans kazanımı olabilir.

  • -Os: Kod boyutu için optimize edin. Bu, daha iyi I-önbellek davranışı nedeniyle bazı durumlarda hızı gerçekten artırabilir.

  • -Og: Optimize edin, ancak hata ayıklamaya müdahale etmeyin. Bu, hata ayıklama yapıları için utanç verici olmayan performans sağlar ve bunun yerini alması amaçlanmıştır.-O0 .

Bunların hiçbiri tarafından etkinleştirilmeyen ve ayrıca etkinleştirilmesi gereken başka seçenekler de vardır. Bir optimizasyon seçeneği kullanmak da mümkündür, ancak bu optimizasyonla etkinleştirilen belirli bayrakları devre dışı bırakabilirsiniz.

Daha fazla bilgi için GCC web sitesine bakın.


Nitekim, diğer cevaplara karşı adil olmak gerekirse, bu cevaplar yazılırken ne -Ohz ne de -Og vardı.
2013

Öyleyse neden -O100derleme yapılıyor?
einpoklum

3
@einpoklum çünkü GCC -O3'ün üzerindeki her şeyi -O3'e eşit olarak ele alıyor.
Demi

Ne yazık ki, hata ayıklayıcıda -Og ile bir ton <optimize edilmiş> elde edersiniz. Adım atma hala rasgele atlıyor. İşe yaramaz IMHO.
doug65536

3

Dört (0-3): GCC 4.4.2 kılavuzuna bakın . Daha yüksek bir değer sadece -O3'tür, ancak bir noktada değişken boyut sınırını aşarsınız.


Ben kaynak kodunu inceledik cevabım ve size katılıyorum. Daha bilgiççe, GCC atoitanımlanmamış davranışa ve ardından bir 255iç sınıra güveniyor gibi görünüyor .
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

4
Lütfen (en azından bu günlerde) yanlış olduğu için yanıtınızı kaldırmayı düşünün.
einpoklum
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.