Archiwa tagu: gentoo

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.

Migracja systemu Gentoo na LVM2 na raid

Z okazji zmiany dysku na większy chciałem w ramach zyskania nowych doświadczeń przenieść system na LVMa.

Przyjąłem założenie, że LVM zostanie zainstalowany na zdegradowanym raidzie, łatwiej jest potem dołożyć nowy dysk, niż kombinować jak przenieść LVM na raida (chociaż według opisu http://akademia.linuksa.pl/readme/lvm/ nie jest to zbyt problematyczne) . Bootloader GRUB w obecnej, szeroko dostępnej wersji (~0.97) nie obsługuje LVM więc partycja /boot będzie umieszczona bezpośrednio na raidzie. Również poza LVM zostanie umieszczona root partycja czyli / . Wynika to z tego, że mam dużą niechęć do initrd , a jest on niestety niezbędny aby powstał system z główną partycją umieszczoną na LVM.

O to jak to zrobiłem to na gentoo:

( O „emerge lvm2” i „rc-update add lvm boot” nie będe wspominał ;)  )

Dysk ma pojemność 250GB, podzieliłem go na takie partycje:

Device Boot      Start         End      Blocks   Id  System
/dev/sdc1   *           1          73      586341   83  Linux
/dev/sdc2              74       30103   241215975    5  Extended
/dev/sdc5              74       13690   109378521   fd  Linux raid autodetect
/dev/sdc6           13691       29252   125001733+  fd  Linux raid autodetect
/dev/sdc7           29253       29434     1461883+  fd  Linux raid autodetect
/dev/sdc8           29435       30103     5373711   fd  Linux raid autodetect

sdc1 to będzie partycja /boot

sdc5 i sdc6 to będą partycje pod lvm

sdc7  to swap

sdc8 będzie partycją / (przeznaczyłem na nią 5.5G aby nie martwić się jak ją powiększyć,)

I na wszelki wypadek zostawiłem 2.4G wolnego miejsca. Root partycję umieściłem właśnie na końcu i po niej zostawiłem to wolne miejsce dodatkowo po to aby np. właśnie móc powiększyć tą partycję,

Zrobiłem dwie mniejsze partycje LVMowe zamiast jednej dużej, ponieważ nie jestem pewny czy nie najdzie mnie ochota zrobić raida używając mniejszych dysków znajdujących się w szufladzie.

Czytaj dalej Migracja systemu Gentoo na LVM2 na raid