lkmc v2-rc

Unsquashed version at v2-rc-unsquashed, but that cannot be merged as it
breaks bisects at several points. All bugs will not bisect to this
humongous change.

It all started with a conversion of the Bash scripts to Python, mainly
because I couldn't stand not being able to properly use --options for
run which has a million options.

Then since that required a full testing, I decided to do all the
refactorings that I had in mind at once, and so I did and it became
v2-rc.

This is the largest patch I have ever done! OMG a few weeks of extra time.
I'm never writing a Bash script for anything that starts getting big again.

Some of the features are:

* separate build-qemu and build-gem5 commands
* common: convert scripts to python. Add --option for everything
* rename build to build-buildroot now that we are splitting all the build
  commands, Linux kernel to follow
* move all git submodules to submodules/ and all buildroot packages to
  packages/
* refactor the out/ structure. Keep projects on toplevel, because guest
  projects separate archs and host ones don't, making a toplevel arch wrong
* do-release: rename to just release
  https://stackoverflow.com/questions/16174992/cant-get-argparse-to-read-quoted-string-with-dashes-in-it
* run: add --terminal and explain gem5 pdb
* just track the lvimrc
* store CLI kernel config fragment inside buildlroot to avoid conflicts
* gem5: document m5 initparam
* readme: make a bunch of things awesomer
* readme: fix broken refs
* parsec-benchmark: update to 75d55ac446a43c47efb1044844a108c6c330184c
  Could not fetch otherwise.
* gem5: M5_OVERRIDE_PY_SOURCE
This commit is contained in:
Ciro Santilli
2018-08-23 09:25:21 +01:00
parent f8c0502bb2
commit fd55d694c0
163 changed files with 4520 additions and 3456 deletions

4
.gitignore vendored
View File

@ -11,3 +11,7 @@ gitignore*
/images-*.zip
/out
/out.*
# Python trash.
*.pyc
__pycache__

24
.gitmodules vendored
View File

@ -1,16 +1,20 @@
[submodule "buildroot"]
path = buildroot
[submodule "submodules/buildroot"]
path = submodules/buildroot
url = https://github.com/cirosantilli/buildroot
ignore = dirty
[submodule "qemu"]
path = qemu
[submodule "submodules/qemu"]
path = submodules/qemu
url = https://github.com/cirosantilli/qemu
[submodule "linux"]
path = linux
# The true upstream does not accept git submodule update --init --depth 1
# git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git
# But git clone --branch --depth 1 worked weirdly:
# https://unix.stackexchange.com/questions/338578/linux-kernel-source-code-size-difference
[submodule "submodules/linux"]
path = submodules/linux
url = https://github.com/cirosantilli/linux
[submodule "gem5/gem5"]
path = gem5/gem5
[submodule "submodules/gem5"]
path = submodules/gem5
url = https://gem5.googlesource.com/public/gem5
[submodule "parsec-benchmark/parsec-benchmark"]
path = parsec-benchmark/parsec-benchmark
[submodule "submodules/parsec-benchmark"]
path = submodules/parsec-benchmark
url = https://github.com/cirosantilli/parsec-benchmark

9
.lvimrc Normal file
View File

@ -0,0 +1,9 @@
" Use this automatically with:
"
" Plugin 'embear/vim-localvimrc'
" let g:localvimrc_ask = 0
" let g:localvimrc_sandbox = 0
if &filetype ==# 'c' || &filetype ==# 'cpp'
setlocal noexpandtab
endif

View File

@ -21,5 +21,6 @@ script: |
# The following packages have unmet dependencies:
# libsdl2-dev : Depends: libegl1-mesa-dev
# Depends: libgles2-mesa-dev
bash -x ./build-qemu -j 16 -S |& awk 'NR % 1000 == 0'
bash -x ./build -j 16 -S |& awk 'NR % 1000 == 0'
bash -x ./run -e 'init=/poweroff.out'

File diff suppressed because it is too large Load Diff

124
bench-all
View File

