bench-boot looks fine

This commit is contained in:
Ciro Santilli
2018-09-09 17:03:06 +01:00
parent b3f2ddd629
commit 6f73a9eb30
6 changed files with 177 additions and 147 deletions

View File

@@ -69,10 +69,11 @@ If you don't know which one to go for, start with <<qemu-buildroot-setup>>
The trade-offs are basically a balance between:
* how long and how much disk space does the build take
* how long and how much disk space does the build and run take
* visibility: can you GDB step debug everything and read source code?
* modifiability: can you modify the source code and rebuild a modified version?
* how portable the setup is: does it work on Windows? Could it ever?
* accuracy: how accurate does the simulation represent real hardware?
=== QEMU Buildroot setup
@@ -9355,6 +9356,8 @@ We tried to automate it on Travis with link:.travis.yml[] but it hits the curren
==== Benchmark Linux kernel boot
Benchmark all:
....
./build-all
./bench-boot
@@ -9365,45 +9368,45 @@ Sample results at 2bddcc2891b7e5ac38c10d509bdfc1c8fe347b94:
....
cmd ./run --arch x86_64 --eval '/poweroff.out'
time 3.58
time 7.46
exit_status 0
cmd ./run --arch x86_64 --eval '/poweroff.out' --kvm
time 0.89
time 7.61
exit_status 0
cmd ./run --arch x86_64 --eval '/poweroff.out' --trace exec_tb
time 4.12
time 8.04
exit_status 0
instructions 2343768
instructions 1665023
cmd ./run --arch x86_64 --eval 'm5 exit' --gem5
time 451.10
time 254.32
exit_status 0
instructions 706187020
instructions 380799337
cmd ./run --arch arm --eval '/poweroff.out'
time 1.85
time 5.56
exit_status 0
cmd ./run --arch arm --eval '/poweroff.out' --trace exec_tb
time 1.92
time 5.78
exit_status 0
instructions 681000
cmd ./run --arch arm --eval 'm5 exit' --gem5
time 94.85
exit_status 0
instructions 139895210
instructions 742319
cmd ./run --arch aarch64 --eval '/poweroff.out'
time 1.36
time 4.85
exit_status 0
cmd ./run --arch aarch64 --eval '/poweroff.out' --trace exec_tb
time 1.37
time 4.91
exit_status 0
instructions 178879
instructions 245471
cmd ./run --arch aarch64 --eval 'm5 exit' --gem5
time 72.50
time 68.71
exit_status 0
instructions 115754212
cmd ./run --arch aarch64 --eval 'm5 exit' --gem5 -- --cpu-type=HPI --caches --l2cache --l1d_size=1024kB --l1i_size=1024kB --l2_size=1024kB --l3_size=1024kB
time 369.13
exit_status 0
instructions 115774177
instructions 120555566
....
TODO: aarch64 gem5 and QEMU use the same kernel, so why is the gem5 instruction count so much much higher?
@@ -9455,32 +9458,29 @@ Or to conveniently do a clean build without affecting your current one:
cat ../linux-kernel-module-cheat-regression/*/build-time.log
....
===== Find which packages are making the build slow
===== Find which packages are making the build slow and big
....
cd "$(./getvar buildroot_out_dir)
make graph-build graph-depends
xdg-open graphs/build.pie-packages.pdf
xdg-open graphs/graph-depends.pdf
./build --skip-configure -- graph-build graph-size graph-depends
cd "$(./getvar buildroot_out_dir)/graphs"
xdg-open build.pie-packages.pdf
xdg-open graph-depends.pdf
xdg-open graph-size.pdf
....
Our philosophy is:
* if something adds little to the build time, build it in by default
* otherwise, make it optional
* try to keep the toolchain (GCC, Binutils) unchanged, otherwise a full rebuild is required.
+
So we generally just enable all toolchain options by default, even though this adds a bit of time to the build.
* if something is very valuable, we just add it by default even if it increases the Build time, notably GDB and QEMU
* runtime is sacred.
+
We do our best to reduce the instruction and feature count to the bare minimum needed, to make the system:
* keep the root filesystem as tiny as possible to make prebuilts small. It is easy to add new packages once you have the toolchain.
* enable every feature possible on the toolchain (GCC, Binutils), because changes imply Buildroot rebuilds
* runtime is sacred. Faster systems are:
+
--
** easier to understand
** run faster, specially for <<gem5>>
** run faster, which is specially for <<gem5>> which is slow
--
+
Runtime basically just comes down to how we configure the Linux kernel, since in the root filesystem all that matters is `init=`, and that is easy to control.
+
One possibility we could play with is to build loadable modules instead of built-in modules to reduce runtime, but make it easier to get started with the modules.
[[prebuilt-toolchain]]

View File

@@ -85,31 +85,27 @@ BR2_TARGET_ROOTFS_EXT2=n
fi
if "$bench_gem5_build"; then
arches='x86_64 arm'
for common_arch in $arches; do
common_gem5_out_dir="$("$getvar" --arch "$common_arch" gem5_out_dir)"
common_gem5_src_dir="$("$getvar" --arch "$common_arch" gem5_src_dir)"
common_out_dir="$("$getvar" --arch "$common_arch" out_dir)"
cd "${common_gem5_src_dir}"
git clean -xdf
results_file="${common_gem5_out_dir}/bench-build.txt"
gem5_outdir="${common_out_dir}/bench_build"
rm -fr "$results_file" "${gem5_outdir}"
# TODO understand better: --foreground required otherwise we cannot
# kill the build with Ctrl+C if something goes wrong, can be minimized to:
# bash -c "eval 'timeout 5 sleep 3'"
"${root_dir}/bench-cmd" "timeout --foreground 900 ../build -a '$common_arch' -o '${gem5_outdir}'" "$results_file"
cp "$results_file" "${new_dir}/gem5-bench-build-${common_arch}.txt"
cd "${root_dir}/gem5/gem5"
git clean -xdf
rm -fr "${gem5_outdir}"
done
common_arch="$default_arch"
gem5_build_id=bench-build
common_gem5_out_dir="$("$getvar" --arch "$common_arch" --gem5-build-id "$gem5_build_id" gem5_out_dir)"
common_gem5_src_dir="$("$getvar" --arch "$common_arch" --gem5-build-id "$gem5_build_id" gem5_src_dir)"
results_file="${common_gem5_out_dir}/bench-build.txt"
git -C "${common_gem5_src_dir}" clean -xdf
rm -f "$results_file"
"${root_dir}/build-gem5" --arch "$common_arch" --clean --gem5-build-id "$gem5_build_id"
# TODO understand better: --foreground required otherwise we cannot
# kill the build with Ctrl+C if something goes wrong, can be minimized to:
# bash -c "eval 'timeout 5 sleep 3'"
"${root_dir}/bench-cmd" "timeout --foreground 900 ./build-gem5 --arch '$common_arch' --gem5-build-id '$gem5_build_id'" "$results_file"
cp "$results_file" "${new_dir}/gem5-bench-build-${common_arch}.txt"
git -C "${common_gem5_src_dir}" clean -xdf
"${root_dir}/build-gem5" --arch "$common_arch" --clean --gem5-build-id "$gem5_build_id"
fi
if "$bench_linux_boot"; then
cd "${root_dir}"
./build-all
./bench-boot
./bench-boot -t 3
cp "$(${root_dir}/getvar bench_boot)" "$new_dir"
fi

View File

@@ -17,57 +17,83 @@ while getopts t: OPT; do
esac
done
shift "$(($OPTIND - 1))"
extra_args="$*"
common_bench_boot="$(${root_dir}/getvar bench_boot)"
if [ $# -gt 1 ]; then
extra_args=" $*"
else
extra_args=
fi
getvar="${root_dir}/getvar"
common_bench_boot="$("$getvar" bench_boot)"
caches='--caches --l2cache --l1d_size=1024kB --l1i_size=1024kB --l2_size=1024kB --l3_size=1024kB'
bench() (
"${root_dir}/bench-cmd" "./run -a ${1} ${extra_args}" "$common_bench_boot"
echo >> "$common_bench_boot"
"${root_dir}/bench-cmd" "./run --arch ${1}${extra_args}" "$common_bench_boot"
)
gem5_insts() (
printf "instructions $(./gem5-stat -a "$1" sim_insts)\n" >> "$common_bench_boot"
printf "instructions $(./gem5-stat --arch "$1" sim_insts)\n" >> "$common_bench_boot"
)
qemu_insts() (
common_arch="$1"
./qemu-trace2txt -a "$common_arch"
common_setup
printf "instructions $(wc -l "${common_trace_txt_file}" | cut -d' ' -f1)\n" >> "$common_bench_boot"
./qemu-trace2txt --arch "$common_arch"
common_qemu_trace_txt_file="$("$getvar" --arch "$common_arch" qemu_trace_txt_file)"
printf "instructions $(wc -l "${common_qemu_trace_txt_file}" | cut -d' ' -f1)\n" >> "$common_bench_boot"
)
newline() (
echo >> "$common_bench_boot"
)
rm -f "${common_bench_boot}"
arch=x86_64
bench "$arch -E '/poweroff.out'"
bench "$arch -E '/poweroff.out' -K"
bench "${arch} --eval '/poweroff.out'"
newline
bench "${arch} --eval '/poweroff.out' --kvm"
newline
if [ "$test_size" -ge 2 ]; then
bench "$arch -E '/poweroff.out' -T exec_tb"
bench "${arch} --eval '/poweroff.out' --trace exec_tb"
qemu_insts "$arch"
fi
if [ "$test_size" -ge 2 ]; then
bench "$arch -E 'm5 exit' -g"
newline
bench "$arch --eval 'm5 exit' --gem5"
gem5_insts "$arch"
newline
fi
#bench "$arch -E 'm5 exit' -g -- --cpu-type=DerivO3CPU ${caches}"
#bench "$arch --eval 'm5 exit' --gem5 -- --cpu-type=DerivO3CPU ${caches}"
#gem5_insts "$arch"
#newline
arch=arm
bench "$arch -E '/poweroff.out'"
bench "$arch --eval '/poweroff.out'"
newline
if [ "$test_size" -ge 2 ]; then
bench "$arch -E '/poweroff.out' -T exec_tb"
bench "$arch --eval '/poweroff.out' --trace exec_tb"
qemu_insts "$arch"
newline
#bench "$arch --eval 'm5 exit' --gem5"
#gem5_insts "$arch"
#newline
fi
#bench "$arch -E 'm5 exit' -g"
#gem5_insts "$arch"
#bench "$arch -E 'm5 exit' -g -- --cpu-type=HPI ${caches}"
#gem5_insts "$arch"
#if [ "$test_size" -ge 3 ]; then
# bench "$arch --eval 'm5 exit' --gem5 -- --cpu-type=HPI ${caches}"
# gem5_insts "$arch"
# newline
#fi
arch=aarch64
bench "$arch -E '/poweroff.out'"
bench "$arch --eval '/poweroff.out'"
newline
if [ "$test_size" -ge 2 ]; then
bench "$arch -E '/poweroff.out' -T exec_tb"
bench "$arch --eval '/poweroff.out' --trace exec_tb"
qemu_insts "$arch"
newline
bench "$arch --eval 'm5 exit' --gem5"
gem5_insts "$arch"
newline
fi
if [ "$test_size" -ge 3 ]; then
bench "$arch --eval 'm5 exit' --gem5 -- --cpu-type=HPI ${caches}"
gem5_insts "$arch"
newline
fi
#bench "$arch -E 'm5 exit' -g"
#gem5_insts "$arch"
#bench "$arch -E 'm5 exit' -g -- --cpu-type=HPI ${caches}"
#gem5_insts "$arch"

2
build
View File

@@ -283,7 +283,7 @@ https://stackoverflow.com/questions/49260466/why-when-i-change-br2-linux-kernel-
help='Do a verbose build'
)
parser.add_argument(
'extra-make-args', default=defaults['extra_make_args'], nargs='*'
'extra_make_args', default=defaults['extra_make_args'], metavar='extra-make-args', nargs='*'
)
return parser

View File

@@ -1,22 +1,22 @@
#!/usr/bin/env bash
set -eu
archs='x86_64 arm aarch64'
gem5=-g
gem5=true
while getopts A:G OPT; do
case "$OPT" in
A)
archs="$OPTARG"
;;
G)
gem5=
gem5=false
;;
esac
done
shift "$(($OPTIND - 1))"
for arch in $archs; do
./build -a "$arch" -k -l "$@"
./build-qemu -a "$arch"
./build --arch "$arch" --kernel-modules -l "$@"
./build-qemu --arch "$arch"
if "$gem5"; then
./build-gem5 -a "$arch"
./build-gem5 --arch "$arch"
fi
done

View File

@@ -10,6 +10,11 @@ import subprocess
import common
parser = common.get_argparse()
parser.add_argument(
'-c', '--clean',
help='Clean the build instead of building.',
action='store_true',
)
parser.add_argument(
'extra_scons_args',
default=[],
@@ -19,61 +24,64 @@ parser.add_argument(
args = common.setup(parser)
binaries_dir = os.path.join(common.gem5_system_dir, 'binaries')
disks_dir = os.path.join(common.gem5_system_dir, 'disks')
os.makedirs(binaries_dir, exist_ok=True)
os.makedirs(disks_dir, exist_ok=True)
if not os.path.exists(os.path.join(common.gem5_src_dir, '.git')):
subprocess.check_call([
'git',
'-C', common.gem5_default_src_dir,
'worktree', 'add',
'-b', os.path.join('wt', args.gem5_build_id),
common.gem5_src_dir
])
if args.arch == 'x86_64':
dummy_img_path = os.path.join(disks_dir, 'linux-bigswap2.img')
with open(dummy_img_path, 'wb') as dummy_img_file:
zeroes = b'\x00' * (2 ** 16)
for i in range(2 ** 10):
dummy_img_file.write(zeroes)
subprocess.check_call(['mkswap', dummy_img_path])
with open(os.path.join(binaries_dir, 'x86_64-vmlinux-2.6.22.9'), 'w'):
# This file must always be present, despite --kernel overriding that default and selecting the kernel.
# I'm not even joking. No one has ever built x86 gem5 without the magic dist dir present.
pass
elif args.arch == 'arm' or args.arch == 'aarch64':
gem5_system_src_dir = os.path.join(common.gem5_src_dir, 'system')
if args.clean:
shutil.rmtree(common.gem5_out_dir)
else:
os.makedirs(binaries_dir, exist_ok=True)
os.makedirs(disks_dir, exist_ok=True)
if not os.path.exists(os.path.join(common.gem5_src_dir, '.git')):
subprocess.check_call([
'git',
'-C', common.gem5_default_src_dir,
'worktree', 'add',
'-b', os.path.join('wt', args.gem5_build_id),
common.gem5_src_dir
])
if args.arch == 'x86_64':
dummy_img_path = os.path.join(disks_dir, 'linux-bigswap2.img')
with open(dummy_img_path, 'wb') as dummy_img_file:
zeroes = b'\x00' * (2 ** 16)
for i in range(2 ** 10):
dummy_img_file.write(zeroes)
subprocess.check_call(['mkswap', dummy_img_path])
with open(os.path.join(binaries_dir, 'x86_64-vmlinux-2.6.22.9'), 'w'):
# This file must always be present, despite --kernel overriding that default and selecting the kernel.
# I'm not even joking. No one has ever built x86 gem5 without the magic dist dir present.
pass
elif args.arch == 'arm' or args.arch == 'aarch64':
gem5_system_src_dir = os.path.join(common.gem5_src_dir, 'system')
# dtb
dt_src_dir = os.path.join(gem5_system_src_dir, 'arm', 'dt')
dt_build_dir = os.path.join(common.gem5_system_dir, 'arm', 'dt')
subprocess.check_call(['make', '-C', dt_src_dir])
os.makedirs(dt_build_dir, exist_ok=True)
for dt in glob.glob(os.path.join(dt_src_dir, '*.dtb')):
shutil.copy2(dt, dt_build_dir)
# dtb
dt_src_dir = os.path.join(gem5_system_src_dir, 'arm', 'dt')
dt_build_dir = os.path.join(common.gem5_system_dir, 'arm', 'dt')
subprocess.check_call(['make', '-C', dt_src_dir])
os.makedirs(dt_build_dir, exist_ok=True)
for dt in glob.glob(os.path.join(dt_src_dir, '*.dtb')):
shutil.copy2(dt, dt_build_dir)
# Bootloader 32.
bootloader32_dir = os.path.join(gem5_system_src_dir, 'arm', 'simple_bootloader')
# TODO use the buildroot cross compiler here, and remove the dependencies from configure.
subprocess.check_call(['make', '-C', bootloader32_dir])
# bootloader
shutil.copy2(os.path.join(bootloader32_dir, 'boot_emm.arm'), binaries_dir)
# Bootloader 32.
bootloader32_dir = os.path.join(gem5_system_src_dir, 'arm', 'simple_bootloader')
# TODO use the buildroot cross compiler here, and remove the dependencies from configure.
subprocess.check_call(['make', '-C', bootloader32_dir])
# bootloader
shutil.copy2(os.path.join(bootloader32_dir, 'boot_emm.arm'), binaries_dir)
# Bootloader 64.
bootloader64_dir = os.path.join(gem5_system_src_dir, 'arm', 'aarch64_bootloader')
# TODO cross_compile is ignored because the make does not use CC...
subprocess.check_call(['make', '-C', bootloader64_dir])
shutil.copy2(os.path.join(bootloader64_dir, 'boot_emm.arm64'), binaries_dir)
assert common.run_cmd([
'scons',
# TODO factor with build.
'-j', str(multiprocessing.cpu_count()),
'--ignore-style',
common.gem5_executable
] +
args.extra_scons_args,
cwd=common.gem5_src_dir,
extra_env={'PATH': '/usr/lib/ccache:' + os.environ['PATH']},
) == 0
term_src_dir = os.path.join(common.gem5_src_dir, 'util/term')
subprocess.check_call(['make', '-C', term_src_dir])
shutil.copy2(os.path.join(term_src_dir, 'm5term'), common.gem5_m5term)
# Bootloader 64.
bootloader64_dir = os.path.join(gem5_system_src_dir, 'arm', 'aarch64_bootloader')
# TODO cross_compile is ignored because the make does not use CC...
subprocess.check_call(['make', '-C', bootloader64_dir])
shutil.copy2(os.path.join(bootloader64_dir, 'boot_emm.arm64'), binaries_dir)
assert common.run_cmd([
'scons',
# TODO factor with build.
'-j', str(multiprocessing.cpu_count()),
'--ignore-style',
common.gem5_executable
] +
args.extra_scons_args,
cwd=common.gem5_src_dir,
extra_env={'PATH': '/usr/lib/ccache:' + os.environ['PATH']},
) == 0
term_src_dir = os.path.join(common.gem5_src_dir, 'util/term')
subprocess.check_call(['make', '-C', term_src_dir])
shutil.copy2(os.path.join(term_src_dir, 'm5term'), common.gem5_m5term)