GCC Optimizasyonu

From Gentoo Wiki
Jump to: navigation, search
This page is a translated version of the page GCC optimization and the translation is 55% complete.

Other languages:
English • ‎español • ‎français • ‎italiano • ‎日本語 • ‎한국어 • ‎português do Brasil • ‎русский • ‎Türkçe • ‎中文(中国大陆)‎

This guide provides an introduction to optimizing compiled code using safe, sane CFLAGS and CXXFLAGS. It also as describes the theory behind optimizing in general.

Tanıtım

CFLAGS ve CXXFLAGS nedir?

CFLAGS and CXXFLAGS are among the environment variables conventionally used to specify compiler options to a build system when compiling C and C++ code. While these variables are not standardized, their use is essentially ubiquitous and any correctly written build should understand these for passing extra or custom options when it invokes the compiler. See the GNU make info page for a list of some of the commonly used variables in this category.

Because such a large proportion of the packages that make up most Gentoo systems are written in C and C++, these are two variables administrators will definitely want to set correctly as they will greatly influence the way much of the system is built.

They can be used to decrease the amount of debug messages for a program, increase error warning levels and, of course, to optimize the code produced. The GCC manual maintains a complete list of available options and their purposes.

Nasıl kullanılırlar?

Normally, CFLAGS and CXXFLAGS would be set in the environment when invoking a configure script or with makefiles generated by the automake program. In Gentoo-based systems, set the CFLAGS and CXXFLAGS variables in /etc/portage/make.conf. Variables set in this file will be exported to the environment of programs invoked by portage such that all packages will be compiled using these options as a base.

CODE /etc/portage/make.conf dosyasındaki CFLAGS değerleri
CFLAGS="-march=athlon64 -O2 -pipe"
CXXFLAGS="${CFLAGS}"
Important
While it is possible to have multiple lines in USE flags, having multiple lines in CFLAGS can and will result in problems with programs such as cmake. Make sure the CFLAGS declaration is on a single line, with as little whitespace as possible to avoid issues. See bug #500034 as an example.

As seen in the example above the CXXFLAGS variable is set to use all the options present in CFLAGS. Almost every system should be configured in this manner. Additional options for CXXFLAGS are less common and don't usually apply generally enough to deserve setting them globally.

Tip
Safe CFLAGS article might help beginners start optimizing their systems.

Hatalı düşünceler

While compiler optimizations enabled by various CFLAGS can be an effective means of producing smaller and/or faster binaries, they can also impair the function of the code, bloat its size, slow down its execution time, or simply cause a build failure. The point of diminishing performance returns is reached rather quickly when dealing with CFLAGS. Don't set them arbitrarily.

Remember, the global CFLAGS configured in /etc/portage/make.conf will be applied to every package on the system so administrators typically only set general, widely-applicable options. Individual packages further modify these options either in the ebuild or the build system itself to generate the final set of flags used when invoking the compiler.

Hazır mısınız?

Karşılaşacağınız riskleri de bildiğinize göre artık bazı mantıklı ve güvenli değerleri incelemenin zamanı geldi. Bu değerler sisteminizi sağlıklı tutacak ve Bugzilla'ya raporlayacağınız hatalarda geliştiricilere yardımcı olacak değerlerdir. Geliştiriciler hata raporlarında genellikle (agresif değerlerin yazılıma zarar verebileceğini bildikleri için) problem oluşturan yazılımın basit CFLAGS değerleri ile tekrar derlenmesini ve problemin halen devam edip etmediğinin incelenmesini isterler.

Optimizasyon

Temel

The goal behind CFLAGS and CXXFLAGS is to create code tailor-made to the system; it should function perfectly while being lean and fast, if possible. Sometimes these conditions are mutually exclusive, so this guide will stick to combinations known to work well. Ideally, they are the best available for any CPU architecture. For informational purposes, aggressive flag use will be covered later. Not every option listed on the GCC manual (there are hundreds) will be discussed, but basic, most common flags will be reviewed.

Note
When unaware of what a flag does refer to the relevant chapter of the GCC manual. If still stumped after viewing the manual, try a search engine or check out the GCC mailing lists.

-march

The first and most important option is -march. This tells the compiler what code it should produce for the system's processor architecture (or arch); it tells GCC that it should produce code for a certain kind of CPU. Different CPUs have different capabilities, support different instruction sets, and have different ways of executing code. The -march flag will instruct the compiler to produce specific code for the system's CPU, with all its capabilities, features, instruction sets, quirks, and so on provided the source code is prepared to use them. For instance, to take benefit from AVX instructions, the source code needs to be adapted to support it.