@ -1,8 +1,9 @@
#!/usr/bin/env bash
. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/common"
set -x
bench_build=false
bench_buildroot_baseline=false
set -eux
root_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null && pwd)"
bench_all=false
bench_buildroot_build=false
bench_buildroot_baseline_build=false
bench_gem5_build=false
bench_linux_boot=false
default_arch=x86_64
@ -10,19 +11,16 @@ update_repo=false
while getopts Aa:Bbglu OPT; do
case "$OPT" in
A)
bench_build=true
bench_buildroot_baseline=true
bench_gem5_build=true
bench_linux_boot=true
bench_all=true
;;
a)
default_arch="$OPTARG"
;;
b)
bench_build=true
bench_buildroot_build=true
;;
B)
bench_buildroot_baseline=true
bench_buildroot_baseline_build=true
;;
g)
bench_gem5_build=true
@ -40,9 +38,24 @@ while getopts Aa:Bbglu OPT; do
done
shift "$(($OPTIND - 1))"
comment="${1:-}"
if \
! "$bench_buildroot_build" && \
! "$bench_buildroot_baseline_build" && \
! "$bench_gem5_build" && \
! "$bench_linux_boot" \
; then
bench_all=true
fi
if "$bench_all"; then
bench_buildroot_build=true
bench_buildroot_baseline_build=true
bench_gem5_build=true
bench_linux_boot=true
fi
getvar="${root_dir}/getvar"
# Create output directory.
benchmark_repo="${common_root_dir}/../linux-kernel-module-cheat-regression"
benchmark_repo="${root_dir}/../linux-kernel-module-cheat-regression"
mkdir -p "$benchmark_repo"
last_dir="$(ls "$benchmark_repo" | grep -E '^[0-9]' | tail -n 1)"
if [ -n "$last_dir" ]; then
@ -51,62 +64,61 @@ else
seq_id=0
fi
seq_id="$(printf '%0.4d' "$seq_id")"
dir_basename="${seq_id}_${common_sha}"
dir_basename="${seq_id}_$("$getvar" sha)"
new_dir="${benchmark_repo}/${dir_basename}"
mkdir "$new_dir"
if "$bench_build"; then
common_arch="$default_arch"
common_suffix=bench
common_setup
rm -rf "$common_out_arch_dir"
./build -a "$common_arch" -B 'BR2_CCACHE=n' -s "$common_suffix"
cp "${common_build_dir}/build-time.log" "${new_dir}/build-time-${common_arch}.log"
rm -rf "$common_out_arch_dir"
do_bench_buildroot_build() (
arch="$default_arch"
build_id=bench
if [ "${1:-}" = baseline ]; then
baseline=--baseline
baseline_suffix=-baseline
else
baseline=
baseline_suffix=
fi
common_build_dir="$("$getvar" --arch "$arch" --buildroot-build-id "$build_id" build_dir)"
common_images_dir="$("$getvar" --arch "$arch" --buildroot-build-id "$build_id" images_dir)"
"${root_dir}/build-buildroot" --arch "$arch" $baseline --buildroot-build-id "$build_id" --clean
"${root_dir}/build-buildroot" --arch "$arch" $baseline --buildroot-build-id "$build_id" --no-all -- source
"${root_dir}/build-buildroot" --arch "$arch" $baseline --buildroot-build-id "$build_id"
cp "${common_build_dir}/build-time.log" "${new_dir}/buildroot-build-time-${baseline_suffix}${arch}.log"
wc -c "${images_dir}/"* > "${new_dir}/buildroot-image-size-${baseline_suffix}${arch}.log"
"${root_dir}/build-buildroot" --arch "$arch" $baseline --buildroot-build-id "$build_id" --clean
)
if "$bench_buildroot_build"; then
do_bench_buildroot_build
fi
if "$bench_buildroot_baseline"; then
cd "${common_root_dir}/buildroot"
git clean -xdf
make "qemu_${default_arch}_defconfig"
printf '
BR2_CCACHE=y
BR2_TARGET_ROOTFS_CPIO=y
BR2_TARGET_ROOTFS_EXT2=n
' >>.config
make olddefconfig
make source
time env -u LD_LIBRARY_PATH make BR2_JLEVEL="$(nproc)"
cp output/build/build-time.log "${new_dir}/baseline-build-time-${default_arch}.log"
wc -c output/images/* > "${new_dir}/baseline-image-size-${default_arch}.log"
git clean -xdf
if "$bench_buildroot_baseline_build"; then
do_bench_buildroot_build baseline
fi
if "$bench_gem5_build"; then
arches='x86_64 arm'
for common_arch in $arches; do
common_setup
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'"
common_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 "${common_root_dir}/gem5/gem5"
git clean -xdf
rm -fr "${gem5_outdir}"
done
common_arch="$default_arch"
gem5_build_id=bench-build
common_gem5_build_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_build_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 "${common_root_dir}"
./build-all
./bench-boot
cp "$common_bench_boot" "$new_dir"
cd "${root_dir}"
"${root_dir}/build-all"
"${root_dir}/bench-boot" -t 3
cp "$(${root_dir}/getvar bench_boot)" "$new_dir"
fi
if "$update_repo"; then

View File

@ -1,5 +1,6 @@
#!/usr/bin/env bash
. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/common"
set -eu
root_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null && pwd)"
test_size=1
OPTIND=1
while getopts t: OPT; do
@ -16,56 +17,83 @@ while getopts t: OPT; do
esac
done
shift "$(($OPTIND - 1))"
extra_args="$*"
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() (
common_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"

17
bench-cmd Executable file
View File

@ -0,0 +1,17 @@
#!/usr/bin/env bash
# Benchmark a command as a string and output results
# to a file with format:
#
# cmd <command run>
# time <time in seconds to finish>
# exit_status <exit status>
set -eu
root_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null && pwd)"
# Command to benchmark
cmd="$1"
shift
# Where to append write results to. Default: /dev/null.
results_file="${1:-/dev/null}"
printf 'cmd ' >> "$results_file"
env time --append -f 'time %e' --output="$results_file" "${root_dir}/eeval" -a "$cmd" "$results_file"
printf "exit_status $?\n" >> "$results_file"

34
bisect-linux-boot-gem5 Executable file
View File

@ -0,0 +1,34 @@
#!/usr/bin/env python3
import imp
import os
import shutil
import sys
import common
build = imp.load_source('build', os.path.join(common.root_dir, 'build'))
run = imp.load_source('run', os.path.join(common.root_dir, 'run'))
parser = common.get_argparse(
argparse_args={
'description': '''Bisect the Linux kernel on gem5 boots.
More information at: https://github.com/cirosantilli/linux-kernel-module-cheat#bisection
'''},
default_args={
'gem5': True,
'linux_build_id': 'bisect',
},
)
args = common.setup(parser)
# We need a clean rebuild because rebuilds at different revisions:
# - may fail
# - may not actually rebuild all files, e.g. on header changes
common.rmrf(common.linux_variant_dir)
assert build.main(args) == 0
status = run.main(args, {
'eval': 'm5 exit',
})
if status == 125 or status == 127:
status = 1
sys.exit(status)

6
bisect-qemu-linux-boot Executable file
View File

@ -0,0 +1,6 @@
#!/usr/bin/env bash
set -eu
git submodule update
cd ..
./build-qemu --arch arm -Q bisect
./run --arch arm -E '/poweroff.out' -Q bisect

View File

@ -1,6 +0,0 @@
BR2_PACKAGE_HOST_QEMU=y
# False because otherwise we need the host to be as recent as guest, and the build fails with:
# package/qemu/qemu.mk:110: *** "Refusing to build qemu-user: target Linux version newer than host's.". Stop.
BR2_PACKAGE_HOST_QEMU_LINUX_USER_MODE=n
BR2_PACKAGE_HOST_QEMU_SYSTEM_MODE=y
BR2_PACKAGE_HOST_QEMU_VDE2=y

View File

@ -1,11 +1,17 @@
#!/usr/bin/env bash
. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/common"
while getopts "${common_getopts_flags}" OPT; do
case "$OPT" in
?)
common_getopts_case "$OPT"
;;
esac
done
shift "$(($OPTIND - 1))"
"${common_root_dir}/gem5-stat" -a "$common_arch" | awk 'NR % 2 { printf "%d %s ", NR/2, $0; next; } 1'
#!/usr/bin/env python3
import common
parser = common.get_argparse(
argparse_args={'description':'Convert a BST vs heap stat file into a gnuplot input'}
)
args = common.setup(parser)
stats = common.get_stats()
it = iter(stats)
i = 1
for stat in it:
try:
next_stat = next(it)
except StopIteration:
# Automatic dumpstats at end may lead to odd number of stats.
break
print('{} {} {}'.format(i, stat, next_stat))
i += 1

223
build
View File

@ -1,223 +0,0 @@
#!/usr/bin/env bash
. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/common"
mkdir -p "${common_out_dir}"
br2_cli_file="${common_out_dir}/br2_cli"
rm -f "$br2_cli_file"
touch "$br2_cli_file"
kernel_config_fragment_cli_file="${common_out_dir}/kernel_config_fragment_cli"
kernel_config_fragment_cli_file_tmp="${kernel_config_fragment_cli_file}_tmp"
rm -f "$kernel_config_fragment_cli_file_tmp"
touch "$kernel_config_fragment_cli_file_tmp"
configure=true
config_fragments="${common_root_dir}/br2/default"
extra_make_args=
j="$(nproc)"
linux_reconfigure=false
linux_kernel_custom_config_file=
kernel_config_fragments=
post_script_args=
qemu_sdl='--enable-sdl --with-sdlabi=2.0'
v=0
while getopts "B:b:C:c:fGj:hIiK:klp:qSs:v${common_getopts_flags}" OPT; do
case "$OPT" in
B)
echo "$OPTARG" >> "$br2_cli_file"
;;
b)
config_fragments="${config_fragments} $(common_abspath "${OPTARG}")"
;;
C)
echo "$OPTARG" >> "$kernel_config_fragment_cli_file_tmp"
;;
c)
kernel_config_fragments="${kernel_config_fragments} $(common_abspath "${OPTARG}")"
;;
f)
configure=false
;;
h)
echo "https://github.com/cirosantilli/linux-kernel-module-cheat#build" 2>&1
exit
;;
I)
echo "
BR2_TARGET_ROOTFS_CPIO=n
BR2_TARGET_ROOTFS_EXT2=n
BR2_TARGET_ROOTFS_INITRAMFS=y
" >> "$br2_cli_file"
;;
i)
echo "
BR2_TARGET_ROOTFS_CPIO=y
BR2_TARGET_ROOTFS_EXT2=n
BR2_TARGET_ROOTFS_INITRAMFS=n
" >> "$br2_cli_file"
;;
j)
j="$OPTARG"
;;
K)
linux_kernel_custom_config_file="$(common_abspath "${OPTARG}")"
;;
k)
extra_make_args="${extra_make_args} kernel_module-reconfigure \\
"
;;
l)
linux_reconfigure=true
extra_make_args="${extra_make_args} linux-reconfigure \\
"
;;
p)
post_script_args="$OPTARG"
;;
q)
extra_make_args="${extra_make_args} host-qemu-reconfigure \\
"
;;
S)
qemu_sdl=
;;
v)
v=1
;;
?)
common_getopts_case "$OPT"
;;
esac
done
shift $(($OPTIND - 1))
if "$common_gem5"; then
extra_make_args="${extra_make_args} gem5-reconfigure \\
"
fi
extra_make_args="${extra_make_args} $@"
common_setup
config_file="${common_buildroot_out_dir}/.config"
case "$common_arch" in
x86_64)
defconfig=qemu_x86_64_defconfig
;;
arm)
defconfig=qemu_arm_vexpress_defconfig
;;
aarch64)
defconfig=qemu_aarch64_virt_defconfig
;;
mips64)
defconfig=qemu_mips64r6_malta_defconfig
;;
esac
config_fragments="${config_fragments} ${common_root_dir}/br2/qemu ${br2_cli_file}"
time {
# Configure.
if "$configure"; then
if ! cmp "${kernel_config_fragment_cli_file}" "${kernel_config_fragment_cli_file_tmp}"; then
# Only copy if modified, otherwise the kernel always rebuilds.
cp "${kernel_config_fragment_cli_file_tmp}" "${kernel_config_fragment_cli_file}"
fi
cd "${common_buildroot_dir}"
for p in $(find "${common_root_dir}/patches/buildroot/" -maxdepth 1 -name '*.patch' -print); do
patch -N -r - -p 1 < "$p" || :
done
br2_external='../kernel_module:../gem5:../parsec-benchmark'
packages_dir="${common_root_dir}/packages"
for package_dir in "${packages_dir}"/*/; do
br2_external="${br2_external}:../packages/$(basename "${package_dir}")"
done
make O="$common_buildroot_out_dir" BR2_EXTERNAL="$br2_external" "$defconfig"
# TODO Can't get rid of these for now.
# http://stackoverflow.com/questions/44078245/is-it-possible-to-use-config-fragments-with-buildroots-config
for config_fragment in $config_fragments; do
cat "$config_fragment" >> "$config_file"
done
printf "
BR2_JLEVEL=${j}
BR2_DL_DIR=\"${common_dir}/dl\"
BR2_ROOTFS_POST_SCRIPT_ARGS=\"${post_script_args}\"
" >> "$config_file"
if "$common_gem5"; then
printf "BR2_PACKAGE_GEM5=y\n" >> "${config_file}"
fi
kernel_config_fragment_dir=../kernel_config_fragment
if [ -n "$linux_kernel_custom_config_file" ]; then
if [ -f "$linux_kernel_custom_config_file" ]; then
printf "BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y\nBR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE=\"${linux_kernel_custom_config_file}\"\n" >> "$config_file"
if "${linux_reconfigure}"; then
touch "${linux_kernel_custom_config_file}"
fi
else
echo "error: -K: file does not exist: ${linux_kernel_custom_config_file}" 1>&2
exit 1
fi
default_config_fragments=
else
default_config_fragments="${kernel_config_fragment_dir}/min ${kernel_config_fragment_dir}/default ${kernel_config_fragment_dir}/display"
fi
printf "BR2_LINUX_KERNEL_CONFIG_FRAGMENT_FILES=\"${default_config_fragments} ${kernel_config_fragments} ${kernel_config_fragment_cli_file}\"\n" >> "$config_file"
if "${linux_reconfigure}"; then
# https://stackoverflow.com/questions/49260466/why-when-i-change-br2-linux-kernel-custom-config-file-and-run-make-linux-reconfi
touch "${kernel_config_fragment_dir}/min"
fi
if [ "$common_arch" = 'mips64' ]; then
# Workaround for: https://bugs.busybox.net/show_bug.cgi?id=10276
sed -Ei 's/^BR2_PACKAGE_LINUX_TOOLS_GPIO/BR2_PACKAGE_LINUX_TOOLS_GPIO=n/' "$config_file"
fi
make O="$common_buildroot_out_dir" olddefconfig
fi
echo 'config time:'
}
echo
common_mkdir
# Manage Linux kernel and QEMU variants.
symlink_buildroot_variant() (
custom_dir="$1"
variant_dir="$2"
if [ -h "$custom_dir" ]; then
rm "$custom_dir"
elif [ -d "$custom_dir" ]; then
# Migration for existing builds.
mv "$custom_dir" "$variant_dir"
fi
mkdir -p "$variant_dir"
ln -s "$variant_dir" "$custom_dir"
)
symlink_buildroot_variant "$common_linux_custom_dir" "$common_linux_variant_dir"
symlink_buildroot_variant "$common_qemu_custom_dir" "$common_qemu_variant_dir"
# TODO: this breaks the build. But then I noticed that it wouldn't make sense,
# because this is a guest tool, and we don't have image variants yet. Some other day maybe.
#symlink_buildroot_variant "$common_qemu_guest_custom_dir" "$common_qemu_guest_variant_dir"
# Manage gem5 variants.
if "$common_gem5"; then
if [ ! -e "${common_gem5_src_dir}/.git" ]; then
git -C "$common_gem5_default_src_dir" worktree add -b "wt/${common_gem5_variant}" "${common_gem5_src_dir}"
fi
fi
cd "$common_buildroot_dir"
# HOST_QEMU_OPTS is a hack that happens to work because the QEMU package luckly uses += at all times.
# It shouldn't be necessary in the first place: https://bugs.busybox.net/show_bug.cgi?id=9936
#
# Even if were an autotools package, there is no general way currently to pass extra configs to it:
# https://stackoverflow.com/questions/44341188/how-to-pass-extra-custom-configure-autotools-options-to-a-buildroot-package/44341225#44341225
#
# BR2_ options may be given on the command line here, and they do have direct "define" effects.
# But this is generally bad, as it skips the Kconfig mechanism, e.g. it does not set defaults properly.
cmd="time \\
env \\
-u LD_LIBRARY_PATH \\
make \\
O='${common_buildroot_out_dir}' \\
HOST_QEMU_OPTS='--enable-debug --enable-trace-backends=simple ${qemu_sdl}' \\
GEM5_LKMC_GEM5_BUILD_TYPE="$common_gem5_build_type" \\
GEM5_LKMC_OUTDIR="$common_gem5_out_dir" \\
GEM5_LKMC_SRCDIR="$common_gem5_src_dir" \\
V='${v}' \\
${extra_make_args} \
all \\
"
"${common_root_dir}/eeval" "$cmd" "${common_out_arch_dir}/build.sh"

View File

@ -1,18 +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" -klq $gem5 "$@"
./build-qemu --arch "$arch"
./build --arch "$arch" --kernel-modules -l "$@"
if "$gem5"; then
./build-gem5 --arch "$arch"
fi
done

324
build-buildroot Executable file
View File

