Профилирование в GCC (fprofile-generate, fprofile-use, fprofile-dir)

Sabayon, Calculate, Funtoo, Exherbo

Модератор: /dev/random

Аватара пользователя
Eronex
Сообщения: 106
ОС: Ubuntu

Профилирование в GCC

Сообщение Eronex »

Профилирование в GCC
Рассмотрено профилирование двух программ, наиболее интенсивно утилизирующих процессорные ресурсы на моём домашнем компьютере. У других людей область задач может отличаться от моей, причём на столько, что профилировщик использовать либо невозможно, либо нецелесообразно. Например попытки профилировать библиотеку «QT» и «XULRunner» пока что заканчивались провалом.
Цель документа -- собрать воедино разбросанную по кусочкам информацию о профилировании при помощи GCC и получить конкретный результат. Хотя бы минимальный результат, на котором уже можно строить дальнейшие эксперименты... и, в идеале, может быть даже влиять на дальнейшее развитие профилировщика и профилируемость программ.

Исходные файлы

Дополнение среды (environment)

Код: Выделить всё

# cat /home/eronex/profiler
pre_pkg_setup() {
 local x

 if hasq generate $PROFILER; then
  elog "bashrc is adding \"-fprofile-dir=/var/tmp/fprofile_dir_data/$PN -fprofile-generate -fprofile-correction\" to CFLAGS and CXXFLAGS for $PN"
  CFLAGS="$CFLAGS -fprofile-dir=/var/tmp/fprofile_dir_data/$PN -fprofile-generate -fprofile-correction"
  CXXFLAGS="$CFLAGS"
 fi
 if hasq use $PROFILER; then
  elog "bashrc is adding \"-fprofile-dir=/var/tmp/fprofile_dir_data/$PN -fprofile-use -fprofile-correction -Wcoverage-mismatch\" to CFLAGS and CXXFLAGS for $PN"
  CFLAGS="$CFLAGS -fprofile-dir=/var/tmp/fprofile_dir_data/$PN -fprofile-use -fprofile-correction -Wcoverage-mismatch"
  CXXFLAGS="$CFLAGS"
 fi
}
Это надстройка, выполняющаяся в зависимости от значения переменной окружения «PROFILER» Если она пустая, то программа компилируется стандартно; если же в ней значение «generate» или «use», то программа компилируется: для генерации статистики, либо с учётом статистики соответственно. На этот файл в дальнейшем будут ссылаться символические ссылки со специально сформированным именем.

Разрешение на профилирование
Необходимо создать символические ссылки с именами профилируемых программ на файл «profiler». Например для p7zip, flac и libogg пути будут выглядеть следующим образом:

Код: Выделить всё

# find -L /etc/portage/env/ -type f
/etc/portage/env/app-arch/p7zip
/etc/portage/env/media-libs/libogg
/etc/portage/env/media-libs/flac
Все эти файлы являются символическими ссылками на «/home/eronex/profiler». Путь к файлу «profiler» может быть другим, в зависимости от расположения этого файла.

Место скопления статистики
Вот здесь: «/var/tmp/fprofile_dir_data/». Необходимо создать каталог и дать ему «полные» права:

Код: Выделить всё

# chmod -v ugo+rwx /var/tmp/fprofile_dir_data/
права доступа «/var/tmp/fprofile_dir_data/» оставлены как 0777 (rwxrwxrwx)
Там же должен быть скрипт, расширяющий права после первой компиляции программы, чтобы потом при запуске «от пользователя» профилируемая программа могла заполнить созданный root'ом каталог своими статистическими данными:

Код: Выделить всё

# cat /var/tmp/fprofile_dir_data/rights.sh
#!/bin/bash

chown -Rv eronex:users /var/tmp/fprofile_dir_data/


Способ применения

Профилирование «flac»
Сначало необходимо скомпилировать программу так, чтобы по окончанию работы она сохраняла статистику:

Код: Выделить всё

PROFILER="generate" emerge -1v flac libogg
/var/tmp/fprofile_dir_data/rights.sh
Вторая строчка -- это изменение владельца у файлов, созданных root'ом при компиляции программы в режиме «generate». Изменяется владелец так, чтобы он соответствовал тому, который будет запускать программу для последующего накопления статистики.
Далее необходимо поиспользовать FLAC, чтобы накопить статистику в «/var/tmp/fprofile_dir_data/flac/» и «/var/tmp/fprofile_dir_data/libogg/». В результате список файлов должен быть похожим на этот:

Код: Выделить всё

