Библиотека сайта rus-linux.net
Что каждый программист должен знать о памяти, часть 7. Инструменты для повышения производительности памяти
Оригинал: Memory part 7: Memory performance toolsАвтор: Ulrich Drepper
Дата публикации: ноябрь 2007 г.
Перевод: М.Ульянов
Дата перевода: 5 мая 2010 г.
Инструменты для повышения производительности памяти
7.4 Улучшаем прогнозирование ветвлений
В разделе 6.2.2 были упомянуты два метода улучшения работы L1i с помощью прогнозирования ветвлений и изменения порядка блоков, а именно: явное (статическое) предсказание через __builtin_expect
и оптимизацию по профилю (profile guided optimization = PGO). Правильное прогнозирование ветвлений в первую очередь влияет на производительность, но в данный момент нас интересует иное - оптимизация использования памяти.
Использовать __builtin_expect
(а лучше - макросы likely
и unlikely
) достаточно просто. Определения помещаются в центральном заголовке, и компилятор берет на себя всё остальное. Хотя есть тут небольшая проблема: программист может легко перепутать определения - использовать likely
вместо unlikely
, и наоборот. Даже если применять инструмент вроде oprofile для контроля за ошибочным прогнозированием ветвлений и промахами L1i, подобные проблемы сложно обнаружить.
Тем не менее, есть один простой способ. Листинг в разделе 9.2 демонстрирует альтернативные определения макросов likely
и unlikely
, с помощью которых прямо при выполнении программы отслеживается, верно заданы явные предсказания или же вкралась ошибка. Затем программист или тестер проверяет результаты и вносит поправки при необходимости. Производительность программы в расчет при этом не берется - просто проверяются статически заданные программистом предсказания, не более. С подробностями и исходниками можно ознакомиться в вышеупомянутом разделе.
Механизм PGO в наши дни довольно легко использовать через gcc. Процесс состоит из трех шагов, при этом необходимо соблюдать некоторые требования. Во-первых, все исходные файлы должны быть скомпилированы с дополнительным параметром -fprofile-generate
. Этот параметр должен использоваться при всех запусках компилятора и должен быть передан команде, компонующей программу. Смешивать объектные файлы, скомпилированные с применением этого параметра и без него - теоретически можно, но с последними могут возникнуть проблемы.
Компилятор создает исполняемый файл, работающий как обычно, но только он значительно больше и медленнее, поскольку записывает (и сохраняет) всю информацию о ветвлениях. Компилятор также создает файл с расширением .gcno
для каждого входного файла. Этот файл содержит информацию относительно ветвлений в коде и его нужно сохранить на будущее.
Как только исполняемый файл будет готов, следует выполнить репрезентативный набор тестов с разными рабочими нагрузками. Какая бы нагрузка не использовалась, в итоге исполняемый файл будет оптимизирован для эффективного выполнения соответствующей задачи. Неоднократные прогоны программы в пределах одного теста возможны - и, в общем, даже необходимы; каждое выполнение вносит свой вклад в итоговый выходной файл. Перед завершением работы программы данные, собранные в течение текущего прогона, записываются в файлы с расширением .gcda
, которые создаются в каталоге с исходниками. Программу можно запускать из любого каталога, исполняемый файл можно копировать, но каталог с исходниками в любом случае должен быть доступен для записи. Еще раз: для каждого входного файла исходников создается свой выходной файл. В случае нескольких прогонов важно, чтобы файлы .gcda
, созданные во время предыдущего прогона, оставались в том же каталоге с исходниками, иначе итоговые данные будет невозможно собрать в один файл.
После завершения всех тестовых прогонов программу следует перекомпилировать. Необходимо и крайне важно, чтобы файлы .gcda
оставались в том же каталоге, где находятся файлы исходников. Эти файлы нельзя перемещать, иначе компилятор их попросту не найдет, что приведет к несовпадению контрольных сумм. При повторной компиляции параметр -fprofile-generate
нужно заменить на -fprofile-use
. Важно не вносить в исходники никаких изменений, могущих повлиять на генерируемый исполняемый код. Это значит: можно изменять форматирование (пробелами) и редактировать комментарии, но вот добавление новых ветвлений или блоков приводит к недействительности всей собранной информации, и компиляция в этом случае окончится неудачей.
Вот и всё, что требуется от программиста; и вправду довольно простой процесс. Самое главное, на что необходимо обратить внимание - это выбор подходящих репрезентативных тестов для сбора информации. Если тестовые нагрузки не будут совпадать с реальными будущими условиями эксплуатации программы, выполненная оптимизация принесет больше вреда чем пользы. Поэтому в общем случае трудно использовать PGO для создания библиотек, ведь они могут быть использованы в самых разных сценариях, иногда чуть ли не противоположных. В связи с этим, если нет уверенности в схожести условий использования, то обычно лучше полагаться исключительно на статическое прогнозирование ветвлений с применением __builtin_expect
.
Пара слов о файлах .gcno
и .gcda
. Это бинарные файлы, первоначально не предназначенные для просмотра. Тем не менее, при необходимости для их исследования можно применить инструмент gcov, также являющийся частью пакета gcc. В основном эта утилита применяется для анализа покрытия (coverage, отсюда и название), но при этом используется тот же формат файлов, что и для PGO. Утилита gcov генерирует выходные файлы с расширением .gcov
для каждого исходного файла с исполняемым кодом (обычно включая системные заголовки). Эти выходные файлы представляют собой листинги, аннотированные в соответствии с заданными gcov параметрами - могут быть показаны вероятности, счетчик ветвлений и т.п.
Назад | Оглавление | Вперед |