@ -0,0 +1,324 @@
#!/usr/bin/env python3
import multiprocessing
import os
import pathlib
import shutil
import subprocess
import sys
import re
import common
defaults = {
'baseline': False,
'buildroot_bare_kernel': False,
'buildroot_config': [],
'buildroot_config_fragment': [],
'initramfs': False,
'initrd': False,
'kernel_config': [],
'kernel_config_fragment': [],
'kernel_custom_config_file': None,
'kernel_modules': False,
'linux_reconfigure': False,
'no_all': False,
'nproc': None,
'skip_configure': False,
'verbose': False,
'extra_make_args': [],
}
def get_argparse():
parser = common.get_argparse(argparse_args={'description':'Run Linux on an emulator'})
common.add_build_arguments(parser)
parser.add_argument(
'-B', '--buildroot-config', default=defaults['buildroot_config'], action='append',
help='''Add a single Buildroot config to the current build.
Example value: 'BR2_TARGET_ROOTFS_EXT2_SIZE="512M"'.
Can be used multiple times to add multiple configs.
Takes precedence over any Buildroot config files.
'''
)
parser.add_argument(
'-b', '--buildroot-config-fragment', default=defaults['buildroot_config_fragment'], action='append',
help='''Also use the given Buildroot configuration fragment file.
Pass multiple times to use multiple fragment files.'''
)
parser.add_argument(
'--baseline', default=defaults['baseline'], action='store_true',
help='''Do a default-ish Buildroot defconfig build, without any of our extra options.
Mostly to track how much slower we are than a basic build.'''
)
parser.add_argument(
'-C', '--kernel-config', default=defaults['kernel_config'], action='append',
help='''Add a single kernel config configs to the current build.
Example value: 'CONFIG_FORTIFY_SOURCE=y'.
Can be used multiple times to add multiple configs.
Takes precedence over any Buildroot config files.
'''
)
parser.add_argument(
'-c', '--kernel-config-fragment', default=defaults['kernel_config_fragment'], action='append',
help='''Also use the given kernel configuration fragment file.
Pass multiple times to use multiple fragment files.'''
)
parser.add_argument(
'-I', '--initramfs', default=defaults['initramfs'], action='store_true',
)
parser.add_argument(
'-i', '--initrd', default=defaults['initrd'], action='store_true',
)
parser.add_argument(
'-j', '--nproc', default=defaults['nproc'], type=int,
help='Number of processors to use for the build. Default: all.'
)
parser.add_argument(
'-K', '--kernel-custom-config-file', default=defaults['kernel_custom_config_file'],
help='''Ignore all default kernel configurations and use this file instead.
Still uses options explicitly passed with `-C` and `-c` on top of it.'''
)
parser.add_argument(
'-k', '--kernel-modules', default=defaults['kernel_modules'], action='store_true',
help='Reconfigure and rebuild the kernel modules'
)
parser.add_argument(
'-l', '--linux-reconfigure', default=defaults['linux_reconfigure'], action='store_true',
help='''Reconfigure and rebuild the Linux kernel.
Touches kernel configuration files to overcome:
https://stackoverflow.com/questions/49260466/why-when-i-change-br2-linux-kernel-custom-config-file-and-run-make-linux-reconfi'''
)
parser.add_argument(
'--no-all', default=defaults['no_all'], action='store_true',
help='''Don't build the all target which normally gets build by default.
That target builds the root filesystem and all its dependencies.'''
)
parser.add_argument(
'--skip-configure', default=defaults['skip_configure'], action='store_true',
help='''Skip the Buildroot configuration. Saves a few seconds,
but requires you to know what you are doing :-)'''
)
parser.add_argument(
'-v', '--verbose', default=defaults['verbose'], action='store_true',
help='Do a verbose build'
)
parser.add_argument(
'extra_make_args', default=defaults['extra_make_args'], metavar='extra-make-args', nargs='*',
help='''Extra arguments to be passed to the Buildroot make,
usually extra Buildroot targets.'''
)
return parser
def main(args, extra_args=None):
global defaults
args = common.resolve_args(defaults, args, extra_args)
if args.clean:
common.rmrf(common.buildroot_build_dir)
else:
os.makedirs(common.out_dir, exist_ok=True)
extra_make_args = args.extra_make_args.copy()
if args.kernel_modules:
extra_make_args.append('kernel_modules-reconfigure')
if args.linux_reconfigure:
extra_make_args.append('linux-reconfigure')
if args.gem5:
extra_make_args.append('gem5-reconfigure')
if args.nproc is None:
nproc = multiprocessing.cpu_count()
else:
nproc = args.nproc
if args.arch == 'x86_64':
defconfig = 'qemu_x86_64_defconfig'
elif args.arch == 'arm':
defconfig = 'qemu_arm_vexpress_defconfig'
elif args.arch == 'aarch64':
defconfig = 'qemu_aarch64_virt_defconfig'
# Configure.
if not args.skip_configure:
# Initial make configure.
# TODO port and test.
#cd "${common_buildroot_src_dir}"
#for p in $(find "${common_root_dir}/patches/buildroot/" -maxdepth 1 -name '*.patch' -print); do
# patch -N -r - -p 1 < "$p" || :
#done
br2_external_dirs = []
packages_dir = os.path.join(common.root_dir, 'packages')
for package_dir in os.listdir(packages_dir):
package_dir_abs = os.path.join(packages_dir, package_dir)
if os.path.isdir(package_dir_abs):
br2_external_dirs.append(path_relative_to_buildroot(package_dir_abs))
br2_external_str = ':'.join(br2_external_dirs)
subprocess.check_call(
[
'make',
'O={}'.format(common.buildroot_build_dir),
'BR2_EXTERNAL={}'.format(br2_external_str),
defconfig,
],
cwd=common.buildroot_src_dir,
)
buildroot_configs = args.buildroot_config
buildroot_configs.extend([
'BR2_JLEVEL={}'.format(nproc),
'BR2_DL_DIR="{}"'.format(common.dl_dir),
])
write_configs(buildroot_configs)
if not args.baseline:
buildroot_configs.extend([
'BR2_GLOBAL_PATCH_DIR="{}"'.format(
path_relative_to_buildroot(os.path.join(common.root_dir, 'patches', 'global'))),
'BR2_PACKAGE_BUSYBOX_CONFIG_FRAGMENT_FILES="{}"'.format(
path_relative_to_buildroot(os.path.join(common.root_dir, 'busybox_config_fragment'))),
'BR2_PACKAGE_OVERRIDE_FILE="{}"'.format(
path_relative_to_buildroot(os.path.join(common.root_dir, 'buildroot_override'))),
'BR2_ROOTFS_OVERLAY="{}"'.format(
path_relative_to_buildroot(os.path.join(common.root_dir, 'rootfs_overlay'))),
'BR2_ROOTFS_POST_BUILD_SCRIPT="{}"'.format(
path_relative_to_buildroot(os.path.join(common.root_dir, 'rootfs_post_build_script'))),
'BR2_ROOTFS_USERS_TABLES="{}"'.format(
path_relative_to_buildroot(os.path.join(common.root_dir, 'user_table'))),
])
if args.gem5:
buildroot_configs.append('BR2_PACKAGE_GEM5=y')
if args.initramfs:
buildroot_configs.extend([
'BR2_TARGET_ROOTFS_CPIO=n',
'BR2_TARGET_ROOTFS_EXT2=n',
'BR2_TARGET_ROOTFS_INITRAMFS=y',
])
if args.initrd:
buildroot_configs.extend([
'BR2_TARGET_ROOTFS_CPIO=y',
'BR2_TARGET_ROOTFS_EXT2=n'
'BR2_TARGET_ROOTFS_INITRAMFS=n',
])
buildroot_config_fragments = [
os.path.join(common.root_dir, 'buildroot_config', 'default')
] + args.buildroot_config_fragment
# Decide kernel configuration.
kernel_config_fragments = []
if True:
# CLI kernel configurations.
kernel_config_fragment_cli_path = os.path.join(common.buildroot_build_dir, 'lkmc_kernel_config_fragment_cli')
kernel_config_cli_str = '\n'.join(args.kernel_config)
do_write = False
if os.path.exists(kernel_config_fragment_cli_path):
with open(kernel_config_fragment_cli_path, 'r') as kernel_config_fragment_cli_file:
kernel_config_cli_str_old = kernel_config_fragment_cli_file.read()
if kernel_config_cli_str != kernel_config_cli_str_old:
do_write = True
else:
do_write = True
if do_write:
# Only update if modified, otherwise Buildroot tries to
# rebuilds the kernel every time, which takes a few seconds.
# even when the kernel has already been built.
with open(kernel_config_fragment_cli_path, 'w') as kernel_config_fragment_cli_file:
kernel_config_fragment_cli_file.write(kernel_config_cli_str)
kernel_config_fragments.append(os.path.join(kernel_config_fragment_cli_path))
if True:
# Kernel configuration fragments.
if args.kernel_custom_config_file is not None:
if os.path.exists(args.kernel_custom_config_file):
buildroot_configs.extend([
'BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y',
'BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE=\"{}\"'.format(args.kernel_custom_config_file),
])
if args.linux_reconfigure:
pathlib.Path(args.kernel_custom_config_file).touch()
else:
raise Exception('Kernel config fragment file does not exist: {}'.format(args.kernel_custom_config_file))
default_kernel_config_fragments = []
else:
kernel_config_fragment_dir = os.path.join(common.root_dir, 'kernel_config')
default_kernel_config_fragments = ['min', 'default']
if args.linux_reconfigure:
# https://stackoverflow.com/questions/49260466/why-when-i-change-br2-linux-kernel-custom-config-file-and-run-make-linux-reconfi
pathlib.Path(os.path.join(kernel_config_fragment_dir, 'min')).touch()
for i, default_kernel_config_fragment in enumerate(default_kernel_config_fragments):
default_kernel_config_fragments[i] = os.path.join(kernel_config_fragment_dir, default_kernel_config_fragment)
kernel_config_fragments.extend(default_kernel_config_fragments)
for i, frag in enumerate(kernel_config_fragments):
kernel_config_fragments[i] = path_relative_to_buildroot(frag)
buildroot_kernel_config_fragment_str = 'BR2_LINUX_KERNEL_CONFIG_FRAGMENT_FILES="{}"'.format(' '.join(kernel_config_fragments))
buildroot_configs.append(buildroot_kernel_config_fragment_str)
write_configs(buildroot_configs, buildroot_config_fragments)
subprocess.check_call(
[
'make',
'O={}'.format(common.buildroot_build_dir),
'olddefconfig',
],
cwd=common.buildroot_src_dir,
)
# Manage Linux kernel and QEMU variants.
def symlink_buildroot_variant(custom_dir, variant_dir):
if os.path.islink(custom_dir):
os.unlink(custom_dir)
elif os.path.isdir(custom_dir):
# Migration for existing builds.
shutil.move(custom_dir, variant_dir)
os.makedirs(variant_dir, exist_ok=True)
os.symlink(variant_dir, custom_dir)
symlink_buildroot_variant(common.linux_build_dir, common.linux_variant_dir)
# Do the actual build.
common.mkdir()
if not args.no_all:
extra_make_args.append('all')
assert common.run_cmd(
[
'make',
'LKMC_GEM5_SRCDIR="{}"'.format(common.gem5_src_dir),
'LKMC_PARSEC_BENCHMARK_SRCDIR="{}"'.format(common.parsec_benchmark_src_dir),
'O={}'.format(common.buildroot_build_dir),
'V={}'.format(int(args.verbose)),
] +
extra_make_args
,
out_file=os.path.join(common.buildroot_build_dir, 'lkmc.log'),
delete_env=['LD_LIBRARY_PATH'],
cwd=common.buildroot_src_dir,
) == 0
# Create the qcow2 from ext2. This is optional, because gem5
# does not need the qcow2.
if os.path.exists(common.qemu_img_executable) and os.path.exists(common.ext2_file):
assert common.run_cmd([
common.qemu_img_executable,
'-T', 'pr_manager_run,file=/dev/null',
'convert',
'-f', 'raw',
'-O', 'qcow2',
common.ext2_file,
common.qcow2_file,
]) == 0
return 0
def path_relative_to_buildroot(abspath):
return os.path.relpath(abspath, common.buildroot_src_dir)
def write_configs(buildroot_configs, buildroot_config_fragments=None):
"""
Write extra configs into the Buildroot config file.
TODO Can't get rid of these for now with nice fragments:
http://stackoverflow.com/questions/44078245/is-it-possible-to-use-config-fragments-with-buildroots-config
"""
if buildroot_config_fragments is None:
buildroot_config_fragments = []
with open(common.buildroot_config_file, 'a') as br2_config_file:
for buildroot_config_fragment in buildroot_config_fragments:
with open(buildroot_config_fragment, 'r') as br2_config_fragment:
for line in br2_config_fragment:
br2_config_file.write(line)
for buildroot_config in buildroot_configs:
br2_config_file.write(buildroot_config + '\n')
if __name__ == '__main__':
parser = get_argparse()
args = common.setup(parser)
sys.exit(main(args))

