Archiwa tagu: wydajność

Profilowanie kompilowanych binarek w Gentoo

Gcc, najczęściej używany kompilator w Gentoo (czy ktoś zna inne kompilatory, którymi da się skompilować system dający uruchomić się?) posiada możliwość profilowania kompilowanego kodu. Wykorzystując wcześniej przygotowane dane, stara się on utworzyć kod wykonywalny, który teoretycznie[1] powinien działać szybciej niż kod nieprofilowany.

Odpowiednie flagi gcc to -fprofile-generate oraz -fprofile-use. Program skompilowany z flagą -fprofile-generate będzie tworzył pliki .gcda w katalogu roboczym. Takie tworzenie plików „gdziekolwiek” nie jest zwykle pożądane, lepiej aby te pliki były generowane w określonej lokalizacji. Pomocą służy nam opcja -fprofile-dir= z której pomocą możemy wskazać katalog w którym będą tworzone pliki *.gcda . Musimy jednak wiedzieć, że ta flaga pojawiła się w GCC dopiero od wersji 4.4.0 .
Wiemy już w jaki sposób możemy możemy wybrać miejsce w którym będą tworzone pliki potrzebne do profilowania. Krok do przodu i kolejny problem, czyli możliwość wystąpienia kolizji. Częstą sytuacją jest, że pliki źródłowe mają taką samą nazwę w różnych pakietach. Dobrym rozwiązaniem wydaje się być utworzenie podkatalogów o nazwie tworzonej na podstawie nazwy pakietu. I co? Może mamy dla każdego pakietu zmieniać flagę -fprofile-dir=/sciezka/do/gcda/nazwa_pakietu ? Jest to trochę mało wygodne.
Ciekawe rozwiązanie znalazłem na rosyjskojęzycznym forum dotyczącym Gentoo, użytkownicy stworzyli modyfikacje do helpera o nazwie emake. Cała „obsługa” sprowadza się do ewentualnego ustawienia katalogu bazowego dla plików .gcda , a wybór czy tego czy binarka ma być skompilowana tradycyjnie, z opcją aby tworzyła pliki profilowe lub skompilowana z użyciem tychże plików dokonywany jest poprzez zmienną FEATURES.
Podczas testowania tego rozwiązania natrafiłem na problem, make dosyć często ignorował CFLAGS ustawione jako zmienne środowiskowe (kwestia budowy Makefile?), użycie make w następujący sposób: make CFLAGS=fprofile-use uznaję za zbyt inwazyjne, nadpisuje flagi użytkownika oraz wprowadza flagi, które mogły być usunięte przez ebuild (filter-flags). Uznałem, że lepiej będzie gdy dodatkowe flagi będą dodane do istniejących zanim będzie pakiet konfigurowany (zazwyczaj przed słynnym ./configure). Niektóre pakiety (np.bzip2) nie mają w ogóle fazy src_configure() dlatego umieściłem  ten kod w src_unpack().  Dzięki temu CFLAGI zostaną, z pomocą configure, prawidłowo umieszczone w Makefile. Najlepszym miejscem do modyfikacji portage wydaje się mi plik /usr/lib/portage/bin/ebuild.sh. Dokonałem kilku drobnych zmian do oryginalnego rozwiązania, plik różnicowy wygląda tak:

--- ebuild.sh.orig      2010-09-03 14:23:46.000000000 +0200
+++ ebuild.sh   2010-09-03 14:44:29.400038418 +0200
@@ -453,6 +453,33 @@
 # should be preserved.
 find . -mindepth 1 -maxdepth 1 ! -type l -print0 | \
 ${XARGS} -0 chmod -fR a+rX,u+w,g-w,o-w