# find /var/tmp/fprofile_dir_data/flac/
/var/tmp/fprofile_dir_data/flac/
/var/tmp/fprofile_dir_data/flac/vorbiscomment.gcda
/var/tmp/fprofile_dir_data/flac/utils.gcda
/var/tmp/fprofile_dir_data/flac/main.gcda
/var/tmp/fprofile_dir_data/flac/getopt1.gcda
/var/tmp/fprofile_dir_data/flac/getopt.gcda
/var/tmp/fprofile_dir_data/flac/.libs
/var/tmp/fprofile_dir_data/flac/.libs/utf8.gcda
/var/tmp/fprofile_dir_data/flac/.libs/replaygain_analysis.gcda
/var/tmp/fprofile_dir_data/flac/.libs/ogg_helper.gcda
/var/tmp/fprofile_dir_data/flac/.libs/md5.gcda
/var/tmp/fprofile_dir_data/flac/.libs/stream_encoder.gcda
/var/tmp/fprofile_dir_data/flac/.libs/format.gcda
/var/tmp/fprofile_dir_data/flac/.libs/iconvert.gcda
/var/tmp/fprofile_dir_data/flac/.libs/lpc.gcda
/var/tmp/fprofile_dir_data/flac/.libs/bitmath.gcda
/var/tmp/fprofile_dir_data/flac/.libs/memory.gcda
/var/tmp/fprofile_dir_data/flac/.libs/picture.gcda
/var/tmp/fprofile_dir_data/flac/.libs/fixed.gcda
/var/tmp/fprofile_dir_data/flac/.libs/stream_encoder_framing.gcda
/var/tmp/fprofile_dir_data/flac/.libs/window.gcda
/var/tmp/fprofile_dir_data/flac/.libs/bitreader.gcda
/var/tmp/fprofile_dir_data/flac/.libs/replaygain.gcda
/var/tmp/fprofile_dir_data/flac/.libs/crc.gcda
/var/tmp/fprofile_dir_data/flac/.libs/bitwriter.gcda
/var/tmp/fprofile_dir_data/flac/.libs/ogg_encoder_aspect.gcda
/var/tmp/fprofile_dir_data/flac/.libs/metadata_iterators.gcda
/var/tmp/fprofile_dir_data/flac/.libs/stream_decoder.gcda
/var/tmp/fprofile_dir_data/flac/.libs/cpu.gcda
/var/tmp/fprofile_dir_data/flac/.libs/seektable.gcda
/var/tmp/fprofile_dir_data/flac/.libs/cuesheet.gcda
/var/tmp/fprofile_dir_data/flac/.libs/file.gcda
/var/tmp/fprofile_dir_data/flac/.libs/replaygain_synthesis.gcda
/var/tmp/fprofile_dir_data/flac/.libs/ogg_decoder_aspect.gcda
/var/tmp/fprofile_dir_data/flac/.libs/metadata_object.gcda
/var/tmp/fprofile_dir_data/flac/conftest.gcda
/var/tmp/fprofile_dir_data/flac/decode.gcda
/var/tmp/fprofile_dir_data/flac/encode.gcda
/var/tmp/fprofile_dir_data/flac/foreign_metadata.gcda
/var/tmp/fprofile_dir_data/flac/local_string_utils.gcda
/var/tmp/fprofile_dir_data/flac/analyze.gcda

# find /var/tmp/fprofile_dir_data/libogg/
/var/tmp/fprofile_dir_data/libogg/
/var/tmp/fprofile_dir_data/libogg/.libs
/var/tmp/fprofile_dir_data/libogg/.libs/framing.gcda
/var/tmp/fprofile_dir_data/libogg/.libs/bitwise.gcda
/var/tmp/fprofile_dir_data/libogg/conftest.gcda
Заключительный этап -- это применение статистики, накопленной при использовании программы. Чтобы её применить, нужно повторно скомпилировать программу, изменив параметры компиляции:

Код: Выделить всё

PROFILER="use" emerge -1v flac libogg
Наслаждайтесь скоростью ;)

Профилирование «p7zip»
Алгоритм тот же самый, разве что не создаются статистические файлы непосредственно после компиляции в режиме «generate». Тем не менее при последующем запуске статистические данные сливаются и наблюдается ускорение при использовании архиватора после компиляции в режиме «use».

Результаты
Это, наверное, самая сочная часть :)
Характеристики компьютера: Athlon64 3000+; DDR PC3200 1ГБ; Gentoo AMD64, профиль «no-multilib»; GCC 4.4.4; флаги компиляции стандартные: «-march=athlon64-sse3 -O2 -pipe --param l1-cache-line-size=64 --param l1-cache-size=64 --param l2-cache-size=512»