83
build-gem5 Executable file
View File

@ -0,0 +1,83 @@
#!/usr/bin/env python3
import glob
import multiprocessing
import os
import pathlib
import shutil
import subprocess
import common
parser = common.get_argparse()
common.add_build_arguments(parser)
parser.add_argument(
'extra_scons_args',
default=[],
metavar='extra-scons-args',
nargs='*'
)
args = common.setup(parser)
binaries_dir = os.path.join(common.gem5_system_dir, 'binaries')
disks_dir = os.path.join(common.gem5_system_dir, 'disks')
if args.clean:
common.rmrf(common.gem5_build_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)
# 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)

41
build-qemu Executable file
View File

@ -0,0 +1,41 @@
#!/usr/bin/env python3
import multiprocessing
import os
import subprocess
import common
parser = common.get_argparse()
common.add_build_arguments(parser)
parser.add_argument(
'extra_config_args',
default=[],
metavar='extra-config-args',
nargs='*'
)
args = common.setup(parser)
if args.clean:
common.rmrf(common.qemu_build_dir)
else:
os.makedirs(common.qemu_build_dir, exist_ok=True)
subprocess.check_call(
[
os.path.join(common.qemu_src_dir, 'configure'),
'--enable-debug',
'--enable-trace-backends=simple',
'--target-list={}-softmmu'.format(args.arch),
'--enable-sdl',
'--with-sdlabi=2.0',
] +
args.extra_config_args,
cwd=common.qemu_build_dir
)
subprocess.check_call(
[
'make',
# TODO factor with build.
'-j', str(multiprocessing.cpu_count()),
],
cwd=common.qemu_build_dir
)

View File

@ -1,6 +1,17 @@
# Custom packages
BR2_PACKAGE_KERNEL_MODULE=y
BR2_SAMPLE_PACKAGE=y
# Toolchain options.
# Enable as much visibility as possible.
BR2_CCACHE=y
BR2_CCACHE_USE_BASEDIR=n
BR2_DEBUG_3=y
BR2_ENABLE_DEBUG=y
BR2_GCC_ENABLE_GRAPHITE=y
BR2_GCC_ENABLE_LTO=y
BR2_GCC_ENABLE_OPENMP=y
BR2_OPTIMIZE_0=y
BR2_PTHREAD_DEBUG=y
BR2_TOOLCHAIN_BUILDROOT_CXX=y
BR2_TOOLCHAIN_BUILDROOT_FORTRAN=y
BR2_TOOLCHAIN_BUILDROOT_WCHAR=y
# Rootfs
BR2_TARGET_ROOTFS_CPIO=n
@ -8,43 +19,6 @@ BR2_TARGET_ROOTFS_EXT2=y
BR2_TARGET_ROOTFS_INITRAMFS=n
BR2_TARGET_ROOTFS_EXT2_SIZE="512M"
# We were tempted to do this to disable S40network neatly,
# but that package also creates extra configuration files
# such as /etc/network/interfaces which we need. So we just
# remove the init.d file for now.
#BR2_PACKAGE_IFUPDOWN_SCRIPTS=n
# Misc
BR2_CCACHE=y
# Otherwise our precious debug would break!
BR2_CCACHE_USE_BASEDIR=n
BR2_GCC_ENABLE_GRAPHITE=y
BR2_GCC_ENABLE_LTO=y
BR2_GCC_ENABLE_OPENMP=y
BR2_GLOBAL_PATCH_DIR="../patches/global"
BR2_PACKAGE_BUSYBOX_CONFIG_FRAGMENT_FILES="../busybox_config_fragment"
BR2_PACKAGE_DHRYSTONE=y
BR2_PACKAGE_FILE=y
BR2_PACKAGE_OVERRIDE_FILE="../buildroot_override"
BR2_PACKAGE_PCIUTILS=y
# For qemu-ga on guest. TODO: do something with it, and document it.
# Maybe: https://superuser.com/questions/930588/how-to-pass-commands-noninteractively-to-running-qemu-from-the-guest-qmp-via-te
BR2_PACKAGE_QEMU=y
BR2_PACKAGE_STRACE=y
BR2_ROOTFS_OVERLAY="../rootfs_overlay"
BR2_ROOTFS_POST_BUILD_SCRIPT="../rootfs_post_build_script"
BR2_ROOTFS_POST_IMAGE_SCRIPT="../rootfs_post_image_script"
BR2_ROOTFS_USERS_TABLES="../user_table"
BR2_TOOLCHAIN_BUILDROOT_CXX=y
BR2_TOOLCHAIN_BUILDROOT_FORTRAN=y
BR2_TOOLCHAIN_BUILDROOT_WCHAR=y
# lscpu: TODO not installing?
BR2_PACKAGE_UTIL_LINUX=y
BR2_PACKAGE_UTIL_LINUX_BINARIES=y
# taskset
BR2_PACKAGE_UTIL_LINUX_SCHEDUTILS=y
# Host GDB
BR2_GDB_VERSION="7.11.1"
BR2_GDB_VERSION_7_10=n
@ -55,12 +29,32 @@ BR2_PACKAGE_HOST_GDB_PYTHON=y
BR2_PACKAGE_HOST_GDB_SIM=y
BR2_PACKAGE_HOST_GDB_TUI=y
# Custom packages
# Keepding those in because we control them fully
# and know for sure that are small.
BR2_PACKAGE_KERNEL_MODULES=y
BR2_SAMPLE_PACKAGE=y
# We were tempted to do this to disable S40network neatly,
# but that package also creates extra configuration files
# such as /etc/network/interfaces which we need. So we just
# remove the init.d file for now.
#BR2_PACKAGE_IFUPDOWN_SCRIPTS=n
# misc packages
BR2_PACKAGE_DHRYSTONE=y
BR2_PACKAGE_FILE=y
BR2_PACKAGE_PCIUTILS=y
BR2_PACKAGE_STRACE=y
# lscpu: TODO not installing?
BR2_PACKAGE_UTIL_LINUX=y
BR2_PACKAGE_UTIL_LINUX_BINARIES=y
# taskset
BR2_PACKAGE_UTIL_LINUX_SCHEDUTILS=y
# gdbserver
BR2_DEBUG_3=y
BR2_ENABLE_DEBUG=y
BR2_OPTIMIZE_0=y
BR2_PACKAGE_GDB=y
BR2_PTHREAD_DEBUG=y
# ftrace
BR2_PACKAGE_TRACE_CMD=y

View File

@ -1,5 +1,2 @@
HOST_QEMU_OVERRIDE_SRCDIR = ../qemu
LINUX_OVERRIDE_SRCDIR = ../linux
PARSEC_BENCHMARK_OVERRIDE_SRCDIR = ../parsec-benchmark/parsec-benchmark
QEMU_OVERRIDE_SRCDIR = ../qemu
# UCLIBC_OVERRIDE_SRCDIR = ../uclibc-ng
LINUX_OVERRIDE_SRCDIR = ../../submodules/linux
QEMU_OVERRIDE_SRCDIR = ../../submodules/qemu

204
common
View File