-march= is an ISA selection option; it tells the compiler that it may use the instructions from the ISA. On an Intel/AMD64 platform with -march=native -O2 or lower OPT level, the code will likely end up with AVX instructions used but using shorter SSE XMM registers. To take full advantage of AVX YMM registers, the -ftree-vectorize, -O3 or -Ofast options should be used as well[1].

-ftree-vectorize is an optimization option (default at -O3 and -Ofast), which attempts to vectorize loops using the selected ISA if possible. The reason it isn't enabled at -O2 is that it doesn't always improve code, it can make code slower as well, and usually makes the code larger; it really depends on the loop etc.

Even though the CHOST variable in /etc/portage/make.conf specifies the general architecture used, -march should still be used so that programs can be optimized for the system specific processor. x86 and x86-64 CPUs (among others) should make use of the -march flag.

Ne tür bir işlemciniz var? Öğrenmek için aşağıdaki komutu çalıştırabilirsiniz:

user $cat /proc/cpuinfo

or even install app-portage/cpuid2cpuflags and add the available CPU-specific options to the make.conf file, which the tool does through e.g. the CPU_FLAGS_X86 variable:

user $cpuid2cpuflags
CPU_FLAGS_X86: aes avx avx2 f16c fma3 mmx mmxext popcnt sse sse2 sse3 sse4_1 sse4_2 ssse3
root #echo "CPU_FLAGS_X86='aes avx avx2 f16c fma3 mmx mmxext popcnt sse sse2 sse3 sse4_1 sse4_2 ssse3'" >> /etc/portage/make.conf

march ve mtune dahil, seçenekler hakkında daha fazla detay için iki komut kullanılabilir:

user $gcc -c -Q -march=native --help=target
user $gcc -### -march=native /usr/include/stdlib.h

Şimdi de -march değerini iş başında görelim. Aşağıdaki örnek eski bir Pentium III işlemci için:

FILE /etc/portage/make.confPentium III örneği
CFLAGS="-march=pentium3"
CXXFLAGS="${CFLAGS}"

Şimdi de 64-bit bir işlemci için bir örnek:

FILE /etc/portage/make.confAMD64 örneği
CFLAGS="-march=athlon64"
CXXFLAGS="${CFLAGS}"

Hangi tür işlemciye sahip olduğunuzdan veya işlemciniz için ne kullanacağınızdan halen emin değilseniz -march=native kullanın. Bu değeri kullanarak, GCC'nin işlemcinizi otomatik olarak tanıyarak en uyumlu değerleri kendi belirlemesini sağlayabilirsiniz. Ancak oluşacak paketi farklı bir CPU'da çalıştırmak üzere bir derleme yapıyorsanız bu seçeneği kullanmayın!

Warning
distcc ile derleme yaparken make.conf içerisindeki CFLAGS veya CXXFLAGS değerlerinde -march=native veya -mtune=native değerlerini kullanmayın.

If compiling packages on one computer in order to run them on a different computer (such as when using a fast computer to build for an older, slower machine), then do not use -march=native. "Native" means that the code produced will run only on that type of CPU. The applications built with -march=native on an AMD Athlon 64 CPU will not be able to run on an old VIA C3 CPU.

Ayrıca -mtune ve -mcpu bayraklarını da kullanabilirsiniz. Bunlar normalde sadece uyumlu -march seçeneği bulunmadığında kullanılan seçeneklerdir; bazı işlemci mimarileri -mtune hatta -mcpu kullanımını gerektirebilir. Malesef GCC'nin her bayrak için davranışı bir mimariden diğerine farklılık göstermektedir.

x86 ve x86-64 işlemcilerde -march kullandığınızda sonuç olarak işlemciniz ile tam uyumlu kodlar alırsınız, yani üretilen paketler farklı veya daha eski işlemcilerde çalışmaz. Paketleri yalnızca derlediğiniz sistemde kullanacaksanız -march kullanın. -mtune ve -mcpu seçeneklerini yalnızca daha eski işlemcilere (i386 ve i486 gibi) uyumlu paketler derleme amacındaysanız değerlendirin. -mcpu seçeneği kullanıldığında birçok gerekli değeri (ABI gibi) dikkate almadığı için, bu seçeneği x86 ve x86-64 sistemlerde kullanmayın.

Only non-x86/x86-64 CPUs (such as SPARC, Alpha, and PowerPC) may require -mtune or -mcpu instead of -march. On these architectures, -mtune / -mcpu will sometimes behave just like -march (on x86/x86-64) but with a different flag name. Again, GCC's behavior and flag naming is not consistent across architectures, so be sure to check the GCC manual to determine which one should be used.

