mirror of
https://github.com/cirosantilli/linux-kernel-module-cheat.git
synced 2026-01-26 19:51:35 +01:00
porting "done"
This commit is contained in:
180
README.adoc
180
README.adoc
@@ -63,10 +63,17 @@ ____
|
|||||||
|
|
||||||
There are several different possible setups to use this repo.
|
There are several different possible setups to use this repo.
|
||||||
|
|
||||||
Each subsection of this describes one of those setups, and the trade-offs of each.
|
Each child section of this section describes one of those setups, and the trade-offs of each.
|
||||||
|
|
||||||
If you don't know which one to go for, start with <<qemu-buildroot-setup>>
|
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
|
||||||
|
* 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?
|
||||||
|
|
||||||
=== QEMU Buildroot setup
|
=== QEMU Buildroot setup
|
||||||
|
|
||||||
This is the best setup if you are on one of the supported systems: Ubuntu 16.04 or Ubuntu 18.04.
|
This is the best setup if you are on one of the supported systems: Ubuntu 16.04 or Ubuntu 18.04.
|
||||||
@@ -260,6 +267,12 @@ or if you are inside tmux, which I highly recommend, just run gem5 with:
|
|||||||
|
|
||||||
This will open up a split terminal by default so that you can see both the gem5 stdout and the terminal. See also: <<tmux-gem5>>
|
This will open up a split terminal by default so that you can see both the gem5 stdout and the terminal. See also: <<tmux-gem5>>
|
||||||
|
|
||||||
|
If you forgot to open the shell and gem5 exit, you can inspect the terminal output post-mortem at:
|
||||||
|
|
||||||
|
....
|
||||||
|
less "$(./getvar --gem5 termout_file)"
|
||||||
|
....
|
||||||
|
|
||||||
TODO: `arm` boot broken on kernel 4.18 with:
|
TODO: `arm` boot broken on kernel 4.18 with:
|
||||||
|
|
||||||
....
|
....
|
||||||
@@ -7074,7 +7087,7 @@ gem5 user mode:
|
|||||||
....
|
....
|
||||||
make \
|
make \
|
||||||
-C "$(./getvar --arch arm build_dir)/dhrystone-2" \
|
-C "$(./getvar --arch arm build_dir)/dhrystone-2" \
|
||||||
CC="$(./getvar --arch arm host_bin_dir)/arm-buildroot-linux-uclibcgnueabihf-gcc" \
|
CC="$(./runtc --arch arm --dry gcc)" \
|
||||||
CFLAGS=-static \
|
CFLAGS=-static \
|
||||||
;
|
;
|
||||||
time \
|
time \
|
||||||
@@ -7635,39 +7648,31 @@ On the other hand, the chip makers tend to upstream less, and the project become
|
|||||||
|
|
||||||
OK, this is why we used gem5 in the first place, performance measurements!
|
OK, this is why we used gem5 in the first place, performance measurements!
|
||||||
|
|
||||||
Let's benchmark https://en.wikipedia.org/wiki/Dhrystone[Dhrystone] which Buildroot provides.
|
Let's see how many cycles https://en.wikipedia.org/wiki/Dhrystone[Dhrystone], which Buildroot provides, takes for a few different input parameters.
|
||||||
|
|
||||||
A flexible setup is:
|
A flexible setup is demonstrated at:
|
||||||
|
|
||||||
....
|
....
|
||||||
arch=aarch64
|
./gem5-bench-dhrystone
|
||||||
cmd="./run -a '$arch' --gem5 --eval-busybox '/gem5.sh'"
|
cat out/gem5-bench-dhrystone.txt
|
||||||
# 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"
|
|
||||||
|
|
||||||
# Restore the most recent checkpoint taken with the more detailed and slower HPI CPU,
|
|
||||||
# and run the benchmark with parameter 1.000. We skip the boot completely, saving time!
|
|
||||||
eval "${cmd} --gem5-readfile 'dhrystone 1000' ${restore}"
|
|
||||||
./gem5-stat -a "$arch"
|
|
||||||
|
|
||||||
# Now run again with another parameter 10.000.
|
|
||||||
# This one should take more cycles!
|
|
||||||
eval "${cmd} --gem5-readfile 'dhrystone 10000' ${restore}"
|
|
||||||
./gem5-stat -a "$arch"
|
|
||||||
|
|
||||||
# Get an interactive shell at the end of the restore
|
|
||||||
# if you need to debug something more interactively.
|
|
||||||
eval "${cmd} --gem5-readfile 'sh' ${restore}"
|
|
||||||
....
|
....
|
||||||
|
|
||||||
|
Source: link:gem5-bench-dhrystone[]
|
||||||
|
|
||||||
|
Sample output:
|
||||||
|
|
||||||
|
....
|
||||||
|
n cycles
|
||||||
|
1000 12898577
|
||||||
|
10000 23441629
|
||||||
|
100000 128428617
|
||||||
|
....
|
||||||
|
|
||||||
|
so as expected, the Dhrystone run with a larger input parameter `100000` took more cycles than the ones with smaller input parameters.
|
||||||
|
|
||||||
The `gem5-stats` commands output the approximate number of CPU cycles it took Dhrystone to run.
|
The `gem5-stats` commands output the approximate number of CPU cycles it took Dhrystone to run.
|
||||||
|
|
||||||
For more serious tests, you will likely want to automate logging the commands ran and results to files, a good example is: link:gem5-bench-cache[].
|
Another interesting example can be found at: link:gem5-bench-cache[].
|
||||||
|
|
||||||
A more naive and simpler to understand approach would be a direct:
|
A more naive and simpler to understand approach would be a direct:
|
||||||
|
|
||||||
@@ -7801,47 +7806,47 @@ So we take a performance measurement approach instead:
|
|||||||
|
|
||||||
....
|
....
|
||||||
./gem5-bench-cache --arch aarch64
|
./gem5-bench-cache --arch aarch64
|
||||||
cat "$(./getvar --arch aarch64 run_dir)bench-cache.txt"
|
cat "$(./getvar --arch aarch64 run_dir)/bench-cache.txt"
|
||||||
....
|
....
|
||||||
|
|
||||||
which gives:
|
which gives:
|
||||||
|
|
||||||
....
|
....
|
||||||
n 1000
|
cmd ./run --gem5 --arch aarch64 --gem5-readfile "dhrystone 1000" --gem5-restore 1 -- --caches --l2cache --l1d_size=1024 --l1i_size=1024 --l2_size=1024 --l3_size=1024 --cpu-type=HPI --restore-with-cpu=HPI
|
||||||
cmd ./run --arch arm --gem5 --gem5-restore 1 -- --caches --l2cache --l1d_size=1024 --l1i_size=1024 --l2_size=1024 --l3_size=1024 --cpu-type=HPI --restore-with-cpu=HPI
|
time 23.82
|
||||||
time 24.71
|
|
||||||
exit_status 0
|
exit_status 0
|
||||||
cycles 52386455
|
cycles 93284622
|
||||||
instructions 4555081
|
instructions 4393457
|
||||||
cmd ./run --arch arm --gem5 --gem5-restore 1 -- --caches --l2cache --l1d_size=1024kB --l1i_size=1024kB --l2_size=1024kB --l3_size=1024kB --cpu-type=HPI --restore-with-cpu=HPI
|
|
||||||
time 17.44
|
|
||||||
exit_status 0
|
|
||||||
cycles 6683355
|
|
||||||
instructions 4466051
|
|
||||||
|
|
||||||
n 10000
|
cmd ./run --gem5 --arch aarch64 --gem5-readfile "dhrystone 1000" --gem5-restore 1 -- --caches --l2cache --l1d_size=1024kB --l1i_size=1024kB --l2_size=1024kB --l3_size=1024kB --cpu-type=HPI --restore-with-cpu=HPI
|
||||||
cmd ./run --arch arm --gem5 --gem5-restore 1 -- --caches --l2cache --l1d_size=1024 --l1i_size=1024 --l2_size=1024 --l3_size=1024 --cpu-type=HPI --restore-with-cpu=HPI
|
time 14.91
|
||||||
time 52.90
|
|
||||||
exit_status 0
|
exit_status 0
|
||||||
cycles 165704397
|
cycles 10128985
|
||||||
instructions 11531136
|
instructions 4211458
|
||||||
cmd ./run --arch arm --gem5 --gem5-restore 1 -- --caches --l2cache --l1d_size=1024kB --l1i_size=1024kB --l2_size=1024kB --l3_size=1024kB --cpu-type=HPI --restore-with-cpu=HPI
|
|
||||||
time 36.19
|
|
||||||
exit_status 0
|
|
||||||
cycles 16182925
|
|
||||||
instructions 11422585
|
|
||||||
|
|
||||||
n 100000
|
cmd ./run --gem5 --arch aarch64 --gem5-readfile "dhrystone 10000" --gem5-restore 1 -- --caches --l2cache --l1d_size=1024 --l1i_size=1024 --l2_size=1024 --l3_size=1024 --cpu-type=HPI --restore-with-cpu=HPI
|
||||||
cmd ./run --arch arm --gem5 --gem5-restore 1 -- --caches --l2cache --l1d_size=1024 --l1i_size=1024 --l2_size=1024 --l3_size=1024 --cpu-type=HPI --restore-with-cpu=HPI
|
time 51.87
|
||||||
time 325.09
|
|
||||||
exit_status 0
|
exit_status 0
|
||||||
cycles 1295703657
|
cycles 188803630
|
||||||
instructions 81189411
|
instructions 12401336
|
||||||
cmd ./run --arch arm --gem5 --gem5-restore 1 -- --caches --l2cache --l1d_size=1024kB --l1i_size=1024kB --l2_size=1024kB --l3_size=1024kB --cpu-type=HPI --restore-with-cpu=HPI
|
|
||||||
time 250.74
|
cmd ./run --gem5 --arch aarch64 --gem5-readfile "dhrystone 10000" --gem5-restore 1 -- --caches --l2cache --l1d_size=1024kB --l1i_size=1024kB --l2_size=1024kB --l3_size=1024kB --cpu-type=HPI --restore-with-cpu=HPI
|
||||||
|
time 35.35
|
||||||
exit_status 0
|
exit_status 0
|
||||||
cycles 110585681
|
cycles 20715757
|
||||||
instructions 80899588
|
instructions 12192527
|
||||||
|
|
||||||
|
cmd ./run --gem5 --arch aarch64 --gem5-readfile "dhrystone 100000" --gem5-restore 1 -- --caches --l2cache --l1d_size=1024 --l1i_size=1024 --l2_size=1024 --l3_size=1024 --cpu-type=HPI --restore-with-cpu=HPI
|
||||||
|
time 339.07
|
||||||
|
exit_status 0
|
||||||
|
cycles 1176559936
|
||||||
|
instructions 94222791
|
||||||
|
|
||||||
|
cmd ./run --gem5 --arch aarch64 --gem5-readfile "dhrystone 100000" --gem5-restore 1 -- --caches --l2cache --l1d_size=1024kB --l1i_size=1024kB --l2_size=1024kB --l3_size=1024kB --cpu-type=HPI --restore-with-cpu=HPI
|
||||||
|
time 240.37
|
||||||
|
exit_status 0
|
||||||
|
cycles 125666679
|
||||||
|
instructions 91738770
|
||||||
....
|
....
|
||||||
|
|
||||||
We make the following conclusions:
|
We make the following conclusions:
|
||||||
@@ -7934,8 +7939,12 @@ https://stackoverflow.com/questions/6147242/heap-vs-binary-search-tree-bst/29548
|
|||||||
Usage:
|
Usage:
|
||||||
|
|
||||||
....
|
....
|
||||||
printf '/bst_vs_heap.out' > data/readfile
|
./run \
|
||||||
./run --arch aarch64 --gem5 --eval-busybox '/gem5.sh'
|
--arch aarch64 \
|
||||||
|
--eval-busybox '/gem5.sh' \
|
||||||
|
--gem5 \
|
||||||
|
--gem5-readfile '/bst_vs_heap.out' \
|
||||||
|
;
|
||||||
./bst-vs-heap --arch aarch64 --gem5 > bst_vs_heap.dat
|
./bst-vs-heap --arch aarch64 --gem5 > bst_vs_heap.dat
|
||||||
....
|
....
|
||||||
|
|
||||||
@@ -8387,18 +8396,32 @@ The problem is that boot takes forever, and after the checkpoint, the memory and
|
|||||||
* hack up an existing rc script, since the disk is fixed
|
* hack up an existing rc script, since the disk is fixed
|
||||||
* inject new kernel boot command line options, since those have already been put into memory by the bootloader
|
* inject new kernel boot command line options, since those have already been put into memory by the bootloader
|
||||||
|
|
||||||
There is however one loophole: <<m5-readfile>>, which reads whatever is present on the host, so we can do it like:
|
There is however a few loopholes, <<m5-readfile>> being the simplest, as it reads whatever is present on the host.
|
||||||
|
|
||||||
|
So we can do it like:
|
||||||
|
|
||||||
....
|
....
|
||||||
printf 'echo "setup run";m5 exit' > data/readfile
|
# Boot, checkpoint and exit.
|
||||||
./run --arch aarch64 --gem5 --eval 'm5 checkpoint;m5 readfile > a.sh;sh a.sh'
|
printf 'echo "setup run";m5 exit' > "$(./getvar gem5_readfile)"
|
||||||
printf 'echo "first benchmark";m5 exit' > data/readfile
|
./run --gem5 --eval 'm5 checkpoint;m5 readfile > a.sh;sh a.sh'
|
||||||
./run --arch aarch64 --gem5 --gem5-restore 1
|
|
||||||
printf 'echo "second benchmark";m5 exit' > data/readfile
|
# Restore and run the first benchmark.
|
||||||
./run --arch aarch64 --gem5 --gem5-restore 1
|
printf 'echo "first benchmark";m5 exit' > "$(./getvar gem5_readfile)"
|
||||||
|
./run --gem5 --gem5-restore 1
|
||||||
|
|
||||||
|
# Restore and run the second benchmark.
|
||||||
|
printf 'echo "second benchmark";m5 exit' > "$(./getvar gem5_readfile)"
|
||||||
|
./run --gem5 --gem5-restore 1
|
||||||
|
|
||||||
|
# If something weird happened, create an interactive shell to examine the system.
|
||||||
|
printf 'sh' > "$(./getvar gem5_readfile)"
|
||||||
|
./run --gem5 --gem5-restore 1
|
||||||
....
|
....
|
||||||
|
|
||||||
Since this is such a common setup, we provide helper for it at: link:rootfs_overlay/gem5.sh[rootfs_overlay/gem5.sh]. This script is analogous to gem5's in-tree link:https://github.com/gem5/gem5/blob/2b4b94d0556c2d03172ebff63f7fc502c3c26ff8/configs/boot/hack_back_ckpt.rcS[hack_back_ckpt.rcS], but with less noise.
|
Since this is such a common setup, we provide some helpers for it as described at <<gem5-run-benchmark>>:
|
||||||
|
|
||||||
|
* link:rootfs_overlay/gem5.sh[rootfs_overlay/gem5.sh]. This script is analogous to gem5's in-tree link:https://github.com/gem5/gem5/blob/2b4b94d0556c2d03172ebff63f7fc502c3c26ff8/configs/boot/hack_back_ckpt.rcS[hack_back_ckpt.rcS], but with less noise.
|
||||||
|
* `./run --gem5-readfile` is a convenient way to set the `m5 readfile`
|
||||||
|
|
||||||
Other loophole possibilities include:
|
Other loophole possibilities include:
|
||||||
|
|
||||||
@@ -8415,6 +8438,8 @@ send "ls /\r"
|
|||||||
send "m5 exit\r"
|
send "m5 exit\r"
|
||||||
expect eof
|
expect eof
|
||||||
....
|
....
|
||||||
|
+
|
||||||
|
This is ugly however as it is not deterministic.
|
||||||
|
|
||||||
https://www.mail-archive.com/gem5-users@gem5.org/msg15233.html
|
https://www.mail-archive.com/gem5-users@gem5.org/msg15233.html
|
||||||
|
|
||||||
@@ -8568,12 +8593,14 @@ m5 writefile myfileguest mydirhost/myfilehost
|
|||||||
|
|
||||||
===== m5 readfile
|
===== m5 readfile
|
||||||
|
|
||||||
|
Read a host file pointed to by the `fs.py --script` option to stdout.
|
||||||
|
|
||||||
https://stackoverflow.com/questions/49516399/how-to-use-m5-readfile-and-m5-execfile-in-gem5/49538051#49538051
|
https://stackoverflow.com/questions/49516399/how-to-use-m5-readfile-and-m5-execfile-in-gem5/49538051#49538051
|
||||||
|
|
||||||
Host:
|
Host:
|
||||||
|
|
||||||
....
|
....
|
||||||
date > data/readfile
|
date > "$(./getvar gem5_readfile)"
|
||||||
....
|
....
|
||||||
|
|
||||||
Guest:
|
Guest:
|
||||||
@@ -8582,13 +8609,18 @@ Guest:
|
|||||||
m5 readfile
|
m5 readfile
|
||||||
....
|
....
|
||||||
|
|
||||||
|
Outcome: date shows on guest.
|
||||||
|
|
||||||
===== m5 execfile
|
===== m5 execfile
|
||||||
|
|
||||||
|
Trivial combination of `m5 readfile` + execute the script.
|
||||||
|
|
||||||
Host:
|
Host:
|
||||||
|
|
||||||
....
|
....
|
||||||
printf '#!/bin/sh
|
printf '#!/bin/sh
|
||||||
echo asdf' > data/readfile
|
echo asdf
|
||||||
|
' > "$(./getvar gem5_readfile)"
|
||||||
....
|
....
|
||||||
|
|
||||||
Guest:
|
Guest:
|
||||||
@@ -8599,6 +8631,12 @@ chmod +x /tmp/execfile
|
|||||||
m5 execfile
|
m5 execfile
|
||||||
....
|
....
|
||||||
|
|
||||||
|
Outcome:
|
||||||
|
|
||||||
|
....
|
||||||
|
adsf
|
||||||
|
....
|
||||||
|
|
||||||
==== m5ops instructions
|
==== m5ops instructions
|
||||||
|
|
||||||
The executable `/m5ops.out` illustrates how to hard code with inline assembly the m5ops that you are most likely to hack into the benchmark you are analysing:
|
The executable `/m5ops.out` illustrates how to hard code with inline assembly the m5ops that you are most likely to hack into the benchmark you are analysing:
|
||||||
@@ -9318,6 +9356,7 @@ We tried to automate it on Travis with link:.travis.yml[] but it hits the curren
|
|||||||
==== Benchmark Linux kernel boot
|
==== Benchmark Linux kernel boot
|
||||||
|
|
||||||
....
|
....
|
||||||
|
./build-all
|
||||||
./bench-boot
|
./bench-boot
|
||||||
cat "$(./getvar bench_boot)"
|
cat "$(./getvar bench_boot)"
|
||||||
....
|
....
|
||||||
@@ -9679,7 +9718,6 @@ The action seems to be happening at: `hw/arm/virt.c`.
|
|||||||
=== Directory structure
|
=== Directory structure
|
||||||
|
|
||||||
* `data`: gitignored user created data. Deleting this might lead to loss of data. Of course, if something there becomes is important enough to you, git track it.
|
* `data`: gitignored user created data. Deleting this might lead to loss of data. Of course, if something there becomes is important enough to you, git track it.
|
||||||
** `data/readfile`: see <<m5-readfile>>
|
|
||||||
** `data/9p`: see <<9p>>
|
** `data/9p`: see <<9p>>
|
||||||
** `data/gem5/<variant>`: see: <<gem5-build-variants>>
|
** `data/gem5/<variant>`: see: <<gem5-build-variants>>
|
||||||
* link:packages/kernel_modules[]: Buildroot package that contains our kernel modules and userland C tests
|
* link:packages/kernel_modules[]: Buildroot package that contains our kernel modules and userland C tests
|
||||||
|
|||||||
24
bench-all
24
bench-all
@@ -1,6 +1,6 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/common"
|
set -eux
|
||||||
set -x
|
root_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null && pwd)"
|
||||||
bench_build=false
|
bench_build=false
|
||||||
bench_buildroot_baseline=false
|
bench_buildroot_baseline=false
|
||||||
bench_gem5_build=false
|
bench_gem5_build=false
|
||||||
@@ -40,9 +40,10 @@ while getopts Aa:Bbglu OPT; do
|
|||||||
done
|
done
|
||||||
shift "$(($OPTIND - 1))"
|
shift "$(($OPTIND - 1))"
|
||||||
comment="${1:-}"
|
comment="${1:-}"
|
||||||
|
getvar="${root_dir}/getvar"
|
||||||
|
|
||||||
# Create output directory.
|
# 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"
|
mkdir -p "$benchmark_repo"
|
||||||
last_dir="$(ls "$benchmark_repo" | grep -E '^[0-9]' | tail -n 1)"
|
last_dir="$(ls "$benchmark_repo" | grep -E '^[0-9]' | tail -n 1)"
|
||||||
if [ -n "$last_dir" ]; then
|
if [ -n "$last_dir" ]; then
|
||||||
@@ -57,8 +58,9 @@ mkdir "$new_dir"
|
|||||||
|
|
||||||
if "$bench_build"; then
|
if "$bench_build"; then
|
||||||
common_arch="$default_arch"
|
common_arch="$default_arch"
|
||||||
|
common_out_arch_dir="$("$getvar" --arch "$common_arch" out_arch_dir)"
|
||||||
|
common_out_arch_dir="$("$getvar" --arch "$common_arch" build_dir)"
|
||||||
common_suffix=bench
|
common_suffix=bench
|
||||||
common_setup
|
|
||||||
rm -rf "$common_out_arch_dir"
|
rm -rf "$common_out_arch_dir"
|
||||||
./build -a "$common_arch" -B 'BR2_CCACHE=n' -s "$common_suffix"
|
./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"
|
cp "${common_build_dir}/build-time.log" "${new_dir}/build-time-${common_arch}.log"
|
||||||
@@ -66,7 +68,7 @@ if "$bench_build"; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if "$bench_buildroot_baseline"; then
|
if "$bench_buildroot_baseline"; then
|
||||||
cd "${common_root_dir}/buildroot"
|
cd "${root_dir}/buildroot"
|
||||||
git clean -xdf
|
git clean -xdf
|
||||||
make "qemu_${default_arch}_defconfig"
|
make "qemu_${default_arch}_defconfig"
|
||||||
printf '
|
printf '
|
||||||
@@ -85,7 +87,9 @@ fi
|
|||||||
if "$bench_gem5_build"; then
|
if "$bench_gem5_build"; then
|
||||||
arches='x86_64 arm'
|
arches='x86_64 arm'
|
||||||
for common_arch in $arches; do
|
for common_arch in $arches; do
|
||||||
common_setup
|
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}"
|
cd "${common_gem5_src_dir}"
|
||||||
git clean -xdf
|
git clean -xdf
|
||||||
results_file="${common_gem5_out_dir}/bench-build.txt"
|
results_file="${common_gem5_out_dir}/bench-build.txt"
|
||||||
@@ -94,19 +98,19 @@ if "$bench_gem5_build"; then
|
|||||||
# TODO understand better: --foreground required otherwise we cannot
|
# TODO understand better: --foreground required otherwise we cannot
|
||||||
# kill the build with Ctrl+C if something goes wrong, can be minimized to:
|
# kill the build with Ctrl+C if something goes wrong, can be minimized to:
|
||||||
# bash -c "eval 'timeout 5 sleep 3'"
|
# bash -c "eval 'timeout 5 sleep 3'"
|
||||||
common_bench_cmd "timeout --foreground 900 ../build -a '$common_arch' -o '${gem5_outdir}'" "$results_file"
|
"${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"
|
cp "$results_file" "${new_dir}/gem5-bench-build-${common_arch}.txt"
|
||||||
cd "${common_root_dir}/gem5/gem5"
|
cd "${root_dir}/gem5/gem5"
|
||||||
git clean -xdf
|
git clean -xdf
|
||||||
rm -fr "${gem5_outdir}"
|
rm -fr "${gem5_outdir}"
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if "$bench_linux_boot"; then
|
if "$bench_linux_boot"; then
|
||||||
cd "${common_root_dir}"
|
cd "${root_dir}"
|
||||||
./build-all
|
./build-all
|
||||||
./bench-boot
|
./bench-boot
|
||||||
cp "$common_bench_boot" "$new_dir"
|
cp "$(${root_dir}/getvar bench_boot)" "$new_dir"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if "$update_repo"; then
|
if "$update_repo"; then
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#!/usr/bin/env bash
|
#!/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
|
test_size=1
|
||||||
OPTIND=1
|
OPTIND=1
|
||||||
while getopts t: OPT; do
|
while getopts t: OPT; do
|
||||||
@@ -17,10 +18,11 @@ while getopts t: OPT; do
|
|||||||
done
|
done
|
||||||
shift "$(($OPTIND - 1))"
|
shift "$(($OPTIND - 1))"
|
||||||
extra_args="$*"
|
extra_args="$*"
|
||||||
|
common_bench_boot="$(${root_dir}/getvar bench_boot)"
|
||||||
|
|
||||||
caches='--caches --l2cache --l1d_size=1024kB --l1i_size=1024kB --l2_size=1024kB --l3_size=1024kB'
|
caches='--caches --l2cache --l1d_size=1024kB --l1i_size=1024kB --l2_size=1024kB --l3_size=1024kB'
|
||||||
bench() (
|
bench() (
|
||||||
common_bench_cmd "./run -a ${1} ${extra_args}" "$common_bench_boot"
|
"${root_dir}/bench-cmd" "./run -a ${1} ${extra_args}" "$common_bench_boot"
|
||||||
echo >> "$common_bench_boot"
|
echo >> "$common_bench_boot"
|
||||||
)
|
)
|
||||||
gem5_insts() (
|
gem5_insts() (
|
||||||
|
|||||||
17
bench-cmd
Executable file
17
bench-cmd
Executable 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"
|
||||||
@@ -2,5 +2,5 @@
|
|||||||
set -eu
|
set -eu
|
||||||
git submodule update
|
git submodule update
|
||||||
cd ..
|
cd ..
|
||||||
./build -aa -Q bisect -q
|
./build-qemu --arch arm -Q bisect
|
||||||
./run -aa -E '/poweroff.out' -Q bisect
|
./run --arch arm -E '/poweroff.out' -Q bisect
|
||||||
|
|||||||
@@ -14,5 +14,9 @@ while getopts A:G OPT; do
|
|||||||
done
|
done
|
||||||
shift "$(($OPTIND - 1))"
|
shift "$(($OPTIND - 1))"
|
||||||
for arch in $archs; do
|
for arch in $archs; do
|
||||||
./build -a "$arch" -klq $gem5 "$@"
|
./build -a "$arch" -k -l "$@"
|
||||||
|
./build-qemu -a "$arch"
|
||||||
|
if "$gem5"; then
|
||||||
|
./build-gem5 -a "$arch"
|
||||||
|
fi
|
||||||
done
|
done
|
||||||
|
|||||||
19
common.py
19
common.py
@@ -45,25 +45,6 @@ if os.path.exists(config_file):
|
|||||||
config = imp.load_source('config', config_file)
|
config = imp.load_source('config', config_file)
|
||||||
configs = {x:getattr(config, x) for x in dir(config) if not x.startswith('__')}
|
configs = {x:getattr(config, x) for x in dir(config) if not x.startswith('__')}
|
||||||
|
|
||||||
# TODO
|
|
||||||
## 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>
|
|
||||||
#bench_cmd() (
|
|
||||||
# cmd = "$1"
|
|
||||||
# results_file = "${2:-/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"
|
|
||||||
#)
|
|
||||||
|
|
||||||
def base64_encode(string):
|
def base64_encode(string):
|
||||||
return base64.b64encode(string.encode()).decode()
|
return base64.b64encode(string.encode()).decode()
|
||||||
|
|
||||||
|
|||||||
3
eeval
3
eeval
@@ -1,5 +1,6 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# echo and eval
|
# echo a command and eval it.
|
||||||
|
# Can also print the command to a file.
|
||||||
set -e
|
set -e
|
||||||
a=
|
a=
|
||||||
while getopts a OPT; do
|
while getopts a OPT; do
|
||||||
|
|||||||
@@ -1,66 +1,67 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/common"
|
set -eu
|
||||||
common_gem5=true
|
root_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null && pwd)"
|
||||||
generate_checkpoints=true
|
generate_checkpoints=true
|
||||||
while getopts "C${common_getopts_flags}" OPT; do
|
while getopts "C" OPT; do
|
||||||
case "$OPT" in
|
case "$OPT" in
|
||||||
C)
|
C)
|
||||||
generate_checkpoints=false
|
generate_checkpoints=false
|
||||||
;;
|
;;
|
||||||
?)
|
?)
|
||||||
common_getopts_case "$OPT"
|
exit 2;
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
shift "$(($OPTIND - 1))"
|
shift "$(($OPTIND - 1))"
|
||||||
common_setup
|
common_opts="--gem5 $@"
|
||||||
|
|
||||||
# Vars
|
# 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_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'
|
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() (
|
bench() (
|
||||||
common_bench_cmd "$1" "$results_file"
|
"${root_dir}/bench-cmd" "$1"
|
||||||
{
|
{
|
||||||
printf 'cycles '
|
printf 'cycles '
|
||||||
./gem5-stat -a "$common_arch"
|
./gem5-stat ${common_opts}
|
||||||
printf 'instructions '
|
printf 'instructions '
|
||||||
./gem5-stat -a "$common_arch" sim_insts
|
./gem5-stat ${common_opts} sim_insts
|
||||||
# RESTORE_INVESTIGATION
|
# 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
|
#if [ -n "$cycles_switch" ]; then
|
||||||
# printf "cycles_switch ${cycles_switch}\n"
|
# printf "cycles_switch ${cycles_switch}\n"
|
||||||
#fi
|
#fi
|
||||||
|
printf "\n"
|
||||||
} >> "$results_file"
|
} >> "$results_file"
|
||||||
)
|
)
|
||||||
|
|
||||||
bench-all() (
|
bench-all() (
|
||||||
bench "${cmd} -l 1 -- ${cache_small} --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} -l 1 -- ${cache_large} --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
|
# RESTORE_INVESTIGATION
|
||||||
# These were mostly to investigate what happens on restore:
|
# 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
|
# 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} --gem5-readfile '$1' --gem5-restore 1"
|
||||||
#bench "${cmd} -l 1 -- ${cache_small}"
|
#bench "${cmd} --gem5-readfile '$1' --gem5-restore 1 -- ${cache_small}"
|
||||||
#bench "${cmd} -l 1 -- ${cache_large}"
|
#bench "${cmd} --gem5-readfile '$1' --gem5-restore 1 -- ${cache_large}"
|
||||||
#bench "${cmd} -l 2 -- ${cache_small}"
|
#bench "${cmd} --gem5-readfile '$1' --gem5-restore 2 -- ${cache_small}"
|
||||||
#bench "${cmd} -l 3 -- ${cache_large}"
|
#bench "${cmd} --gem5-readfile '$1' --gem5-restore 3 -- ${cache_large}"
|
||||||
#bench "${cmd} -l 4 -- ${cache_small} --cpu-type=HPI"
|
#bench "${cmd} --gem5-readfile '$1' --gem5-restore 4 -- ${cache_small} --cpu-type=HPI"
|
||||||
#bench "${cmd} -l 5 -- ${cache_large} --cpu-type=HPI"
|
#bench "${cmd} --gem5-readfile '$1' --gem5-restore 5 -- ${cache_large} --cpu-type=HPI"
|
||||||
## Restore from At-- omicSimpleCPU to HPI.
|
## Restore from At-- omicSimpleCPU to HPI.
|
||||||
#bench "${cmd} -l 2 -- ${cache_small} --cpu-type=HPI --restore-with-cpu=HPI"
|
#bench "${cmd} --gem5-readfile '$1' --gem5-restore 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} --gem5-readfile '$1' --gem5-restore 3 -- ${cache_large} --cpu-type=HPI --restore-with-cpu=HPI"
|
||||||
#bench "${cmd} -l 2 -- ${cache_small} --restore-with-cpu=HPI"
|
#bench "${cmd} --gem5-readfile '$1' --gem5-restore 2 -- ${cache_small} --restore-with-cpu=HPI"
|
||||||
#bench "${cmd} -l 3 -- ${cache_large} --restore-with-cpu=HPI"
|
#bench "${cmd} --gem5-readfile '$1' --gem5-restore 3 -- ${cache_large} --restore-with-cpu=HPI"
|
||||||
#bench "${cmd} -l 2 -- ${cache_small} --cpu-type=HPI"
|
#bench "${cmd} --gem5-readfile '$1' --gem5-restore 2 -- ${cache_small} --cpu-type=HPI"
|
||||||
#bench "${cmd} -l 3 -- ${cache_large} --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.
|
## Restore HPI with different cache sizes and see if it is used.
|
||||||
#bench "${cmd} -l 4 -- ${cache_large} --cpu-type=HPI"
|
#bench "${cmd} --gem5-readfile '$1' --gem5-restore 4 -- ${cache_large} --cpu-type=HPI"
|
||||||
#bench "${cmd} -l 5 -- ${cache_small} --cpu-type=HPI"
|
#bench "${cmd} --gem5-readfile '$1' --gem5-restore 5 -- ${cache_small} --cpu-type=HPI"
|
||||||
#bench "${cmd} -l 2 -- ${cache_large} --cpu-type=HPI"
|
#bench "${cmd} --gem5-readfile '$1' --gem5-restore 2 -- ${cache_large} --cpu-type=HPI"
|
||||||
#bench "${cmd} -l 3 -- ${cache_small} --cpu-type=HPI"
|
#bench "${cmd} --gem5-readfile '$1' --gem5-restore 3 -- ${cache_small} --cpu-type=HPI"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -83,8 +84,5 @@ fi
|
|||||||
# Restore and run benchmarks.
|
# Restore and run benchmarks.
|
||||||
rm -f "$results_file"
|
rm -f "$results_file"
|
||||||
for n in 1000 10000 100000; do
|
for n in 1000 10000 100000; do
|
||||||
printf "n ${n}\n" >> "$results_file"
|
bench-all "dhrystone ${n}"
|
||||||
printf "dhrystone ${n}" > "${common_gem5_readfile_file}"
|
|
||||||
bench-all
|
|
||||||
printf "\n" >> "$results_file"
|
|
||||||
done
|
done
|
||||||
|
|||||||
26
gem5-bench-dhrystone
Executable file
26
gem5-bench-dhrystone
Executable 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
|
||||||
20
runtc
20
runtc
@@ -22,6 +22,11 @@ ls "$(./getvar -a arm host_bin_dir)"
|
|||||||
....
|
....
|
||||||
'''
|
'''
|
||||||
})
|
})
|
||||||
|
parser.add_argument(
|
||||||
|
'--dry',
|
||||||
|
help='Just output the tool path to stdout but actually run it',
|
||||||
|
action='store_true',
|
||||||
|
)
|
||||||
parser.add_argument('tool', help='Which tool to run.')
|
parser.add_argument('tool', help='Which tool to run.')
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'extra_args',
|
'extra_args',
|
||||||
@@ -31,9 +36,12 @@ parser.add_argument(
|
|||||||
nargs='*'
|
nargs='*'
|
||||||
)
|
)
|
||||||
args = common.setup(parser)
|
args = common.setup(parser)
|
||||||
sys.exit(common.run_cmd(
|
if args.dry:
|
||||||
[common.get_toolchain_tool(args.tool)] + args.extra_args,
|
print(common.get_toolchain_tool(args.tool))
|
||||||
cmd_file=os.path.join(common.run_dir, 'runtc.sh'),
|
else:
|
||||||
cwd=common.linux_variant_dir,
|
sys.exit(common.run_cmd(
|
||||||
show_cmd=False,
|
[common.get_toolchain_tool(args.tool)] + args.extra_args,
|
||||||
))
|
cmd_file=os.path.join(common.run_dir, 'runtc.sh'),
|
||||||
|
cwd=common.linux_variant_dir,
|
||||||
|
show_cmd=False,
|
||||||
|
))
|
||||||
|
|||||||
Reference in New Issue
Block a user