+
+       # New implementation with profiling on compilation support
+       # source "${PORTAGE_BIN_PATH}/isolated-functions.sh"  &>/dev/null
+       PROFILE_DIR="${PROF_DIR:-/var/tmp/profile}"
+       PROFILE_SUBDIR="${PROFILE_DIR}/${CATEGORY}/${PF}"
+       GCC_VERSION=$(gcc --version | awk '{print $3;exit}')
+       if has profile ${FEATURES} ; then
+                       if [[ ${GCC_VERSION} < 4.4.0 ]]; then
+                               ewarn "\nGCC version is too old to use compilation with profile usage."
+                               ewarn "GCC 4.4.0 or higher required."
+                               ewarn "Falling back to compilation w/o profile usage.\n"
+                       elif has profile-use ${FEATURES} ; then
+                               if [[ -d ${PROFILE_SUBDIR} ]] ; then
+                                       einfo "\nCompiling with profiling data usage.\n"
+                                       CFLAGS+=" -fprofile-use -fprofile-dir=${PROFILE_SUBDIR} -Wcoverage-mismatch -fprofile-correction"
+                                       CXXFLAGS="${CFLAGS}"
+                               else
+                                       ewarn "\nNo directory with profiling data. Did you run fist stage and then program itself?\n"
+                               fi
+                       else
+                               einfo "\nCompiling with profiling data gathering support.\n"
+                               mkdir -m 777 -p "${PROFILE_SUBDIR}"
+                               CFLAGS+=" -fprofile-generate -fprofile-dir=${PROFILE_SUBDIR}"
+                               CXXFLAGS="${CFLAGS}"
+                               LDFLAGS+=" -fprofile-arcs"
+                       fi
+       fi
 }

 strip_duplicate_slashes() {

Alternatywą jest pobranie pliku-patcha z adresu: http://repoz.mejor.pl/svn/gentoo/distfiles/ebuild-2.1.8.3-profile.patch.
Lista nowych opcji jakie możemy ustawić w /etc/make.conf:
PROFILE_DIR=< ścieżka do katalogu, poniżej którego będę tworzone pliki profilujące>, domyślna wartość to /var/tmp/profile
W FEATURES można ustawić:
profile – kompilacja z ustawieniem flagi aby tworzyć pliki służące profilowaniu
profile-use – kompilacja z użyciem plików profilujących, aby ta flaga działała musi być również ustawiona opcja profile

To co? Wszystko jest omówione? A co jeśli program zostanie uruchomiony najpierw przez roota, a potem zwykły śmiertelnik będzie chciał także go uruchomić? Wtedy dostanie listę komunikatów z serii permission denied dla wszystkich plików .gcda , i tyle byłoby z profilowania.
Rozwiązałem to z użyciem ACL, czyli musimy pamiętać aby partycja, na której będę zbierane te pliki (nie są duże) była zamontowana z obsługą ACL.
# getfacl profile/
# file: profile/
# owner: root
# group: root
user::rwx
group::rwx
other::rwx
default:user::rwx
default:group::rwx
default:other::rwx

Tak nadajemy te uprawnienia:
setfacl -d -m g::rwx /var/tmp/profile
setfacl -d -m o::rwx /var/tmp/profile
setfacl -m g::rwx /var/tmp/profile
setfacl -m o::rwx /var/tmp/profile

[1] – ktoś pokusi się i sprawdzi na ile takie profilowanie przyśpiesza wykonywanie programu? I zaprezentuje zarówno pozytywne jak i negatywne wyniki testów pomiarów szybkości ;)

P.S. Właśnie zauważyłem, że ta funkcja nie działa przy live ebuildach.

Firebird i Reiserfs

Głównymi bohaterami są Firebird 1.5 oraz system plików reiserfs 3.6 .

Baza danych jest pojedynczym (jak to zwykle przy firebirdzie bywa ;) ) plikiem o wielkości od 1 GB do ~5 GB. Podaje taki przedział ponieważ obserwacji dokonywałem na wielu serwerach dla baz o różnej wielkości. Partycja jest zwykle o wielkości ~15-20 GB czyli jest znacznie większa od wielkości pliku.

Sposób pracy na bazie jest klasyczny, czyli dane są dokładane i to w dosyć sporej ilości.

W efekcie już po kilku tygodniach takiej pracy, plik bazodanowej jest bardzo mocno sfragmentowany. Filefrag zgłasza od kilkudziesięciu do nawet 200-300 tysięcy „extentsów”.

W ramach testów przeszedłem na XFS, efekt? Po kilku tygodniach pracy fragmentacja dla pliku ~2GB wynosi: 3 extents. Różnica jest olbrzymia.

Planuję obserwować jak będzie to zachowywać się na EXT3 w ramach alternatywy dla XFSa. I należałoby dać chyba jeszcze szansę reiserowi i zamontować go z opcją „notail”, być może to będzie miało pozytywny wpływ.

Epilog:

Po 3 tygodniach obserwacji, baza na XFS nadal jest w 3 częściach.

Baza umieszczona na Reiserfs zamontowanego z opcją notail, po kilku dniach zwiększyła ilość swoich kawałków z ponad dwóch tysięcy do ponad czterech tysięcy.