flac
Измерения для flac'а проводились на цикле распаковки и упаковки альбома с параметром «--best». И вот результат:
Режим «стандартный»:
real 2m23.445s 2m20.613s
user 2m14.810s 2m14.430s
sys 0m3.120s 0m3.350s
Режим «use»:
real 2m8.127s 2m6.636s
user 1m58.140s 1m57.760s
sys 0m3.540s 0m3.730s
Профит:
((((2*60+14.810)+(2*60+14.430))/2)-(((1*60+58.140)+(1*60+57.760))/2))/(((2*60+14.810)+(2*60+14.430))/2)*100%=12.38%
12% -- это серьёзно! :)

p7zip
Ускорение p7zip измерялось подобным образом -- цикл распаковки/упаковки разнородных архивов с параметром «-mx=7»:
Режим «стандартный»:
real 0m47.601s 0m47.982s 0m47.751s
user 0m46.270s 0m46.360s 0m46.070s
sys 0m1.200s 0m1.210s 0m1.310s
Режим «use»:
real 0m45.881s 0m45.907s 0m48.812s
user 0m44.660s 0m44.630s 0m44.580s
sys 0m1.090s 0m1.150s 0m1.060s
Профит:
(((46.270+46.360+46.070)/3)-((44.660+44.630+44.580)/3))/((46.270+46.360+46.070)/3)*100%=3.48%
В данном случае ускорение не большое, но оно реальное, оно ощутимое и оно есть! :)

Мысли
Реально доступным профилирование стало с выходом компилятора версии 4.4.4, потому что именно в этой версии появилась команда «-fprofile-dir», с помощью которой стало возможным указывать отдельные каталоги скопления статистики для разных програм. А теперь ещё версия 4.4.4 в стабильной ветке Gentoo! :)
«CXXFLAGS» тоже необходимо дополнить командами профилировщика наравне с «CFLAGS». Это утверждение нашло подтверждение в профилировании «p7zip», так как исходный код архиватора состоит в основном из кода на C++.
«-lgcov» не нужен! GCC сам выполняет необходимые действия при линковке объектных файлов, предназначенных для профилирования. Пруф-линк не дам, но утверждение очевидно из выше удавшихся экспериментов и неудавшемся с «qt-core», где «-lgcov» в «LDFLAGS» никак не спасает.
«-fprofile-correction» и «-Wcoverage-mismatch». Вторая команда избавляет от вылета из процесса компиляции при ошибке «несовпадение контрольных сумм исходников», эти ошибки становятся обычными предупреждениями (вместо «error» теперь «warning»). Первая команда («-fprofile-correction») тоже избавляет от ошибки, возникающей в профилировании многопоточных приложений. Конкретнее про эти две команды можно посмотреть в «man gcc». Первую и вторую добавить, возникла необходимость во время профилирования p7zip. Единственным осталось непонятно, почему всё-таки пришлось использовать «-fprofile-correction», ведь архиватор был запущен в один поток на одноядерном процессоре...
Спасибо сказали:
Аватара пользователя
megabaks
Сообщения: 697
ОС: Gentoo ~x86

Re: Профилирование в GCC

Сообщение megabaks »

а я сделал так

Код: Выделить всё

#PGO
PROFILE_GEN="$CFLAGS -fprofile-generate -ftest-coverage -fprofile-dir=/var/tmp/PGO/$CATEGORY/$PF"
PROFILE_USE="$CFLAGS -fprofile-use -fprofile-correction -Wcoverage-mismatch -fprofile-dir=/var/tmp/PGO/$CATEGORY/$PF"

if [ -f /etc/portage/package.pgo ]; then
while read -a target; do
    if [ "${target}" = "${CATEGORY}/${PN}" ]; then
      if [ -d "/var/tmp/PGO/$CATEGORY/$PF" ]; then
        if [ "$count" != "1" ]; then
              if [ "$countt" != "1" ]; then export CFLAGS="$PROFILE_USE" && export CXXFLAGS="$PROFILE_USE" && export MAKEOPTS="-j1" && export countt="1"
              fi
        fi
   else
      if [ "$count" != "1" ]; then
        if [ "$countt" != "1" ]; then export CFLAGS="$PROFILE_GEN" && export CXXFLAGS="$PROFILE_GEN" && export MAKEOPTS="-j1" && export count="1"
        fi
      fi
fi
fi
done < /etc/portage/package.pgo
fi
Спасибо сказали:
Аватара пользователя
vr13
Сообщения: 885
ОС: gentoo