@ -1,204 +0,0 @@
#!/usr/bin/env bash
set -eu
common_abspath() (
echo "$(cd "$(dirname "$1")"; pwd)/$(basename "$1")"
)
# Benchmark a command.
#
# $1: command to benchmark
# $2: where to append write results to. Default: /dev/null.
#
# Result format:
#
# cmd <command run>
# time <time in seconds to finish>
# exit_status <exit status>
common_bench_cmd() (
cmd="$1"
results_file="${2:-/dev/null}"
printf 'cmd ' >> "$results_file"
env time --append -f 'time %e' --output="$results_file" "${common_root_dir}/eeval" -a "$cmd" "$results_file"
printf "exit_status $?\n" >> "$results_file"
)
# Handle options common across multiple scripts.
common_getopts_case() {
case "$1" in
a)
common_arch="$OPTARG"
;;
g)
common_gem5=true
;;
L)
common_linux_variant="$OPTARG"
;;
M)
common_gem5_variant="$OPTARG"
;;
N)
common_gem5_worktree="$OPTARG"
;;
n)
common_run_id="$OPTARG"
;;
Q)
common_qemu_variant="$OPTARG"
;;
s)
common_suffix="$OPTARG"
;;
t)
common_gem5_build_type="$OPTARG"
;;
?)
exit 2
;;
esac
}
common_getopts_flags='a:gL:M:N:n:Q:s:t:'
# Setup several variables and do other initialization common to most scripts.
# Typically done after getting inputs from the command line arguments.
common_setup() {
case "$common_arch" in
a|arm)
common_arch=arm
common_gem5_arch=ARM
;;
A|aarch64)
common_arch=aarch64
common_gem5_arch=ARM
;;
m|mips64)
common_arch=mips64
;;
x|x86_64)
common_arch=x86_64
common_gem5_arch=X86
;;
*)
printf "unknown arch: ${common_arch}\n" 1>&2
exit 2
;;
esac
common_buildroot_dir="${common_root_dir}/buildroot"
common_arch_dir="$common_arch"
if [ -n "$common_suffix" ]; then
common_arch_dir="${common_arch_dir}-${common_suffix}"
fi
common_out_arch_dir="${common_out_dir}/${common_arch_dir}"
common_buildroot_out_dir="${common_out_arch_dir}/buildroot"
common_build_dir="${common_buildroot_out_dir}/build"
common_linux_custom_dir="${common_build_dir}/linux-custom"
common_linux_variant_dir="${common_linux_custom_dir}.${common_linux_variant}"
common_vmlinux="${common_linux_variant_dir}/vmlinux"
common_qemu_custom_dir="${common_build_dir}/host-qemu-custom"
common_qemu_guest_variant_dir="${common_qemu_custom_dir}.${common_qemu_variant}"
common_qemu_variant_dir="${common_qemu_custom_dir}.${common_qemu_variant}"
common_qemu_exec="${common_qemu_variant_dir}/${common_arch}-softmmu/qemu-system-${common_arch}"
common_qemu_guest_custom_dir="${common_build_dir}/qemu-custom"
common_host_dir="${common_buildroot_out_dir}/host"
common_images_dir="${common_buildroot_out_dir}/images"
common_qcow2_file="${common_images_dir}/rootfs.ext2.qcow2"
common_staging_dir="${common_buildroot_out_dir}/staging"
common_target_dir="${common_buildroot_out_dir}/target"
common_gem5_run_dir="${common_out_arch_dir}/gem5/${common_run_id}"
common_m5out_dir="${common_gem5_run_dir}/m5out"
common_trace_txt_file="${common_m5out_dir}/trace.txt"
common_gem5_termout_file="${common_gem5_run_dir}/termout.txt"
common_qemu_run_dir="${common_out_arch_dir}/qemu/${common_run_id}"
common_qemu_termout_file="${common_qemu_run_dir}/termout.txt"
common_qemu_rrfile="${common_qemu_run_dir}/rrfile"
common_gem5_out_dir="${common_dir}/gem5/${common_gem5_variant}"
common_gem5_m5term="${common_gem5_out_dir}/m5term"
common_gem5_build_dir="${common_gem5_out_dir}/build"
common_gem5_exec="${common_gem5_build_dir}/${common_gem5_arch}/gem5.${common_gem5_build_type}"
common_gem5_system_dir="${common_gem5_out_dir}/system"
if [ -n "$common_gem5_worktree" ]; then
common_gem5_src_dir="${common_gem5_non_default_src_root_dir}/${common_gem5_worktree}"
else
common_gem5_src_dir="$common_gem5_default_src_dir"
fi
if "$common_gem5"; then
common_exec="$common_gem5_exec"
common_run_dir="$common_gem5_run_dir"
common_termout_file="$common_gem5_termout_file"
else
common_exec="$common_qemu_exec"
common_run_dir="$common_qemu_run_dir"
common_termout_file="$common_qemu_termout_file"
fi
case "$common_arch" in
arm)
common_linux_image=arch/arm/boot/zImage
;;
aarch64)
common_linux_image=arch/arm64/boot/Image
;;
mips64)
common_linux_image=vmlinux
;;
x86_64)
common_linux_image=arch/x86/boot/bzImage
;;
esac
common_linux_image="${common_linux_variant_dir}/${common_linux_image}"
# Ports.
common_run_id_number="$(echo "$common_run_id" | cut -d . -f 2)"
if "$common_gem5"; then
common_gem5_telnet_port="$((3456 + $common_run_id_number))"
common_gdb_port="$((7000 + $common_run_id_number))"
else
common_qemu_base_port="$((45454 + 10 * $common_run_id_number))"
common_qemu_monitor_port="$(($common_qemu_base_port + 0))"
common_qemu_hostfwd_generic_port="$(($common_qemu_base_port + 1))"
common_qemu_hostfwd_ssh_port="$(($common_qemu_base_port + 2))"
common_qemu_gdb_port="$(($common_qemu_base_port + 3))"
common_gdb_port="$common_qemu_gdb_port"
fi
}
common_mkdir() (
mkdir -p \
"$common_build_dir" \
"$common_gem5_out_dir" \
"$common_gem5_run_dir" \
"$common_qemu_run_dir" \
"$common_9p_dir" \
;
)
# Default paths.
common_root_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
common_data_dir="${common_root_dir}/data"
common_9p_dir="${common_data_dir}/9p"
common_gem5_non_default_src_root_dir="${common_data_dir}/gem5"
common_gem5_readfile_file="${common_data_dir}/readfile"
common_gem5_default_src_dir="${common_root_dir}/gem5/gem5"
common_out_dir="${common_root_dir}/out"
common_bench_boot="${common_out_dir}/bench-boot.txt"
common_dir="${common_out_dir}/common"
# Other default variables.
common_arch=x86_64
common_gem5=false
common_gem5_build_type=opt
common_gem5_cpt_pref='^cpt\.'
common_gem5_variant=default
common_gem5_worktree=
common_linux_variant=default
common_qemu_variant=default
common_run_id=0
common_sha="$(git log -1 --format="%H")"
common_suffix=
f="${common_data_dir}/config"
if [ -f "$f" ]; then
. "$f"
fi

395
common.py Normal file
View File

