Naposledy testováno na Ubuntu 20.04 s vývojovou verzí glibc 2.33.9000 (viz glibc/version.h
) dne 27. června 2021.
Jak stáhnout a sestavit glibc a spustit jeho benchmarky
Zdrojový kód glibc můžete ručně získat zde:https://www.gnu.org/software/libc/sources.html:
git clone https://sourceware.org/git/glibc.git
cd glibc
git checkout master
Zrcadlo třetí strany na GitHubu:https://github.com/bminor/glibc/tree/master/benchtests
Viz také:
- https://kazoo.ga/a-simple-tool-to-test-malloc-performance/
Pokud si někdy budete přát ručně sestavit glibc a jeho benchtesty, udělejte to následovně:
# IMPORTANT: begin AT THE SAME DIRECTORY LEVEL as the `glibc` source code
# directory, NOT inside the `glibc` source code dir! In other words, if
# you are in the correct dir, running `ls` will show the `glibc` source
# code dir (that you just cloned) inside the dir you are in.
mkdir -p glibc-build
mkdir -p glibc-install
cd glibc-build
../glibc/configure --prefix="$(realpath "../glibc-install")"
time make -j8 # build with 8 threads (jobs); on a fast laptop this takes ~3 min.
time make install # (optional: install to the `glibc-install` dir you created)
# Build the benchtests (everything inside the `glibc/benchtests` dir) too;
# see the makefile 'glibc/benchtests/Makefile' for more build commands.
time make bench-build -j8
# Now you have this executable file you can use for malloc speed tests, for instance!:
# ../glibc-build/benchtests/bench-malloc-thread
# To build **and run** all glibc benchtests, do:
time make bench
Odkazy:
- https://www.gnu.org/software/libc/manual/html_node/Configuring-and-compiling.html
- https://kazoo.ga/a-simple-tool-to-test-malloc-performance/
- https://github.com/f18m/malloc-benchmarks/blob/master/Makefile#L122-L129 :Hodně jsem se toho naučil při studiu tohoto cíle makefile:
$(glibc_install_dir)/lib/libc.so.6: @echo "Building GNU libc... go get a cup of coffee... this will take time!" mkdir -p $(glibc_build_dir) cd $(glibc_build_dir) && \ ../glibc/configure --prefix=$(glibc_install_dir) && \ make $(parallel_flags) && \ make install [ -x $(glibc_build_dir)/benchtests/bench-malloc-thread ] && echo "GNU libc benchmarking utility is ready!" || echo "Cannot find GNU libc benchmarking utility! Cannot collect benchmark results"
- Jak zkompilovat vlastní standardní knihovnu glibc C ze zdroje a použít ji?
Klíčová slova:jak sestavit a spustit glibc a jeho benchtesty, vč. benchtesty malloc, ze zdroje; sestavte glibc ze zdroje na linux ubuntu
Makefile
bude existovat ve vašem build-glibc
pokud je configure
skript úspěšně skončí.
Pokud se vše zdá během configure
proběhly hladce a stále žádné Makefile
, pak vám pravděpodobně unikla výstřednost:
Při provádění configure
pro glibc se očekává, že normálně poskytnete alternativní --prefix
, protože instalace do výchozího umístění (/usr/local
) může potenciálně ochromit systém. Pokud žádný nezadáte, musíte zapnout --disable-sanity-checks
.
Pokud ani toto není tento případ, vyhledejte config.log
a přečtěte si jeho obsah.
Nastavení 1:glibc bez vyhrazeného GCC
Toto nastavení může fungovat a je rychlé, protože nepřekompiluje celý nástroj GCC, pouze glibc.
Jediný problém, který mám s tímto nastavením, je ten, že jsem nenašel pěkný způsob, jak používat runtime objekty, jako je crt1.o
, crti.o
a crtn.o
poskytuje náš glibc a já zatím používám hostitelské. Toto je zmíněno na:https://sourceware.org/glibc/wiki/Testing/Builds?action=recall&rev=21#Compile_against_glibc_in_an_installed_location Tyto objekty provádějí brzké nastavení, na které se glibc spoléhá, takže bych nebyl překvapen, kdyby se věci zhroutily v úžasném a úžasně rafinovanými způsoby. Viz pokusy o vyřešení níže.
Sestavte glibc a nainstalujte lokálně:
git clone git://sourceware.org/git/glibc.git
cd glibc
git checkout glibc-2.32
mkdir build
cd build
export glibc_install="$(pwd)/install"
../configure --prefix "$glibc_install"
make -j `nproc`
make install -j `nproc`
Nastavení 1:ověřte sestavení
test_glibc.c
#define _GNU_SOURCE
#include <assert.h>
#include <gnu/libc-version.h>
#include <stdatomic.h>
#include <stdio.h>
#include <threads.h>
atomic_int acnt;
int cnt;
int f(void* thr_data) {
for(int n = 0; n < 1000; ++n) {
++cnt;
++acnt;
}
return 0;
}
int main(int argc, char **argv) {
/* Basic library version check. */
printf("gnu_get_libc_version() = %s\n", gnu_get_libc_version());
/* Exercise thrd_create from -pthread,
* which is not present in glibc 2.27 in Ubuntu 18.04.
* https://stackoverflow.com/questions/56810/how-do-i-start-threads-in-plain-c/52453291#52453291 */
thrd_t thr[10];
for(int n = 0; n < 10; ++n)
thrd_create(&thr[n], f, NULL);
for(int n = 0; n < 10; ++n)
thrd_join(thr[n], NULL);
printf("The atomic counter is %u\n", acnt);
printf("The non-atomic counter is %u\n", cnt);
}
Kompilace a spuštění s test_glibc.sh
:
#!/usr/bin/env bash
set -eux
gcc \
-L "${glibc_install}/lib" \
-I "${glibc_install}/include" \
-Wl,--rpath="${glibc_install}/lib" \
-Wl,--dynamic-linker="${glibc_install}/lib/ld-linux-x86-64.so.2" \
-std=c11 \
-o test_glibc.out \
-v \
test_glibc.c \
-pthread \
;
ldd ./test_glibc.out
./test_glibc.out
Příkaz upraven z https://sourceware.org/glibc/wiki/Testing/Builds?action=recall&rev=21#Compile_against_glibc_in_an_installed_location
Výstupem programu je očekávané:
gnu_get_libc_version() = 2.32
The atomic counter is 10000
The non-atomic counter is 8674
ldd
výstup potvrzuje, že ldd
a knihovny, které jsme právě vytvořili, se skutečně používají podle očekávání:
+ ldd test_glibc.out
linux-vdso.so.1 (0x00007ffe4bfd3000)
libpthread.so.0 => /home/ciro/glibc/build/install/lib/libpthread.so.0 (0x00007fc12ed92000)
libc.so.6 => /home/ciro/glibc/build/install/lib/libc.so.6 (0x00007fc12e9dc000)
/home/ciro/glibc/build/install/lib/ld-linux-x86-64.so.2 => /lib64/ld-linux-x86-64.so.2 (0x00007fc12f1b3000)
gcc
výstup ladění kompilace ukazuje, že byly použity moje hostitelské runtime objekty, což je špatné, jak bylo zmíněno dříve, ale nevím, jak to obejít, např. obsahuje:
COLLECT_GCC_OPTIONS=/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/crt1.o
Nastavení 1:úprava glibc
Nyní upravíme glibc pomocí:
diff --git a/nptl/thrd_create.c b/nptl/thrd_create.c
index 113ba0d93e..b00f088abb 100644
--- a/nptl/thrd_create.c
+++ b/nptl/thrd_create.c
@@ -16,11 +16,14 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
+#include <stdio.h>
+
#include "thrd_priv.h"
int
thrd_create (thrd_t *thr, thrd_start_t func, void *arg)
{
+ puts("hacked");
_Static_assert (sizeof (thr) == sizeof (pthread_t),
"sizeof (thr) != sizeof (pthread_t)");
Poté znovu zkompilujte a znovu nainstalujte glibc a znovu zkompilujte a znovu spusťte náš program:
cd glibc/build
make -j `nproc`
make -j `nproc` install
./test_glibc.sh
a vidíme hacked
vytištěno několikrát podle očekávání.
To dále potvrzuje, že jsme skutečně použili glibc, který jsme zkompilovali, a ne hostitelský.
Testováno na Ubuntu 20.10.
Nastavení 1:pokusí se použít správný crt*
objekty
https://sourceware.org/glibc/wiki/Testing/Builds?action=recall&rev=21#Compile_against_glibc_in_an_installed_location navrhuje přidat --sysroot
na gcc
příkaz ale:
- ve skutečnosti nemění objekty na naše podle protokolů
- a způsobí to selhání kompilace s
/usr/bin/ld: cannot find libgcc_s.so.1
pravděpodobně proto, žesysroot
se používá pro tento objekt poskytovaný GCC, který v tomto kořenovém adresáři sysroot nemáme, protože jsme vytvořili pouze glibc
Na https://stackoverflow.com/a/66634184/895245 ZeZNiQ poskytuje řešení, které je pravděpodobně správné, tím, že předá:
-nostartfiles
následují všechny předměty. Stačí extrahovat správné objekty z úplného příkazu s -nostartfiles
a předejte je ručně.
Například na mém počítači amd64 se použité objekty lišily od jeho 32bitového příkazu, takže je to trochu nešikovné.
Bibliografie:
- Jak změním výchozí vyhledávací adresář GCC pro crti.o?
- https://gcc.gnu.org/legacy-ml/gcc-help/2015-02/msg00016.html
- https://gcc.gnu.org/legacy-ml/gcc-help/2001-11/msg00029.html
Nastavení 2:Dokonalé nastavení crosstool-NG
Toto je alternativa k nastavení 1 a je to nejsprávnější nastavení, kterého jsem dosud dosáhl:vše je v pořádku, pokud mohu pozorovat, včetně objektů C runtime, jako je crt1.o
, crti.o
a crtn.o
.
V tomto nastavení zkompilujeme úplný vyhrazený toolchain GCC, který používá glibc, který chceme.
Jedinou nevýhodou této metody je, že sestavení bude trvat déle. Ale neriskoval bych produkční nastavení s ničím menším.
crosstool-NG je sada skriptů, která pro nás stahuje a kompiluje vše ze zdroje, včetně GCC, glibc a binutils.
Ano, sestavovací systém GCC je tak špatný, že na to potřebujeme samostatný projekt.
Toto nastavení není dokonalé, protože crosstool-NG nepodporuje vytváření spustitelných souborů bez extra -Wl
flags, což je divný pocit, protože jsme vytvořili samotné GCC. Ale zdá se, že vše funguje, takže je to jen nepříjemnost.
Získejte crosstool-NG, nakonfigurujte jej a sestavte:
git clone https://github.com/crosstool-ng/crosstool-ng
cd crosstool-ng
git checkout a6580b8e8b55345a5a342b5bd96e42c83e640ac5
export CT_PREFIX="$(pwd)/.build/install"
export PATH="/usr/lib/ccache:${PATH}"
./bootstrap
./configure --enable-local
make -j `nproc`
./ct-ng x86_64-unknown-linux-gnu
./ct-ng menuconfig
env -u LD_LIBRARY_PATH time ./ct-ng build CT_JOBS=`nproc`
Sestavení trvá asi třicet minut až dvě hodiny.
Jedinou povinnou možností konfigurace, kterou vidím, je zajistit, aby odpovídala verzi vašeho hostitelského jádra, aby používala správné hlavičky jádra. Najděte verzi hostitelského jádra pomocí:
uname -a
což mi ukazuje:
4.15.0-34-generic
tedy v menuconfig
Já ano:
Operating System
Version of linux
takže vybírám:
4.14.71
což je první stejná nebo starší verze. Musí být starší, protože jádro je zpětně kompatibilní.
Nastavení 2:volitelné konfigurace
.config
které jsme vygenerovali pomocí ./ct-ng x86_64-unknown-linux-gnu
má:
CT_GLIBC_V_2_27=y
Chcete-li to změnit, v menuconfig
udělat:
C-library
Version of glibc
uložte .config
a pokračujte v sestavení.
Nebo, pokud chcete použít svůj vlastní zdroj glibc, např. pro použití glibc z nejnovějšího git postupujte takto:
Paths and misc options
Try features marked as EXPERIMENTAL
:nastaveno na hodnotu true
C-library
Source of glibc
Custom location
:řekni anoCustom location
Custom source location
:přejděte na adresář obsahující váš zdroj glibc
kde glibc byl klonován jako:
git clone git://sourceware.org/git/glibc.git
cd glibc
git checkout glibc-2.28
Nastavení 2:vyzkoušejte to
Jakmile vytvoříte požadovaný nástrojový řetězec, vyzkoušejte jej pomocí:
#!/usr/bin/env bash
set -eux
install_dir="${CT_PREFIX}/x86_64-unknown-linux-gnu"
PATH="${PATH}:${install_dir}/bin" \
x86_64-unknown-linux-gnu-gcc \
-Wl,--dynamic-linker="${install_dir}/x86_64-unknown-linux-gnu/sysroot/lib/ld-linux-x86-64.so.2" \
-Wl,--rpath="${install_dir}/x86_64-unknown-linux-gnu/sysroot/lib" \
-v \
-o test_glibc.out \
test_glibc.c \
-pthread \
;
ldd test_glibc.out
./test_glibc.out
Zdá se, že vše funguje jako v Nastavení 1, až na to, že nyní byly použity správné runtime objekty:
COLLECT_GCC_OPTIONS=/home/ciro/crosstool-ng/.build/install/x86_64-unknown-linux-gnu/bin/../x86_64-unknown-linux-gnu/sysroot/usr/lib/../lib64/crt1.o
Nastavení 2:neúspěšný pokus o efektivní rekompilaci glibc
Zdá se, že s crosstool-NG to není možné, jak je vysvětleno níže.
Pokud jste právě přestavěli;
env -u LD_LIBRARY_PATH time ./ct-ng build CT_JOBS=`nproc`
pak se vezmou v úvahu vaše změny ve vlastním umístění zdroje glibc, ale vše vytváří od začátku, takže je pro iterativní vývoj nepoužitelný.
Pokud to uděláme:
./ct-ng list-steps
poskytuje pěkný přehled kroků sestavení:
Available build steps, in order:
- companion_tools_for_build
- companion_libs_for_build
- binutils_for_build
- companion_tools_for_host
- companion_libs_for_host
- binutils_for_host
- cc_core_pass_1
- kernel_headers
- libc_start_files
- cc_core_pass_2
- libc
- cc_for_build
- cc_for_host
- libc_post_cc
- companion_libs_for_target
- binutils_for_target
- debug
- test_suite
- finish
Use "<step>" as action to execute only that step.
Use "+<step>" as action to execute up to that step.
Use "<step>+" as action to execute from that step onward.
proto vidíme, že existují kroky glibc propojené s několika kroky GCC, zejména libc_start_files
je před cc_core_pass_2
, což je pravděpodobně nejdražší krok spolu s cc_core_pass_1
.
Chcete-li sestavit pouze jeden krok, musíte nejprve nastavit "Uložit mezikroky" v .config
možnost pro počáteční sestavení:
Paths and misc options
Debug crosstool-NG
Save intermediate steps
a pak můžete zkusit:
env -u LD_LIBRARY_PATH time ./ct-ng libc+ -j`nproc`
ale bohužel +
vyžadováno, jak je uvedeno na:https://github.com/crosstool-ng/crosstool-ng/issues/1033#issuecomment-424877536
Všimněte si však, že restartování v mezikroku resetuje instalační adresář do stavu, v jakém byl během tohoto kroku. To znamená, že budete mít přestavěnou knihovnu libc – ale žádný konečný kompilátor vytvořený s touto knihovnou libc (a tudíž ani žádné knihovny kompilátorů jako libstdc++).
a v zásadě je přestavba stále příliš pomalá na to, aby byla proveditelná pro vývoj, a nevím, jak to překonat bez záplatování crosstool-NG.
Navíc počínaje libc
nezdálo se, že by step znovu zkopíroval zdroj z Custom source location
, což dále činí tuto metodu nepoužitelnou.
Bonus:stdlibc++
Bonus, pokud vás také zajímá standardní knihovna C++:Jak upravit a znovu sestavit zdrojový kód standardní knihovny GCC libstdc++ C++?
Přidání k dřívější odpovědi/řešení Ciro https://stackoverflow.com/a/52454710/4726668 :
@CiroSantilli Úprava vaší odpovědi vrátí „Fronta navrhovaných úprav je plná“. Skript ldd, který voláte, v test_glibc.sh
skript ukazuje na hostitelský dynamický linker:/home/ciro/glibc/build/install/lib/ld-linux-x86-64.so.2 => /lib64/ld-linux-x86-64.so.2 (0x00007fc12f1b3000)
. Chcete-li to opravit, v test_glibc.sh
, změňte ldd
na ${glibc_install}/bin/ldd
. To bude vyžadovat, abyste přidali vestavěný crt
*.o soubory také do skriptu:
-nostartfiles \
${glibc_install}/lib/crti.o \
${glibc_install}/lib/crtn.o \
${glibc_install}/lib/crt1.o \
Na mém počítači GNU/Linux i386/i686 (32bitový x86 arch) je můj pracovní test_glibc.sh
:
#!/usr/bin/env bash
set -eux
gcc \
-L "${glibc_install}/lib" \
-I "${glibc_install}/include" \
-Wl,--rpath="${glibc_install}/lib" \
-Wl,--dynamic-linker="${glibc_install}/lib/ld-linux.so.2" \
-std=c11 \
-nostartfiles \
${glibc_install}/lib/crti.o \
${glibc_install}/lib/crtn.o \
${glibc_install}/lib/crt1.o \
-o test_glibc.out \
-v \
test_glibc.c \
-pthread \
;
${glibc_install}/bin/ldd ./test_glibc.out
./test_glibc.out