Note
For more suggested -march / -mtune / -mcpu settings, please read chapter 5 of the appropriate Gentoo Installation Handbook for the arch. Also, read the GCC manual's list of architecture-specific options, as well as more detailed explanations about the differences between -march, -mcpu, and -mtune.

-O

Note
To print all packages that were built with specified CFLAGS/CXXFLAGS it's possible to use the following command: grep Ofast /var/db/pkg/*/*/CFLAGS

Gelecek seçeneğimiz -O. Bu seçenek genel optimizasyon değerini kontrol etmekte. Bu değeri değiştirmek, özellikle yüksek değerlerde derleme sürecini biraz daha yavaş hale getirip, RAM tüketimini artırabilir.

There are seven -O settings: -O0, -O1, -O2, -O3, -Os, -Og, and -Ofast. Only use one of them in /etc/portage/make.conf.

With the exception of -O0, the -O settings each activate several additional flags, so be sure to read the GCC manual's chapter on optimization options to learn which flags are activated at each -O level, as well as some explanations as to what they do.

Optimiasyon seviyelerinin yaptıklarına bir göz atalım:

  • -O0 : Bu seviye (bir "O" harfinin ardından eklenmiş sıfır) tıpkı -O kullanılmamış gibi tüm optimizasyon seçeneklerini kapalı konuma getirir. Bu sayede derleme zamanı azalır ve hata ayıklamak kolaylaşır ancak bazı uygulamalar optimizasyon olmadan düzgün çalışamayacaktır. Programdaki hataları yakalama amacı dışında bu seçenek önerilmemektedir.
  • -O1 : En temel optimizasyon seviyesidir. Derleme süresini çok yükseltmeden daha hızlı ve daha ufak kodlar üretir. Basit bir seçenektir ancak genellikle her zaman güvenlidir diyebiliriz.
  • -O2: A step up from -O1. The recommended level of optimization unless the system has special needs. -O2 will activate a few more flags in addition to the ones activated by -O1. With -O2, the compiler will attempt to increase code performance without compromising on size, and without taking too much compilation time. SSE or AVX may be be utilized at this level but no YMM registers will be used unless -ftree-vectorize is also enabled.
  • -O3: the highest level of optimization possible. It enables optimizations that are expensive in terms of compile time and memory usage. Compiling with -O3 is not a guaranteed way to improve performance, and in fact, in many cases, can slow down a system due to larger binaries and increased memory usage. -O3 is also known to break several packages. Using -O3 is not recommended. However, it also enables -ftree-vectorize so that loops in the code get vectorized and will use AVX YMM registers.
  • -Os : Bu seçenek üretilen kodun boyutunu optimize eder. Boyutta büyümeye sebep olmayacak tüm -O2 seçeneklerini açar. Çok az disk alanı ve/veya işlemcisinde ufak önbellekleri bulunan bilgisayarlarda kullanışlı olabilir.
  • -Og: GCC 4.8'de yeni bir optimizasyon seviyesi olarak -Og tanıtıldı. Çalıştırma hızından çok ödün vermeden, hızlı bir derleme ile hata ayıklama modunda çalışmak için kullanılmaktadır. Geliştirme için genel olarak -O0'dan daha rahat bir ortam sağlamaktadır. -Og uygulamak otomatik olarak -g'yi aktif hale getirmez, yalnızca hata ayıklamayı zorlaştıran optimizasyonları etkisiz hale getirir.
  • -Ofast: GCC 4.7 ile gelen bir seçenektir, -O3 üzerine -ffast-math, -fno-protect-parens ve -fstack-arrays ekler. Bu seçenek tavsiye edilen standartların dışında olduğu için tavsiye edilmemektedir.

Önceden de belirttiğimiz gibi -O2 önerilen optimizasyon seviyesidir. Eğer derlemeniz hata ile sonlandıysa ve -O2 kullanmıyorsanız, öncelikle kullanarak tekrar deneyin. Hata oluştuğu durumlarda optimizasyonu azaltmayı (-O1), hatta kapatmayı (-O0 -g2 -ggdb) deneyebilirsiniz.

-pipe

Bir başka sık kullanılan bayrak da -pipe'dır. Derleme sonrası üretilen kodda bir değişikliğe sebep olmaz ancak derleme işleminin daha hızlı gerçekleştirilmesini sağlar. Derleyiciye, derleme sırasında geçici dosyalar kullanmak yerine pipe kullanmasını belirtir. Bu işlem daha fazla RAM kullanımına sebep olduğu için, eğer cihazınızda RAM sıkıntısı yaşıyorsanız ve derleme sırasında problem oluşuyor ise bu seçeneği kullanmayabilirsiniz.

-fomit-frame-pointer

Bu da üretilen kodun azaltılmasını sağlayan yaygın bir seçenektir. Hata ayıklamayı zorlaştırmadığı platformlarda (x86-64 gibi) -O seçeneğinin her seviyesinde (-O0 hariç) otomatik olarak açılır. GCC belgeleri her mimari için bu durumu netleştirmemektedir ancak x86 üzerinde kendiniz ekleyerek açmanız gerektiği bilinmektedir. Bu seçeneği kullanmak uygulamalarda oluşan hataları yakalamayı oldukça zorlaştırır.

Özel olarak Java ile yazılmış uygulamaların hata ayıklamasını neredeyse imkansız hale getirir. Yine de bu bayrak yalnızca Java kodlarını etkilememektedir. Yani getirisinin bir bedeli olarak problem oluşturan uygulamalarınızın hata kaydı çıktıları işe yaramaz duruma gelecektir. Hata ayıklama işlemine ihtiyacınız yok ise ve farklı hata ayıklama seçeneklerini (-ggdb gibi) kullanmıyorsanız -fomit-frame-pointer kullanmayı deneyebilirsiniz.

Önemli
-fomit-frame-pointer seçeneğini benzeri olan -momit-leaf-frame-pointer ile kullanmayın. Ayrıca -momit-leaf-frame-pointer seçeneğinin performans üzerinde negatif etkisi olduğu bilinmektedir.

-msse, -msse2, -msse3, -mmmx, -m3dnow

These flags enable the Streaming SIMD Extensions (SSE), SSE2, SSE3, MMX, and 3DNow! instruction sets for x86 and x86-64 architectures. These are useful primarily in multimedia, gaming, and other floating point-intensive computing tasks, though they also contain several other mathematical enhancements. These instruction sets are found in more modern CPUs.

Important
Be sure to see if the CPU supports these instruction sets by running cat /proc/cpuinfo. The output will include any supported additional instruction sets. Note that pni is just a different name for SSE3.

Doğru -march değerini kullandığınız sürece normal şartlarda bu seçenekleri /etc/portage/make.conf dosyasına eklemenize gerek bulunmamakta. Örneğin -march=nocona seçeneği zaten içerisinde -msse3 barındırmakta. Bazı yeni VIA ve Amd64 işlemcilerde -march'ın kapsamadığı seçenekler (sse3 gibi) bulunabilmekte. Bu tür durumlarda cat /proc/cpuinfo kodunun çıktısına bakarak gerekli eklemeyi yapmanız gerekecektir.

Note
Check the list of x86 and x86-64-specific flags to see which of these instruction sets are activated by the proper CPU type flag. If an instruction is listed, then it does not need to be separately specified; it will be turned on by using the proper -march setting.

Optimizasyon SSS

Ama -funroll-loops -fomg-optimize seçenekleri ile daha iyi performans alıyorum!

No, people only think they do because someone has convinced them that more flags are better. Aggressive flags will only hurt applications when used system-wide. Even the GCC manual says that using -funroll-loops and -funroll-all-loops will make code larger and run more slowly. Yet for some reason, these two flags, along with -ffast-math, -fforce-mem, -fforce-addr, and similar flags, continue to be very popular among ricers who want the biggest bragging rights.

Aslında bunlar tehlikeli derecede agresif seçenekler. Bu seçeneklerin kullanımı ile ilgili Gentoo Forumları ve Bugzilla'ya göz attığınızda pek iyi bir manzara ile karşılaşmayacaksınız.

These flags are not needed globally in CFLAGS or CXXFLAGS. They will only hurt performance. They might bring on the idea of having a high-performance system running on the bleeding edge, but they don't do anything but bloat the code and get bugs marked INVALID or WONTFIX.

Dangerous flags like these are not needed. Don't use them. Stick to the basics: -march, -O, and -pipe.

Peki ya 3'ten büyük -O seviyeleri?

Bazı kullanıcılar -O4, -O9 gibi yüksek optimizasyon seviyeleri ile daha iyi performans aldıklarını iddia etmekteler. Aslında -O3'ün üzerindeki hiçbir optimizasyon değerinin bir etkisi bulunmamakta. Derleyici yalnızca -O3 seviyesini uygulamaktadır.

Kanıt mı istiyorsunuz? Kaynak kodunu inceleyin:

CODE -O kaynak kodu
if (optimize >= 3)
    {
      flag_inline_functions = 1;
      flag_unswitch_loops = 1;
      flag_gcse_after_reload = 1;
      /* Allow even more virtual operators.  */
      set_param_value ("max-aliased-vops", 1000);
      set_param_value ("avg-aliased-vops", 3);
    }

As can be seen, any value higher than 3 is treated as just -O3.

Ya hedef bilgisayar haricinde derleme yapıyorsak?

Some readers might wonder if compiling outside the target machine with a strictly inferior CPU or GCC sub-architecture will result in inferior optimization results (compared to a native compilation). The answer is simple: No. Regardless of the actual hardware on which the compilation takes place and the CHOST for which GCC was built, as long as the same arguments are used (except for -march=native) and the same version of GCC is used (although minor version might be different), the resulting optimizations are strictly the same.

To exemplify, if Gentoo is installed on a machine whose GCC's CHOST is i686-pc-linux-gnu, and a Distcc server is setup on another computer whose GCC's CHOST is i486-linux-gnu, then there is no need to be afraid that the results would be less optimal because of the strictly inferior sub-architecture of the remote compiler and/or hardware. The result would be as optimized as a native build, as long as the same options are passed to both compilers (and the -march parameter doesn't get a native argument). In this particular case the target architecture needs to be specified explicitly as explained in Distcc and -march=native.

The only difference in behavior between two GCC versions built targeting different sub-architectures is the implicit default argument for the -march parameter, which is derived from the GCC's CHOST when not explicitly provided in the command line.

Peki ihtiyaç fazlası bayraklar?

Çoğu zaman /etc/portage/make.conf dosyasındaki CFLAGS ve CXXFLAGS değerlerinin arasında tekrarlanan -O değerlerini görebilirsiniz. Bu bazen hata ile bazen de bayrak değişiminin önüne geçmek için yapılan birşeydir.

Bayrak filtreleme/değişimi Portage içerisinde birçok uygulamada yapılmakta. Genellikle bir uygulamanın belirli bir -O değeri ile çalışamadığı görüldüğünde ebuild üzerinde ilgili seçeneğin kaldırılması veya değiştirilmesi ile problem aşılıyor.

The Gentoo Developer Manual outlines where and how flag filtering/replacing works.

Gereksiz -O değerleri kullanarak belirli bir seviye için filtreleme işleminden kurtulmak mümkün. Örneğin -O3 için:

CODE Gereksiz CFLAGS belirtme
CFLAGS="-O3 -finline-functions -funswitch-loops"

However, this is not a smart thing to do. CFLAGS are filtered for a reason! When flags are filtered, it means that it is unsafe to build a package with those flags. Clearly, it is not safe to compile the whole system with -O3 if some of the flags turned on by that level will cause problems with certain packages. Therefore, don't try to "outsmart" the developers who maintain those packages. Trust the developers. Flag filtering and replacing is done to ensure stability of the system and application! If an ebuild specifies alternative flags, then don't try to get around it.

Building packages with unacceptable flags will most likely lead to problems. When reporting problems on Bugzilla, the flags that are used in /etc/portage/make.conf will be readily visible and developers will ask to recompile without those flags. Save the trouble of recompiling by not using redundant flags in the first place! Don't just automatically assume to be more knowledgeable than the developers.

Peki ya LDFLAGS?

Gentoo geliştiricileri zaten gerekli ve güvenli LDFLAGS değerlerini profillerin içine yerleştirdikleri için herhangi bir değişiklik yapmanıza gerek bulunmamaktadır.

Her paket için ayrı bayrak kullanabilir miyim?

Warning
Using per-package flags complicates debugging and support. Make sure to mention the use of this feature in the bug reports together with the changes made.

Her paket için ayrı ortam değişkenini (CFLAGS dahil) nasıl kullanabileceğiniz ile ilgili bilgi Gentoo El Kitabı, "Per-Package Environment Variables" bölümünde bulunmaktadır.

See also

External resources

Aşağıdaki kaynaklar optimizasyon ile ilgili daha fazla bilgi almanıza yardımcı olabilir:

  • man make.conf

References

  1. GNU GCC Bugzilla, AVX/AVX2 no ymm registers used in a trivial reduction. Retrieved on 2017/07/18.

This page is based on a document formerly found on our main website gentoo.org.
The following people contributed to the original document: Joshua Saddler (nightmorph)
They are listed here because wiki history does not allow for any external attribution. If you edit the wiki article, please do not add yourself here; your contributions are recorded on each article's associated history page.