@ -0,0 +1,395 @@
#!/usr/bin/env python3
import argparse
import base64
import copy
import glob
import imp
import os
import re
import shlex
import shutil
import signal
import stat
import subprocess
import sys
this = sys.modules[__name__]
# Default paths.
root_dir = os.path.dirname(os.path.abspath(__file__))
data_dir = os.path.join(root_dir, 'data')
p9_dir = os.path.join(data_dir, '9p')
gem5_non_default_src_root_dir = os.path.join(data_dir, 'gem5')
out_dir = os.path.join(root_dir, 'out')
bench_boot = os.path.join(out_dir, 'bench-boot.txt')
dl_dir = os.path.join(out_dir, 'dl')
submodules_dir = os.path.join(root_dir, 'submodules')
buildroot_src_dir = os.path.join(submodules_dir, 'buildroot')
gem5_default_src_dir = os.path.join(submodules_dir, 'gem5')
linux_src_dir = os.path.join(submodules_dir, 'linux')
qemu_src_dir = os.path.join(submodules_dir, 'qemu')
parsec_benchmark_src_dir = os.path.join(submodules_dir, 'parsec-benchmark')
# Other default variables.
arch_map = {
'a': 'arm',
'A': 'aarch64',
'x': 'x86_64',
}
arches = [arch_map[k] for k in arch_map]
gem5_cpt_prefix = '^cpt\.'
sha = subprocess.check_output(['git', '-C', root_dir, 'log', '-1', '--format=%H']).decode().rstrip()
config_file = os.path.join(data_dir, 'config')
if os.path.exists(config_file):
config = imp.load_source('config', config_file)
configs = {x:getattr(config, x) for x in dir(config) if not x.startswith('__')}
def base64_encode(string):
return base64.b64encode(string.encode()).decode()
def gem_list_checkpoint_dirs():
'''
List checkpoint directory, oldest first.
'''
global this
prefix_re = re.compile(this.gem5_cpt_prefix)
files = list(filter(lambda x: os.path.isdir(os.path.join(this.m5out_dir, x)) and prefix_re.search(x), os.listdir(this.m5out_dir)))
files.sort(key=lambda x: os.path.getmtime(os.path.join(this.m5out_dir, x)))
return files
def get_argparse(default_args=None, argparse_args=None):
'''
Return an argument parser with common arguments set.
:type default_args: Dict[str,str]
:type argparse_args: Dict
'''
global this
if default_args is None:
default_args = {}
if argparse_args is None:
argparse_args = {}
arch_choices = []
for key in this.arch_map:
arch_choices.append(key)
arch_choices.append(this.arch_map[key])
default_build_id = 'default'
parser = argparse.ArgumentParser(
formatter_class=argparse.RawTextHelpFormatter,
**argparse_args
)
parser.add_argument(
'-a', '--arch', choices=arch_choices, default='x86_64',
help='CPU architecture. Default: %(default)s'
)
parser.add_argument(
'-g', '--gem5', default=False, action='store_true',
help='Use gem5 instead of QEMU'
)
parser.add_argument(
'-L', '--linux-build-id', default=default_build_id,
help='Linux build ID. Allows you to keep multiple separate Linux builds. Default: %(default)s'
)
parser.add_argument(
'-M', '--gem5-build-id', default=default_build_id,
help='gem5 build ID. Allows you to keep multiple separate gem5 builds. Default: %(default)s'
)
parser.add_argument(
'-N', '--gem5-worktree',
help='''\
gem5 git worktree to use for build and Python scripts at runtime. Automatically
create a new git worktree with the given id if one does not exist. If not
given, just use the submodule source.
'''
)
parser.add_argument(
'-n', '--run-id', default='0',
help='''\
ID for run outputs such as gem5's m5out. Allows you to do multiple runs,
and then inspect separate outputs later in different output directories.
Default: %(default)s
'''
)
parser.add_argument(
'--port-offset', type=int,
help='''\
Increase the ports to be used such as for GDB by an offset to run multiple
instances in parallel.
Default: the run ID (-n) if that is an integer, otherwise 0.
'''
)
parser.add_argument(
'-Q', '--qemu-build-id', default=default_build_id,
help='QEMU build ID. Allows you to keep multiple separate QEMU builds. Default: %(default)s'
)
parser.add_argument(
'--buildroot-build-id',
default=default_build_id,
help='Buildroot build ID. Allows you to keep multiple separate gem5 builds. Default: %(default)s'
)
parser.add_argument(
'-t', '--gem5-build-type', default='opt',
help='gem5 build type, most often used for "debug" builds. Default: %(default)s'
)
if hasattr(this, 'configs'):
defaults = this.configs.copy()
else:
defaults = {}
defaults.update(default_args)
# A bit ugly as it actually changes the defaults shown on --help, but we can't do any better
# because it is impossible to check if arguments were given or not...
# - https://stackoverflow.com/questions/30487767/check-if-argparse-optional-argument-is-set-or-not
# - https://stackoverflow.com/questions/3609852/which-is-the-best-way-to-allow-configuration-options-be-overridden-at-the-comman
parser.set_defaults(**defaults)
return parser
def add_build_arguments(parser):
parser.add_argument(
'--clean',
help='Clean the build instead of building.',
action='store_true',
)
def get_elf_entry(elf_file_path):
global this
readelf_header = subprocess.check_output([
this.get_toolchain_tool('readelf'),
'-h',
elf_file_path
])
for line in readelf_header.decode().split('\n'):
split = line.split()
if line.startswith(' Entry point address:'):
addr = line.split()[-1]
break
return int(addr, 0)
def get_stats(stat_re=None, stats_file=None):
global this
if stat_re is None:
stat_re = '^system.cpu[0-9]*.numCycles$'
if stats_file is None:
stats_file = this.stats_file
stat_re = re.compile(stat_re)
ret = []
with open(stats_file, 'r') as statfile:
for line in statfile:
if line[0] != '-':
cols = line.split()
if len(cols) > 1 and stat_re.search(cols[0]):
ret.append(cols[1])
return ret
def get_toolchain_tool(tool):
global this
return glob.glob(os.path.join(this.host_bin_dir, '*-buildroot-*-{}'.format(tool)))[0]
def log_error(msg):
print('error: {}'.format(msg), file=sys.stderr)
def print_cmd(cmd, cmd_file=None, extra_env=None):
'''
Format a command given as a list of strings so that it can
be viewed nicely and executed by bash directly and print it to stdout.
Optionally save the command to cmd_file file, and add extra_env
environment variables to the command generated.
'''
newline_separator = ' \\\n'
out = []
for key in extra_env:
out.extend(['{}={}'.format(shlex.quote(key), shlex.quote(extra_env[key])), newline_separator])
for arg in cmd:
out.extend([shlex.quote(arg), newline_separator])
out = ''.join(out)
print(out)
if cmd_file is not None:
with open(cmd_file, 'w') as f:
f.write('#!/usr/bin/env bash\n')
f.write(out)
st = os.stat(cmd_file)
os.chmod(cmd_file, st.st_mode | stat.S_IXUSR)
def resolve_args(defaults, args, extra_args):
if extra_args is None:
extra_args = {}
argcopy = copy.copy(args)
argcopy.__dict__ = dict(list(defaults.items()) + list(argcopy.__dict__.items()) + list(extra_args.items()))
return argcopy
def rmrf(path):
if os.path.exists(path):
shutil.rmtree(path)
def run_cmd(
cmd,
cmd_file=None,
out_file=None,
show_stdout=True,
show_cmd=True,
extra_env=None,
delete_env=None,
**kwargs
):
'''
Run a command. Write the command to stdout before running it.
Wait until the command finishes execution.
:param cmd: command to run
:type cmd: List[str]
:param cmd_file: if not None, write the command to be run to that file
:type cmd_file: str
:param out_file: if not None, write the stdout and stderr of the command the file
:type out_file: str
:param show_stdout: wether to show stdout and stderr on the terminal or not
:type show_stdout: bool
:param extra_env: extra environment variables to add when running the command
:type extra_env: Dict[str,str]
'''
if out_file is not None:
stdout = subprocess.PIPE
stderr = subprocess.STDOUT
else:
if show_stdout:
stdout = None
stderr = None
else:
stdout = subprocess.DEVNULL
stderr = subprocess.DEVNULL
if extra_env is None:
extra_env = {}
if delete_env is None:
delete_env = []
env = os.environ.copy()
env.update(extra_env)
for key in delete_env:
del env[key]
if show_cmd:
print_cmd(cmd, cmd_file, extra_env=extra_env)
# Otherwise Ctrl + C gives:
# - ugly Python stack trace for gem5 (QEMU takes over terminal and is fine).
# - kills Python, and that then kills GDB: https://stackoverflow.com/questions/19807134/does-python-always-raise-an-exception-if-you-do-ctrlc-when-a-subprocess-is-exec
signal.signal(signal.SIGINT, signal.SIG_IGN)
# https://stackoverflow.com/questions/15535240/python-popen-write-to-stdout-and-log-file-simultaneously/52090802#52090802
with subprocess.Popen(cmd, stdout=stdout, stderr=stderr, env=env, **kwargs) as proc:
if out_file is not None:
with open(out_file, 'bw') as logfile:
while True:
byte = proc.stdout.read(1)
if byte:
if show_stdout:
sys.stdout.buffer.write(byte)
sys.stdout.flush()
logfile.write(byte)
else:
break
signal.signal(signal.SIGINT, signal.SIG_DFL)
return proc.returncode
def setup(parser, **extra_args):
'''
Parse the command line arguments, and setup several variables based on them.
Typically done after getting inputs from the command line arguments.
'''
global this
args = parser.parse_args()
if args.arch in this.arch_map:
args.arch = this.arch_map[args.arch]
if args.arch == 'arm':
this.armv = 7
this.gem5_arch = 'ARM'
elif args.arch == 'aarch64':
this.armv = 8
this.gem5_arch = 'ARM'
elif args.arch == 'x86_64':
this.gem5_arch = 'X86'
this.buildroot_build_dir = os.path.join(this.out_dir, 'buildroot', args.arch, args.buildroot_build_id)
this.buildroot_config_file = os.path.join(this.buildroot_build_dir, '.config')
this.build_dir = os.path.join(this.buildroot_build_dir, 'build')
this.linux_build_dir = os.path.join(this.build_dir, 'linux-custom')
this.linux_variant_dir = '{}.{}'.format(this.linux_build_dir, args.linux_build_id)
this.vmlinux = os.path.join(this.linux_variant_dir, "vmlinux")
this.qemu_build_dir = os.path.join(this.out_dir, 'qemu', args.qemu_build_id)
this.qemu_executable = os.path.join(this.qemu_build_dir, '{}-softmmu'.format(args.arch), 'qemu-system-{}'.format(args.arch))
this.qemu_img_executable = os.path.join(this.qemu_build_dir, 'qemu-img')
this.qemu_guest_build_dir = os.path.join(this.build_dir, 'qemu-custom')
this.host_dir = os.path.join(this.buildroot_build_dir, 'host')
this.host_bin_dir = os.path.join(this.host_dir, 'usr', 'bin')
this.images_dir = os.path.join(this.buildroot_build_dir, 'images')
this.ext2_file = os.path.join(this.images_dir, 'rootfs.ext2')
this.qcow2_file = os.path.join(this.images_dir, 'rootfs.ext2.qcow2')
this.staging_dir = os.path.join(this.buildroot_build_dir, 'staging')
this.target_dir = os.path.join(this.buildroot_build_dir, 'target')
this.run_dir_base = os.path.join(this.out_dir, 'run')
this.gem5_run_dir = os.path.join(this.run_dir_base, 'gem5', args.arch, str(args.run_id))
this.m5out_dir = os.path.join(this.gem5_run_dir, 'm5out')
this.stats_file = os.path.join(this.m5out_dir, 'stats.txt')
this.trace_txt_file = os.path.join(this.m5out_dir, 'trace.txt')
this.gem5_readfile = os.path.join(this.gem5_run_dir, 'readfile')
this.gem5_termout_file = os.path.join(this.gem5_run_dir, 'termout.txt')
this.qemu_run_dir = os.path.join(this.run_dir_base, 'qemu', args.arch, str(args.run_id))
this.qemu_trace_basename = 'trace.bin'
this.qemu_trace_file = os.path.join(this.qemu_run_dir, 'trace.bin')
this.qemu_trace_txt_file = os.path.join(this.qemu_run_dir, 'trace.txt')
this.qemu_termout_file = os.path.join(this.qemu_run_dir, 'termout.txt')
this.qemu_rrfile = os.path.join(this.qemu_run_dir, 'rrfile')
this.gem5_build_dir = os.path.join(this.out_dir, 'gem5', args.gem5_build_id)
this.gem5_m5term = os.path.join(this.gem5_build_dir, 'm5term')
this.gem5_build_build_dir = os.path.join(this.gem5_build_dir, 'build')
this.gem5_executable = os.path.join(this.gem5_build_build_dir, gem5_arch, 'gem5.{}'.format(args.gem5_build_type))
this.gem5_system_dir = os.path.join(this.gem5_build_dir, 'system')
if args.gem5_worktree is not None:
this.gem5_src_dir = os.path.join(this.gem5_non_default_src_root_dir, args.gem5_worktree)
else:
this.gem5_src_dir = this.gem5_default_src_dir
if args.gem5:
this.executable = this.gem5_executable
this.run_dir = this.gem5_run_dir
this.termout_file = this.gem5_termout_file
else:
this.executable = this.qemu_executable
this.run_dir = this.qemu_run_dir
this.termout_file = this.qemu_termout_file
this.gem5_config_dir = os.path.join(this.gem5_src_dir, 'configs')
this.gem5_se_file = os.path.join(this.gem5_config_dir, 'example', 'se.py')
this.gem5_fs_file = os.path.join(this.gem5_config_dir, 'example', 'fs.py')
this.run_cmd_file = os.path.join(this.run_dir, 'run.sh')
if args.arch == 'arm':
this.linux_image = os.path.join('arch', 'arm', 'boot', 'zImage')
elif args.arch == 'aarch64':
this.linux_image = os.path.join('arch', 'arm64', 'boot', 'Image')
elif args.arch == 'x86_64':
this.linux_image = os.path.join('arch', 'x86', 'boot', 'bzImage')
this.linux_image = os.path.join(this.linux_variant_dir, linux_image)
# Ports.
if args.port_offset is None:
try:
args.port_offset = int(args.run_id)
except ValueError:
args.port_offset = 0
if args.gem5:
this.gem5_telnet_port = 3456 + args.port_offset
this.gdb_port = 7000 + args.port_offset
else:
this.qemu_base_port = 45454 + 10 * args.port_offset
this.qemu_monitor_port = this.qemu_base_port + 0
this.qemu_hostfwd_generic_port = this.qemu_base_port + 1
this.qemu_hostfwd_ssh_port = this.qemu_base_port + 2
this.qemu_gdb_port = this.qemu_base_port + 3
this.gdb_port = this.qemu_gdb_port
return args
def mkdir():
global this
os.makedirs(this.build_dir, exist_ok=True)
os.makedirs(this.gem5_build_dir, exist_ok=True)
os.makedirs(this.gem5_run_dir, exist_ok=True)
os.makedirs(this.qemu_run_dir, exist_ok=True)
os.makedirs(this.p9_dir, exist_ok=True)

View File

@ -1,3 +1,4 @@
#!/usr/bin/env bash
common_arch=aarch64
common_gem5=true
#!/usr/bin/env python
arch = 'aarch64'
gem5 = True
run_id = 'asdf'

14
configure vendored
View File

@ -1,5 +1,5 @@
#!/usr/bin/env bash
set -e
set -eu
interactive_pkgs=libsdl2-dev
gem5=false
qemu=true
@ -11,7 +11,7 @@ while getopts gpqt OPT; do
gem5=true
;;
p)
submodules="$submodules parsec-benchmark/parsec-benchmark"
submodules="${submodules} parsec-benchmark"
;;
q)
qemu=false
@ -100,11 +100,12 @@ fi
## Submodules
if "$qemu"; then
submodules="$submodules qemu"
submodules="${submodules} qemu"
fi
if "$gem5"; then
submodules="$submodules gem5/gem5"
submodules="${submodules} gem5"
fi
submodules="$(for submodule in ${submodules}; do printf "submodules/${submodule} "; done)"
(
set -e
# Shallow cloning saves a considerable amount of time, specially because of the linux kernel.
@ -113,10 +114,9 @@ fi
# In particular:
# - `shallow = true` on the submodule has no effect for the non default educational branches of our submodules
# - QEMU's submodules point to commits that are neither under branches nor tags, and so `--shallow-submodules` fails
git submodule update --depth 1 $gitjobs --init -- $submodules
git submodule update --depth 1 $gitjobs --init -- ${submodules}
if "$qemu"; then
cd qemu
git submodule update --init --recursive
git -C submodules/qemu submodule update --init --recursive
fi
) &
# https://unix.stackexchange.com/questions/65532/why-does-set-e-not-work-inside-subshells-with-parenthesis-followed-by-an-or

3
eeval
View File

@ -1,5 +1,6 @@
#!/usr/bin/env bash
# echo and eval
# echo a command and eval it.
# Can also print the command to a file.
set -e
a=
while getopts a OPT; do

View File

@ -1,72 +1,72 @@
#!/usr/bin/env bash
. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/common"
common_gem5=true
set -eu
root_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null && pwd)"
generate_checkpoints=true
while getopts "C${common_getopts_flags}" OPT; do
while getopts "C" OPT; do
case "$OPT" in
C)
generate_checkpoints=false
;;
?)
common_getopts_case "$OPT"
exit 2;
;;
esac
done
shift "$(($OPTIND - 1))"
common_setup
common_opts="--gem5 $@"
# Vars
cmd="./run -a ${common_arch} -g"
cmd="./run ${common_opts}"
cache_small='--caches --l2cache --l1d_size=1024 --l1i_size=1024 --l2_size=1024 --l3_size=1024 '
cache_large='--caches --l2cache --l1d_size=1024kB --l1i_size=1024kB --l2_size=1024kB --l3_size=1024kB'
results_file="${common_gem5_run_dir}/bench-cache.txt"
results_file="$(${root_dir}/getvar ${common_opts} run_dir)/bench-cache.txt"
bench() (
common_bench_cmd "$1" "$results_file"
"${root_dir}/bench-cmd" "$1"
{
printf 'cycles '
./gem5-stat -a "$common_arch"
./gem5-stat ${common_opts}
printf 'instructions '
./gem5-stat -a "$common_arch" sim_insts
./gem5-stat ${common_opts} sim_insts
# RESTORE_INVESTIGATION
#cycles_switch="$(./gem5-stat -a "$common_arch" system.switch_cpus.numCycles)"
#cycles_switch="$(./gem5-stat ${common_opts} system.switch_cpus.numCycles)"
#if [ -n "$cycles_switch" ]; then
# printf "cycles_switch ${cycles_switch}\n"
#fi
printf "\n"
} >> "$results_file"
)
bench-all() (
bench "${cmd} -l 1 -- ${cache_small} --cpu-type=HPI --restore-with-cpu=HPI"
bench "${cmd} -l 1 -- ${cache_large} --cpu-type=HPI --restore-with-cpu=HPI"
bench "${cmd} --gem5-readfile \"$1\" --gem5-restore 1 -- ${cache_small} --cpu-type=HPI --restore-with-cpu=HPI"
bench "${cmd} --gem5-readfile \"$1\" --gem5-restore 1 -- ${cache_large} --cpu-type=HPI --restore-with-cpu=HPI"
# RESTORE_INVESTIGATION
# These were mostly to investigate what happens on restore:
# https://stackoverflow.com/questions/49011096/how-to-switch-cpu-models-in-gem5-after-restoring-a-checkpoint-and-then-observe-t
#bench "${cmd} -l 1"
#bench "${cmd} -l 1 -- ${cache_small}"
#bench "${cmd} -l 1 -- ${cache_large}"
#bench "${cmd} -l 2 -- ${cache_small}"
#bench "${cmd} -l 3 -- ${cache_large}"
#bench "${cmd} -l 4 -- ${cache_small} --cpu-type=HPI"
#bench "${cmd} -l 5 -- ${cache_large} --cpu-type=HPI"
#bench "${cmd} --gem5-readfile '$1' --gem5-restore 1"
#bench "${cmd} --gem5-readfile '$1' --gem5-restore 1 -- ${cache_small}"
#bench "${cmd} --gem5-readfile '$1' --gem5-restore 1 -- ${cache_large}"
#bench "${cmd} --gem5-readfile '$1' --gem5-restore 2 -- ${cache_small}"
#bench "${cmd} --gem5-readfile '$1' --gem5-restore 3 -- ${cache_large}"
#bench "${cmd} --gem5-readfile '$1' --gem5-restore 4 -- ${cache_small} --cpu-type=HPI"
#bench "${cmd} --gem5-readfile '$1' --gem5-restore 5 -- ${cache_large} --cpu-type=HPI"
## Restore from At-- omicSimpleCPU to HPI.
#bench "${cmd} -l 2 -- ${cache_small} --cpu-type=HPI --restore-with-cpu=HPI"
#bench "${cmd} -l 3 -- ${cache_large} --cpu-type=HPI --restore-with-cpu=HPI"
#bench "${cmd} -l 2 -- ${cache_small} --restore-with-cpu=HPI"
#bench "${cmd} -l 3 -- ${cache_large} --restore-with-cpu=HPI"
#bench "${cmd} -l 2 -- ${cache_small} --cpu-type=HPI"
#bench "${cmd} -l 3 -- ${cache_large} --cpu-type=HPI"
#bench "${cmd} --gem5-readfile '$1' --gem5-restore 2 -- ${cache_small} --cpu-type=HPI --restore-with-cpu=HPI"
#bench "${cmd} --gem5-readfile '$1' --gem5-restore 3 -- ${cache_large} --cpu-type=HPI --restore-with-cpu=HPI"
#bench "${cmd} --gem5-readfile '$1' --gem5-restore 2 -- ${cache_small} --restore-with-cpu=HPI"
#bench "${cmd} --gem5-readfile '$1' --gem5-restore 3 -- ${cache_large} --restore-with-cpu=HPI"
#bench "${cmd} --gem5-readfile '$1' --gem5-restore 2 -- ${cache_small} --cpu-type=HPI"
#bench "${cmd} --gem5-readfile '$1' --gem5-restore 3 -- ${cache_large} --cpu-type=HPI"
## Restore HPI with different cache sizes and see if it is used.
#bench "${cmd} -l 4 -- ${cache_large} --cpu-type=HPI"
#bench "${cmd} -l 5 -- ${cache_small} --cpu-type=HPI"
#bench "${cmd} -l 2 -- ${cache_large} --cpu-type=HPI"
#bench "${cmd} -l 3 -- ${cache_small} --cpu-type=HPI"
#bench "${cmd} --gem5-readfile '$1' --gem5-restore 4 -- ${cache_large} --cpu-type=HPI"
#bench "${cmd} --gem5-readfile '$1' --gem5-restore 5 -- ${cache_small} --cpu-type=HPI"
#bench "${cmd} --gem5-readfile '$1' --gem5-restore 2 -- ${cache_large} --cpu-type=HPI"
#bench "${cmd} --gem5-readfile '$1' --gem5-restore 3 -- ${cache_small} --cpu-type=HPI"
)
if "$generate_checkpoints"; then
# Create the checkpoints after the kernel boot.
printf 'm5 exit' > "${common_gem5_readfile_file}"
cpt_cmd="-E '/gem5.sh'"
# RESTORE_INVESTIGATION
## 5
@ -84,8 +84,5 @@ fi
# Restore and run benchmarks.
rm -f "$results_file"
for n in 1000 10000 100000; do
printf "n ${n}\n" >> "$results_file"
printf "dhrystone ${n}" > "${common_gem5_readfile_file}"
bench-all
printf "\n" >> "$results_file"
bench-all "dhrystone ${n}"
done

26
gem5-bench-dhrystone Executable file
View File

@ -0,0 +1,26 @@
#!/usr/bin/env bash
# https://github.com/cirosantilli/linux-kernel-module-cheat/tree/58de3f7243016c052ad080f82dd757d61878219b#gem5-run-benchmark
set -eu
root_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null && pwd)"
outfile="${root_dir}/out/gem5-bench-dhrystone.txt"
arch=aarch64
cmd="./run -a '$arch' --gem5 --eval-busybox '/gem5.sh'"
# These cache sizes roughly match the ARM Cortex A75
# https://en.wikipedia.org/wiki/ARM_Cortex-A75
restore='-l 1 -- --cpu-type=HPI --restore-with-cpu=HPI --caches --l2cache --l1d_size=128kB --l1i_size=1024kB --l2_size=256kB'
# Generate a checkpoint after Linux boots, using the faster and less detailed CPU.
# The boot takes a while, be patient young Padawan.
eval "$cmd"
printf 'n cycles\n' > "$outfile"
for n in 1000 10000 100000; do
# Restore the most recent checkpoint taken with the more detailed and slower HPI CPU,
# and run the benchmark with different parameters. We skip the boot completely, saving time!
eval "${cmd} --gem5-readfile 'dhrystone ${n}' ${restore}" &>/dev/null
printf "${n} " >> "$outfile"
./gem5-stat -a "$arch" >> "$outfile"
done

View File

@ -1,13 +1,13 @@
#!/usr/bin/env bash
. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/common"
common_gem5=true
while getopts "${common_getopts_flags}" OPT; do
case "$OPT" in
?)
common_getopts_case "$OPT"
;;
esac
done
shift "$(($OPTIND - 1))"
common_setup
"${common_gem5_m5term}" localhost "$common_gem5_telnet_port"
#!/usr/bin/env python3
import subprocess
import sys
import common
parser = common.get_argparse(
default_args={'gem5':True},
argparse_args={'description':'Connect a terminal to a running gem5 instance'}
)
args = common.setup(parser)
sys.exit(common.run_cmd([str(common.gem5_m5term), 'localhost', str(common.gem5_telnet_port)]))

View File

@ -1,25 +1,14 @@
#!/usr/bin/env bash
. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/common"
common_gem5=true
while getopts "h${common_getopts_flags}" OPT; do
case "$OPT" in
h)
printf "\
usage: $0 [-a arch] [stat=system.cpu.numCycles]
Get the value for a gem5 stat from the stats.txt file.
" 1>&2
exit
;;
?)
common_getopts_case "$OPT"
;;
esac
done
shift "$(($OPTIND - 1))"
if [ $# -gt 0 ]; then
stat="$1"
else
stat=system.cpu[0-9]*.numCycles
fi
common_setup
awk "/^$stat /{ print \$2 }" "${common_m5out_dir}/stats.txt"
#!/usr/bin/env python3
import common
parser = common.get_argparse(
argparse_args={'description':'Get the value of a gem5 stat from the stats.txt file.'}
)
parser.add_argument(
'stat',
default=None,
help='Python regexp matching the full stat name of interest',
nargs='?',
)
args = common.setup(parser)
stats = common.get_stats(args.stat)
print('\n'.join(stats))

View File

@ -1,7 +0,0 @@
config BR2_PACKAGE_GEM5
bool "gem5"
help
gem5 system simulator. Only builds the m5 guest instrumentation
tool for now, not the simulator itself.
http://gem5.org

View File

@ -1,61 +0,0 @@
#!/usr/bin/env bash
set -eux
arch=x86_64
build_type=opt
cross_compile=
j=
outdir="$(pwd)"
while getopts a:c:j:o:t: OPT; do
case "$OPT" in
a)
arch="$OPTARG"
;;
c)
cross_compile="CROSS_COMPILE=$OPTARG"
;;
j)
j="$OPTARG"
;;
o)
outdir="$OPTARG"
;;
t)
build_type="$OPTARG"
;;
?)
exit 2
;;
esac
done
shift "$(($OPTIND - 1))"
if [ -z "$j" ]; then
j="$(nproc)"
fi
system_dir="${outdir}/system"
binaries_dir="${system_dir}/binaries"
disks_dir="${system_dir}/disks"
mkdir -p "$binaries_dir" "$disks_dir"
export PATH="/usr/lib/ccache:${PATH}"
if [ "$arch" = x86_64 ]; then
scons -j "$j" --ignore-style "${outdir}/build/X86/gem5.${build_type}"
f="${disks_dir}/linux-bigswap2.img"
dd if=/dev/zero of="$f" bs=1024 count=65536
mkswap "$f"
# 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.
touch "${binaries_dir}/x86_64-vmlinux-2.6.22.9"
elif [ "$arch" = arm ] || [ "$arch" = aarch64 ]; then
scons -j "$j" --ignore-style "${outdir}/build/ARM/gem5.${build_type}"
make -C ./system/arm/dt/
mkdir -p "${system_dir}/arm/dt"
# || true in case they are the same directory.
cp ./system/arm/dt/*.dtb "${system_dir}/arm/dt" || true
# TODO use the buildroot cross compiler here, and remove the dependencies from configure.
make -C ./system/arm/simple_bootloader/ $cross_compile
cp ./system/arm/simple_bootloader/boot_emm.arm "$binaries_dir"
# TODO cross_compile is ignored because the make does not use CC...
make -C ./system/arm/aarch64_bootloader/ $cross_compile
cp ./system/arm/aarch64_bootloader/boot_emm.arm64 "$binaries_dir"
fi
make -C util/term
cp util/term/m5term "${outdir}"

37
getvar
View File

@ -1,16 +1,21 @@
#!/usr/bin/env bash
. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/common"
while getopts "h${common_getopts_flags}" OPT; do
case "$OPT" in
h)
echo "https://github.com/cirosantilli/linux-kernel-module-cheat#getvar" 2>&1
exit
;;
?)
common_getopts_case "$OPT"
;;
esac
done
shift "$(($OPTIND - 1))"
common_setup
eval "echo \$common_${1}"
#!/usr/bin/env python3
import common
parser = common.get_argparse(argparse_args={
'description': '''Print the value of a common.py variable.
This is useful to:
* give dry commands on the README that don't change when we refactor directory structure
* create simple bash scripts that call use common.py variables
For example, to get the Buildroot output directory for an ARM build, use:
....
./%(prog)s -a arm buildroot_build_dir
....
'''
})
parser.add_argument('variable')
args = common.setup(parser)
print(getattr(common, args.variable))

View File

@ -1,28 +1,16 @@
# Misc.
CONFIG_BLK_DEV_INITRD=y
CONFIG_STRICT_DEVMEM=n
CONFIG_DEBUG_FS=y
CONFIG_DYNAMIC_DEBUG=y
CONFIG_MODULE_SRCVERSION_ALL=y
CONFIG_OVERLAY_FS=y
CONFIG_STRICT_DEVMEM=n
# GDB debugging.
CONFIG_DEBUG_FS=y
CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_KERNEL=y
CONFIG_GDB_SCRIPTS=y
# Non-static variables show up on /proc/kallsyms
# https://stackoverflow.com/questions/20196636/does-kallsyms-have-all-the-symbol-of-kernel-functions/44614878#44614878
CONFIG_KALLSYMS_ALL=y
# /proc/config.gz
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
# TODO make example.
# This seems to allow userspace to create arbitrary configuration trees,
# which kernel modules can then read and interpret.
CONFIG_CONFIGFS_FS=y
# KGDB
CONFIG_CONSOLE_POLL=y
CONFIG_KDB_CONTINUE_CATASTROPHIC=0
@ -38,6 +26,19 @@ CONFIG_MAGIC_SYSRQ=y
CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1
CONFIG_SERIAL_KGDB_NMI=n
# Non-static variables show up on /proc/kallsyms
# https://stackoverflow.com/questions/20196636/does-kallsyms-have-all-the-symbol-of-kernel-functions/44614878#44614878
CONFIG_KALLSYMS_ALL=y
# /proc/config.gz
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
# TODO make example.
# This seems to allow userspace to create arbitrary configuration trees,
# which kernel modules can then read and interpret.
CONFIG_CONFIGFS_FS=y
# Module.symvers in kernel tree and modules tree contains CRC of signatures.
# TODO: I think the CRC are stored in the built kernel and module, and checked
# at insmod, but bgrep did not find it in kernel image.

View File

@ -1,4 +1,4 @@
# This file contains only configs which are required to boot all configurations.
# This file contains only configs which are required to boot all configurations and get a shell.
## gem5 x86

View File

@ -1 +0,0 @@
name: KERNEL_MODULE

View File

@ -1,28 +0,0 @@
#!/usr/bin/env bash
. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/common"
while getopts "h${common_getopts_flags}" OPT; do
case "$OPT" in
h)
echo "https://github.com/cirosantilli/linux-kernel-module-cheat#getvar" 2>&1
exit
;;
?)
common_getopts_case "$OPT"
;;
esac
done
shift "$(($OPTIND - 1))"
common_linux_variant=bisect
common_setup
cd "$common_root_dir"
# We need a clean rebuild becuase rebuilds at different revisions:
# - may fail
# - may not actually rebuild all files, e.g. on header changes
rm -rf "$(./getvar -a "$common_arch" -L "$common_linux_variant" linux_variant_dir)"
./build -a "$common_arch" -L "$common_linux_variant"
status=0
./run -a "$common_arch" -E 'm5 exit' -L "$common_linux_variant" -g || status=$?
if [ "$status" -eq 125 ] || [ "$status" -gt 127 ]; then
status=1
fi
exit "$status"

7
packages/gem5/Config.in Normal file
View File

@ -0,0 +1,7 @@
config BR2_PACKAGE_GEM5
bool "gem5"
help
Only for the m5 guest instrumentation tool of the gem5 system simulator,
does not build the simulator itself.
http://gem5.org

View File

@ -5,7 +5,7 @@
################################################################################
GEM5_VERSION = 1.0
GEM5_SITE = $(BR2_EXTERNAL_GEM5_PATH)
GEM5_SITE = $(LKMC_GEM5_SRCDIR)
GEM5_SITE_METHOD = local
ifeq ($(ARCH),x86_64)
@ -15,16 +15,13 @@ ARCH_MAKE = $(ARCH)
endif
define GEM5_BUILD_CMDS
# TODO cannot pass "-c '$(TARGET_CROSS)'" here because the ARM build uses aarch64 for the bootloader...
cd '$(GEM5_LKMC_SRCDIR)' && '$(GEM5_SITE)/build' -a '$(ARCH)' -j '$(BR2_JLEVEL)' -o '$(GEM5_LKMC_OUTDIR)' -t '$(GEM5_LKMC_GEM5_BUILD_TYPE)'
# TODO cannot use TARGET_CONFIGURE_OPTS here because it overrides the CFLAGS on m5,
# which have an include. We should patch gem5 to add a += instead of = there.
cd '$(@D)/gem5/util/m5' && $(MAKE) -f 'Makefile.$(ARCH_MAKE)' CC='$(TARGET_CC)' LD='$(TARGET_LD)'
cd '$(@D)/util/m5' && $(MAKE) -f 'Makefile.$(ARCH_MAKE)' CC='$(TARGET_CC)' LD='$(TARGET_LD)'
endef
define GEM5_INSTALL_TARGET_CMDS
$(INSTALL) -D -m 0755 '$(@D)/gem5/util/m5/m5' '$(TARGET_DIR)/usr/bin'
$(INSTALL) -D -m 0755 '$(@D)/util/m5/m5' '$(TARGET_DIR)/usr/bin'
endef
$(eval $(generic-package))

View File

@ -1,5 +1,5 @@
config BR2_PACKAGE_KERNEL_MODULE
bool "kernel_module"
config BR2_PACKAGE_KERNEL_MODULES
bool "kernel_modules"
depends on BR2_LINUX_KERNEL
help
Linux Kernel Module Cheat.

View File

@ -1,4 +1,4 @@
obj-m += $(addsuffix .o, $(notdir $(basename $(filter-out %.mod.c, $(wildcard $(BR2_EXTERNAL_KERNEL_MODULE_PATH)/*.c)))))
obj-m += $(addsuffix .o, $(notdir $(basename $(filter-out %.mod.c, $(wildcard $(BR2_EXTERNAL_KERNEL_MODULES_PATH)/*.c)))))
ccflags-y := -DDEBUG -g -std=gnu99 -Werror -Wno-declaration-after-statement -Wframe-larger-than=1000000000
.PHONY: all clean

View File

@ -0,0 +1 @@
name: KERNEL_MODULES

View File

@ -1,24 +1,24 @@
################################################################################
#
# kernel_module
# kernel_modules
#
################################################################################
KERNEL_MODULE_VERSION = 1.0
KERNEL_MODULE_SITE = $(BR2_EXTERNAL_KERNEL_MODULE_PATH)
KERNEL_MODULE_SITE_METHOD = local
KERNEL_MODULES_VERSION = 1.0
KERNEL_MODULES_SITE = $(BR2_EXTERNAL_KERNEL_MODULES_PATH)
KERNEL_MODULES_SITE_METHOD = local
ifeq ($(BR2_PACKAGE_EIGEN),y)
KERNEL_MODULE_DEPENDENCIES += eigen
KERNEL_MODULES_DEPENDENCIES += eigen
endif
ifeq ($(BR2_PACKAGE_LIBDRM),y)
KERNEL_MODULE_DEPENDENCIES += libdrm
KERNEL_MODULES_DEPENDENCIES += libdrm
endif
ifeq ($(BR2_PACKAGE_OPENBLAS),y)
KERNEL_MODULE_DEPENDENCIES += openblas
KERNEL_MODULES_DEPENDENCIES += openblas
endif
define KERNEL_MODULE_BUILD_CMDS
define KERNEL_MODULES_BUILD_CMDS
$(MAKE) -C '$(@D)/user' $(TARGET_CONFIGURE_OPTS) \
BR2_PACKAGE_EIGEN="$(BR2_PACKAGE_EIGEN)" \
BR2_PACKAGE_LIBDRM="$(BR2_PACKAGE_LIBDRM)" \
@ -26,7 +26,7 @@ define KERNEL_MODULE_BUILD_CMDS
;
endef
define KERNEL_MODULE_INSTALL_TARGET_CMDS
define KERNEL_MODULES_INSTALL_TARGET_CMDS
# The modules are already installed by the kernel-module package type
# under /lib/modules/**, but let's also copy the modules to the root
# for insmod convenience.

View File

@ -3,7 +3,7 @@
# We can almost do everything from the Makefile itself by using default values for
#
# LINUX_DIR ?= "/lib/modules/$(uname -r)/build"
# BR2_EXTERNAL_KERNEL_MODULE_PATH="$(pwd)"
# BR2_EXTERNAL_KERNEL_MODULES_PATH="$(pwd)"
#
# The problem with that is that if you define those variables in your environment,
# the build breaks, so this is more portable.
@ -20,5 +20,5 @@ while getopts j: OPT; do
esac
done
shift $(($OPTIND - 1))
make -j "$j" KERNEL_MODULE_PATH="$(pwd)" LINUX_DIR="/lib/modules/$(uname -r)/build" "$@"
make -j "$j" KERNEL_MODULES_PATH="$(pwd)" LINUX_DIR="/lib/modules/$(uname -r)/build" "$@"
make -C user/ -j "$j" "$@"

Some files were not shown because too many files have changed in this diff Show More