Re: Профилирование в GCC

Сообщение vr13 »

интересно, но кажется, применимо только к своему (или очень знакомому) коду. в общем случае пробраться через все autoconf/cmake к makefiles и пытаться установить в нужных местах обращения к libgcov.a практически невозможно: для интереса попытался отпрофайлить libbz2 (app-arch/bzip2) - за 2 часа ниасилил :)
Спасибо сказали:
Аватара пользователя
Eronex
Сообщения: 106
ОС: Ubuntu

Re: Профилирование в GCC

Сообщение Eronex »

megabaks писал(а):
14.02.2011 21:52
а я сделал так

Код: Выделить всё

#PGO
PROFILE_GEN="$CFLAGS -fprofile-generate -ftest-coverage -fprofile-dir=/var/tmp/PGO/$CATEGORY/$PF"
PROFILE_USE="$CFLAGS -fprofile-use -fprofile-correction -Wcoverage-mismatch -fprofile-dir=/var/tmp/PGO/$CATEGORY/$PF"

if [ -f /etc/portage/package.pgo ]; then
while read -a target; do
    if [ "${target}" = "${CATEGORY}/${PN}" ]; then
      if [ -d "/var/tmp/PGO/$CATEGORY/$PF" ]; then
        if [ "$count" != "1" ]; then
              if [ "$countt" != "1" ]; then export CFLAGS="$PROFILE_USE" && export CXXFLAGS="$PROFILE_USE" && export MAKEOPTS="-j1" && export countt="1"
              fi
        fi
   else
      if [ "$count" != "1" ]; then
        if [ "$countt" != "1" ]; then export CFLAGS="$PROFILE_GEN" && export CXXFLAGS="$PROFILE_GEN" && export MAKEOPTS="-j1" && export count="1"
        fi
      fi
fi
fi
done < /etc/portage/package.pgo
fi

Ещё один вариант -- это есть хорошо.


vr13 писал(а):
25.02.2011 00:17
интересно, но кажется, применимо только к своему (или очень знакомому) коду. в общем случае пробраться через все autoconf/cmake к makefiles и пытаться установить в нужных местах обращения к libgcov.a практически невозможно: для интереса попытался отпрофайлить libbz2 (app-arch/bzip2) - за 2 часа ниасилил :)

Да, не всё профайлится.

В каком месте обычно фильтры для gcc-флагов у программ? Очень хочется профильнуть Qt! Ведь там код на C++ :)
Спасибо сказали:
Аватара пользователя
megabaks
Сообщения: 697
ОС: Gentoo ~x86

Re: Профилирование в GCC

Сообщение megabaks »

чуть поправил

Код: Выделить всё

#PGO
PGO_DIR="/var/tmp/PGO"

PROFILE_GEN="${CFLAGS} -fprofile-generate -ftest-coverage -fprofile-dir=${PGO_DIR}/${CATEGORY}/${PF}"
PROFILE_USE="${CFLAGS} -fprofile-use -fprofile-correction -Wcoverage-mismatch -fprofile-dir=${PGO_DIR}/${CATEGORY}/${PF}"

if [ -f /etc/portage/package.pgo ]; then
while read -a target; do
    if [ "${target}" = "${CATEGORY}/${PN}" ]; then
      if [ -d "${PGO_DIR}/${CATEGORY}/${PF}" ]; then
        if [ "$count" != "1" ]; then
              if [ "$countt" != "1" ]; then export CFLAGS="${PROFILE_USE}" && export CXXFLAGS="${PROFILE_USE}" && export MAKEOPTS="-j1" && export countt="1"
              fi
        fi
   else
      if [ "$count" != "1" ]; then
        if [ "$countt" != "1" ]; then export CFLAGS="${PROFILE_GEN}" && export CXXFLAGS="${PROFILE_GEN}" && export MAKEOPTS="-j1" && export count="1"
        fi
      fi
fi
fi
done < /etc/portage/package.pgo
chmod -R ugo+rwx ${PGO_DIR}
fi
Спасибо сказали:
Аватара пользователя
vr13
Сообщения: 885
ОС: gentoo

Re: Профилирование в GCC

Сообщение vr13 »

вдруг обнаружил, что pgo появился флагом в firefox-6, соответственно весь процесс profile-generate/profile-use засунут в ebuild. теперь, согласно браузерной пузомерке, firefox выглядит вполне достойно на фоне конкурентов:

pgo дал примерно 13% прироста производительности
У вас нет необходимых прав для просмотра вложений в этом сообщении.
Спасибо сказали: