GCC оптимизации – Gentoo Wiki
Този урок предлага въведение в компилирането на оптимизация на код с помощта на безопасни, разумни флагове CFLAGS и CXXFLAGS. Той също така описва теорията на оптимизацията в общи линии.
Какво представляват CFLAGS и CXXFLAGS?
Тъй като голяма част от пакетите, съставляващи повечето системи на Gentoo, са написани на C и C++, администраторите трябва да настроят тези две променливи правилно, тъй като те имат голямо влияние върху това как е изградена системата.
Те могат да се използват за намаляване на броя на съобщенията за отстраняване на грешки в програмата, увеличаване на нивото на съобщенията за грешки и, разбира се, оптимизиране на генерирания код. Ръководството на GCC поддържа пълен списък на наличните опции и техните цели.
Как се използват?
Обикновено променливите CFLAGS и CXXFLAGS се задават в средата чрез извикване на скрипта за конфигуриране или чрез използване на makefile файл, генериран от програмата automake. В системи, базирани на Gentoo, тези променливи се задават във файла /etc/portage/make.conf. Променливите, зададени в този файл, се експортират в средата на програми, стартирани от portage - по този начин всички пакети са изградени, използвайки тези параметри като основа.
В горния пример променливата CXXFLAGS е зададена така, че да използва всички опции, зададени в променливата CFLAGS. Почти всички системи трябва да бъдат конфигурирани по този начин. Допълнителните опции за променливата CXXFLAGS са по-рядко срещани и обикновено не се използват широко, за да си струва да ги задавате глобално.
Заблуди
Докато оптимизациите на компилатора, активирани чрез различни опции на CFLAGS, могат да бъдат ефективен начин за създаване на по-малки и/или по-бързи изпълними файловефайлове, те също могат да влошат функционалността на кода, да увеличат размера му, да забавят изпълнението му или да доведат до грешка при компилиране. Неправилното използване на променливата CFLAGS може бързо да доведе до лоша производителност. Не задавайте тези параметри произволно.
Настройките в глобалната променлива CFLAGS, зададена във файла /etc/portage/make.conf, се прилагат за всички пакети в системата, така че администраторите обикновено задават само най-общите, широко използвани настройки в тази променлива. Индивидуалните пакети могат да променят тези опции или във файла ebuild, или в самата система за изграждане, създавайки окончателния набор от флагове, които да бъдат подавани към компилатора.
Сега, като знаем някои от рисковете, нека да разгледаме някои от интелигентните и безопасни оптимизации. Те ще бъдат от голяма полза и ще поставят разработчиците в добра полза следващия път, когато докладвате за проблем на Bugzilla. (Разработчиците обикновено молят потребителите да прекомпилират пакет с възможно най-малко CFLAGS, за да определят дали проблемът все още съществува. Запомнете: Агресивните флагове могат да нарушат кода!)
Оптимизация
Целта на използването на CFLAGS и CXXFLAGS е да се създаде код, съобразен със системата; трябва да функционира перфектно, да е лек и бърз, ако е възможно. Понякога това са взаимно изключващи се условия, така че това ръководство ще се придържа към комбинации, за които е известно, че работят добре. В идеалния случай те са лесно достъпни на всяка CPU архитектура. За справка, агресивното използване на знамето ще бъде обсъдено по-късно. Няма да покриваме всеки параметър от ръководството на GCC (има много от тях), но ще опишем основните, най-често използвани флагове.
-ftree-vectorize еопция за оптимизация (по подразбиране при -O3 и -Ofast), която се опитва да векторизира цикли, използвайки избрания ISA, ако е възможно. Причината да не е активиран при -O2 е, че не винаги подобрява кода, може да направи кода и по-бавен и обикновено го прави по-голям; наистина зависи от цикъла и т.н.
Какъв тип процесор има системата? За да разберете, въведете следната команда:
- Първата команда казва на компилатора да не свързва ( -c ) и вместо да интерпретира опцията --help, за да посочи опциите на командния ред, показва кои опции са активирани или деактивирани ( -Q ). В този случай се показват опциите, които са били активирани за избраната цел:
- Втората команда ще покаже директивите на компилатора за изграждане на заглавния файл, но без реално изпълнение и ще покаже резултата от работата на екрана ( -### ). Резултатът съдържа всички опции за оптимизация, както и избраната архитектура:
И това е друг пример за 64-битов AMD процесор:
Следващата в списъка е променливата -O. Той контролира цялото ниво на оптимизация. Промяната на тази променлива кара кода да отнема повече време за компилиране и може да заема много повече памет, особено когато нивото на оптимизация е повишено.
Има седем вида настройки за променливата -O: -O0 , -O1 , -O2 , -O3 , -Os , -Og и -Ofast . Използвайте само един от тях в /etc/portage/make.conf.
С изключение на -O0, всяка от настройките с префикс -O активира няколко допълнителни флага, така че се уверете, че сте прочели главата на ръководството на GCC относно опциите за оптимизация, за да научите кои флагове са активирани на всяко ниво с префикс -O, както и някои от обясненията за това какво правят.
Нека проучим всяко нивооптимизации:
- -O0 : Това ниво (буквата "O", последвана от нула) деактивира оптимизацията напълно и е нивото по подразбиране, ако в променливите CFLAGS или CXXFLAGS не е указано ниво с префикс -O. Това намалява времето за компилиране и може да подобри данните за отстраняване на грешки, но някои приложения няма да работят правилно без оптимизация. Тази опция не се препоръчва, освен за целите на отстраняване на грешки.
- -O1 : Това е най-простото ниво на оптимизация. Компилаторът ще се опита да генерира бърз, по-малък код, без да отнема най-дълго време за компилиране. Това е достатъчно просто, но винаги трябва да свърши работата.
- -O2 : Стъпка напред от -O1 .Препоръчителнониво на оптимизация, освен ако не е необходимо нещо специално. -O2 активира няколко допълнителни флага в допълнение към флаговете, активирани от -O1. С опцията -O2 компилаторът ще се опита да увеличи производителността на кода, без да прави компромис с размера и без да изразходва много време за компилиране. SSE и AVX могат да се използват на това ниво, но YMM регистрите няма да се използват, освен ако опцията -ftree-vectorize не е разрешена.
- -O3 : Това е възможно най-високото ниво на оптимизация. Включва оптимизации, които са скъпи по отношение на времето за компилиране и консумацията на памет. Компилирането с -O3 не е гарантиран начин за подобряване на производителността и всъщност може да забави системата в много случаи поради големи двоични файлове и увеличено потребление на памет. Известно е също, че -O3 разбива няколко пакета. Използването на -O3 не се препоръчва.
- -Os : На това ниво кодът ще бъде оптимизиран за пространство. Той активира всички -O2 опции,които не водят до увеличаване на размера на генерирания код. Може да бъде полезно на компютри, които имат изключително ограничено пространство на твърдия диск и/или процесори с малък размер на кеша.
- -Og : Ново общо ниво на оптимизация -Og беше въведено в GCC 4.8. Той задоволява необходимостта от бързо компилиране и отлични възможности за отстраняване на грешки, като същевременно осигурява приемливо ниво на производителност по време на изпълнение. Цялостното изживяване при разработка трябва да е по-добро, отколкото при нивото на оптимизация по подразбиране -O0. Обърнете внимание, че -Og не означава -g, а просто деактивира оптимизациите на кода, които могат да попречат на отстраняването на грешки.
- -Ofast: Ново в GCC 4.7, състои се от -O3 плюс -ffast-math, -fno-protect-parens и -fstack-arrays. Тази опция нарушава стриктното спазване на стандарта и не се препоръчва за употреба.
Често използваният флаг е -pipe. Този флаг не засяга генерирания код, ноускорява процеса на компилиране. Той казва на компилатора да използва канал вместо временни файлове по време на различни етапи на компилация, които използват повече памет. На системи с малко памет GCC може да излезе. В тези случаи не използвайте този флаг.
-fomit-frame-pointer
Това е много често използван флаг, предназначен да намали размера на генерирания код. Той е активиран на всички нива с префикса -O (с изключение на -O0 ) на архитектури, където не възпрепятства отстраняването на грешки (като x86-64), но може да се наложи да бъде активиран. В този случай го добавете към флаговете. Въпреки че ръководството на GCC не изброява всички архитектури, то е активирано чрез опцията -O. Трябва също изрично да активирате -fomit-frame-указател за x86-32, ако версията на GCC е под 4.6, или когато използвате -Os на x86-32 с която и да е версия на GCC. Използването на -fomit-frame-pointer обаче може да направи отстраняването на грешки трудно или дори невъзможно.
По-специално, това прави много по-трудно отстраняването на неизправности в приложения, написани на Java и компилирани в gcj, въпреки че кодът, написан на Java, не е единственият, засегнат от използването на този флаг. Така че докато използването на този флаг може да помогне, то също така прави отстраняването на грешки по-трудно; по-специално проследяването на стека би било безполезно. Ако не планирате да отстранявате грешки в програми и няма други свързани с отстраняването на грешки CFLAGS като -ggdb, опитайте да използвате -fomit-frame-pointer.
-msse, -msse2, -msse3, -mmmx, -m3dnow
Тези флагове позволяват SIMD разширенията (SSE), SSE2, SSE3, MMX и 3DNow! за x86 и x86-64 архитектури. Те се използват предимно в мултимедия, игри и други изчислителни задачи с интензивно използване на плаваща запетая, въпреки че включват и няколко други математически разширения. Тези набори от инструкции се предоставят от повечето съвременни процесори.
Често задавани въпроси за оптимизация
Но получавам по-добра производителност с -funroll-loops -fomg-optimize!
Не, хората самочувстват, че получават по-добра производителност, защото някой ги е убедил, че повече флагове е по-добре. Агресивните флагове ще навредят на приложенията само когато се използват глобално. Дори ръководството на GCC казва, че използването на опциите -funroll-loops и -funroll-all-loops може да увеличи размера на кода и времето за изпълнение. Въпреки че по някаква причина тези два флага, заедно с флаговете -ffast-math, -fforce-mem, -fforce-addr и други подобни, продължават да се използватпопулярен сред ездачите, които искат да повишат чувството си за собствена значимост.
Истината е, че това са изключително агресивни знамена. Разгледайте форумите на Gentoo и Bugzilla, за да видите какво могат да направят тези флагове: нищо добро!
Не е необходимо да използвате тези флагове глобално, в променливите CFLAGS и CXXFLAGS. Те само ще влошат производителността. Може да изглежда, че ще направят системата по-производителна и най-модерна, но те не правят нищо, освен да раздуват кода и да карат вашите доклади за грешки да бъдат маркирани като НЕВАЛИДНИ или WONTFIX.
Какво ще кажете за нивата на оптимизация -O по-големи от 3?
Някои потребители се хвалят с дори по-добрата производителност, постигната чрез използване на -O4, -O9 и т.н., но в действителност нивата на -O, по-големи от 3, нямат ефект. Компилаторът може да приеме CFLAGS променливи като -O4, но всъщност не прави нищо с тях. Той извършва само оптимизации до -O3 и нищо друго:
Нуждаете се от повече доказателства? Разгледайте изходния код:
Както можете да видите, всяка стойност, по-голяма от три, се третира като -O3.
Какво ще кажете за компилиране на нецелева машина?
Какво ще кажете за излишните флагове?
Често променливите CFLAGS и CXXFLAGS, които са разрешени на различни -O нива, са излишни в /etc/portage/make.conf. Понякога това се прави поради незнание, но и за да се избегне филтриране или заместване на флагове.
Филтрирането/подмяната на флаг се използва в много от електронните компилации, намиращи се в дървото на Portage. Това обикновено се прави, защото пакетите не се компилират на определени -O нива или когато изходният код е много чувствителен към използването на допълнителни флагове. ebuild-файл или филтрира някои или всички променливи CFLAGS и CXXFLAGS, или може да замени -O с друго ниво.
Ръководството за разработчици на Gentoo описва в общи линии къде и как работи филтрирането/подмяната на флагове.
Възможно е да се заобиколи филтрирането на ниво -O чрез излишно изброяване на флагове за конкретно ниво, като -O3, като се правят неща като:
Въпреки това,това не е най-умното нещо, което трябва да направите. CFLAGS се филтрират с причина! Когато флаговете се филтрират, това означава, че не е безопасно да се изгради пакет с тези флагове. Очевидно енебезопаснода компилирате цялата система с -O3, ако някои от флаговете, разрешени на това ниво, биха причинили проблеми с определени пакети. Затова не се опитвайте данадхитритеразработчиците, които поддържат тези пакети.Доверете се на разработчиците. Филтрирането и подмяната на флагове се извършват, за да се гарантира стабилност на системата и приложението! Ако файлът ebuild указва алтернативни флагове, тогава не се опитвайте да заобиколите това.
Създаването на пакети с невалидни флагове вероятно ще причини проблеми. Когато създавате доклад за грешка в Bugzilla, флаговете, зададени във файла /etc/portage/make.conf, са ясно видими и разработчиците пак ще ви помолят да изградите отново пакета без тези флагове. За да избегнете необходимостта от повторно изграждане, не използвайте тези флагове първоначално. Не трябва автоматично да приемате, че сте по-информирани от разработчиците.
Какво ще кажете за LDFLAGS?
Разработчиците на Gentoo вече са задали прости, сигурни LDFLAGS в базовите профили, така че няма нужда да ги променяте.
Мога ли да използвам флагове за отделни пакети?
Информация за използването на променливи на обкръжението на базата на пакет по пакет (включително CFLAGS ) е описана в наръчника на Gentoo, „Променливи на обкръжениетоза отделни пакети.
Вижте също
- Задаване на опции за компилиране (AMD64 Ръководство)
Външни ресурси
Следните източници могат да бъдат полезни за по-нататъшно научаване на оптимизацията: