Подготовка к портежам-2. Вопросы оптимизации

Алексей Федорчук
[email protected]

Переменная USE - эффективный способ настройки Gentoo под задачи пользователя. Однако редактированием файла /etc/make.conf можно добиться большего - задать глобально условия компиляции. То есть, по простому говоря, те флаги компилятора gcc, которые при ручной сборке программ обычно задаются в командной строке утилиты make.

Рассмотрение флагов компилятора gcc само по себе далеко выходит за рамки этой заметки (см. библиографию). Наша сегодняшняя цель сугубо практическая - добиться наибольшей оптимизации как базовой системы, так и всех компилируемых приложений под конкретное железо, благо текущая (3.2.x) версия gcc позволяет сделать это для любых процессоров.

Итак, возвращаемся к файлу /etc/make.conf, в котором видим три строки, описывающие флаги компиляции. По умолчанию, в свежеустановленной из тарбаллов, системе они имеют вид вроде:

CHOST='i686-pc-linux-gnu'
CFLAGS='-march=pentium4 -mcpu=pentium4 -O3 -pipe'
CXXFLAGS='-march=pentium4 -mcpu=pentium4 -O3 -pipe'

Первая строка определяет архитектуру хост-машины, то есть компьютера, на котором компиляция выполняется. А поскольку, если иное не указано явным образом, тип целевой машины принимается совпадающим с хостом, то характеризует и компьютер, для которого компилируется система. Исключение - случаи кросс-платформенной компиляции, тогда и host, и target нужно определять отдельно. С типом все просто - для всех процессоров от PentiumPro и выше (включая Athlon'ы разного рода и Pentium4) строка по умолчанию отражает действительность. Для Pentium просто здесь следовало бы поставить

CHOST='i586-pc-linux-gnu'

и так далее, но собирать на таких машинах Gentoo - занятие весьма скучное.

А следующие две строки и содержат флаги, определяющие условия оптимизации для неких процессоров. Верхняя из них действенна для сборки исходников на Си просто, нижняя - для Си++.

Рассмотрим эти флаги в обратном обычному порядке (справа налево). Флаг -pipe предписывает использовать при компиляции т.н. программные каналы вместо временных файлов для передачи данных между разными стадиями компиляции. Насколько я понимаю, она не влияет на быстродействие генерируемого кода, но способствует ускорению самого процесса компиляции. И, следовательно, не лишней не будет.

Флаг -O# задает собственно уровень оптимизации - от самого низшего, O (или O1, что идентично) до высшего - O3 (уровень O0 означает отсутствие всякой оптимизации). Собственно, каждый из этих флагов - некая совокупность опций, способствующих быстродействию сгенерированного кода, но для нас это не существенно.

Как можно видеть, по умолчанию в Gentoo предписывается самый высокий уровень оптимизации (O3). С чем трудно не согласиться - какой же русский не любит быстрой езды. Правда, у быстрой езды есть оборотная сторона - теоретически рассуждая, не каждое приложение (особенно тех, код которых в основном написан достаточно давно) обязано собираться при высшей степени оптимизации.

Не будучи программером, не могу сказать, каким образом решается эта проблема в Gentoo. Но факт остается фактом: абсолютно все требующиеся мне программы собирались благополучно при флаге -O3. Типичный пример - оконная система X. Сколько я ни пытался собирать вручную первозданный (с http://www.xfree86.org) ее исходник с флагом -O3 - рано или поздно, но регулярно получал сообщение об ошибке. А из Gentoo-портежей - компилируется без сучка, без задоринки, и при еще более жестких условиях оптимизации. Не для того ли существуют Gentoo-специфичные патчи? Буду признателен за разъяснение от профессионалов.

Так что смело оставляем умолчальный флаг -O3 и переходим к двум следующим. Смысл их близок и сводится к указанию конкретного процессора, под который производится сборка. В качестве значения обоих флагов могут выступать (в gcc 3.2 и выше, и не выходя за пределы PC-архитектуры) абсолютно все Intel-совместимые процессоры, от i386, K6, Duron до Athlon-XP, -MP и Pentium4. Полный список поддерживаемых камней можно посмотреть в комментариях к файлу /etc/make.conf или, еще лучше - на man (1) gcc.

В чем различие флагов -march и -mcpu? Первый генерирует код с учетом особенностей указанного процессора, без возможности запуска на более младших моделях. Второй делает то же самое, но сохраняет совместимость с братьями меньшими. То есть при сборке системы на настольной машине и для нее же представляется избыточным. Так что в реальности можно ограничиться указанием лишь -march=модель.

В принципе, этими тремя флагами можно и ограничиться. Однако на freehackers.org можно обнаружить страничку, специально посвященную флагам оптимизации для дистрибутива Gentoo (к слову замечу, что указанный сайт функционирует под управлением именно этого дистрибутива). Так вот, там в числе безопасных (safe) приведен, причем для всех типов процессоров, еще один флаг - -fomit-frame-pointer. Не возьмусь объяснять точное его значение, но из классического описания Ричарда Столлмана (см. библиографию) можно понять, что его наличие способствует исключению некоторых необязательных команд и таким образом также способствует быстродействию. Так что, вероятно, пренебрегать им не следует.

В итоге строки с gcc=флагами оптимизации для Pentiun4 примут следующий вид:

CFLAGS="-march=pentium4 -O3 -pipe -fomit-frame-pointer"
CXXFLAGS="-march=pentium4 -O3 -pipe -fomit-frame-pointer"

Каковой и можно принять как оптимальный в обычных условиях. В случае реликтового (по цене, но не по производительности) Pentium-III, значение -march= следует изменить на pentium3, для Athlon разных видов - на athlon (athlon-tbird, athlon-xp, athlon-mp), и так далее.

На том же freehackers.org можно обнаружить предложения и более жесткой оптимизации, а именно - указание флагов -ffast-math (оптимизация с нарушением некоторых правил ANSI и IEEE), -fforce-addr, -funroll-loops и некоторые другие. За отсутствием собственного опыта, не могу ничего сказать об их действенности. Но то, что они не отнесены к safe-флагам, говорит, что использовать их следует осторожно. И не особо удивляться, получив сообщение об ошибке после пары часов сборки какого-либо тяжелого приложения.

Библиография вопроса

Прежде чем приступать к оптимизации, очень не вредно почитать вводную часть классического труда Ричарда Столлмана сотоварищи "Компилятор GNU CC", русский перевод которого можно найти на многих сайтах с подборками документации, например, на Linux.Yaroslavl. А конкретные рекомендации применительно к сборке Gentoo-портежей есть, как уже было сказано, на двух страницах freehackers.org, первая из которых посвящена безопасным флагам, а вторая - сильно оптимизирующим.

Спасибо участнику Gentoo-форума universal'у за приведенные выше ссылки. Буду также благодарен за все примеры конкретного применения всяких сильно оптимизирующих флагов.