mirror of
https://github.com/cirosantilli/linux-kernel-module-cheat.git
synced 2026-01-29 04:54:27 +01:00
rungdb, gem5-shell and ./run -u ported
This commit is contained in:
29
README.adoc
29
README.adoc
@@ -1112,7 +1112,7 @@ Bibliography: https://stackoverflow.com/questions/5947286/how-to-load-linux-kern
|
|||||||
|
|
||||||
When doing long simulations sweeping across multiple system parameters, it becomes fundamental to do multiple simulations in parallel.
|
When doing long simulations sweeping across multiple system parameters, it becomes fundamental to do multiple simulations in parallel.
|
||||||
|
|
||||||
This is specially true for gem5, which runs much slower than QEMU, and cannot use multiple host cores to speed up the simulation: https://github.com/cirosantilli-work/gem5-issues/issues/15
|
This is specially true for gem5, which runs much slower than QEMU, and cannot use multiple host cores to speed up the simulation: link:https://github.com/cirosantilli-work/gem5-issues/issues/15[], so the only way to parallelize is to run multiple instances in parallel.
|
||||||
|
|
||||||
This also has a good synergy with <<build-variants>>.
|
This also has a good synergy with <<build-variants>>.
|
||||||
|
|
||||||
@@ -1128,9 +1128,16 @@ Another shell:
|
|||||||
./run -n 1
|
./run -n 1
|
||||||
....
|
....
|
||||||
|
|
||||||
|
and now you have two QEMU instances running in parallel.
|
||||||
|
|
||||||
The default run id is `0`.
|
The default run id is `0`.
|
||||||
|
|
||||||
This method also allows us to keep run outputs in separate directories for later inspection, e.g.:
|
Our scripts solve two difficulties with simultaneous runs:
|
||||||
|
|
||||||
|
* port conflicts, e.g. GDB and link:gem5-shell[]
|
||||||
|
* output directory conflicts, e.g. traces and gem5 stats overwriting one another
|
||||||
|
|
||||||
|
Each run gets a separate output directory. For example:
|
||||||
|
|
||||||
....
|
....
|
||||||
./run -a A -g -n 0 &>/dev/null &
|
./run -a A -g -n 0 &>/dev/null &
|
||||||
@@ -1140,8 +1147,8 @@ This method also allows us to keep run outputs in separate directories for later
|
|||||||
produces two separate `m5out` directories:
|
produces two separate `m5out` directories:
|
||||||
|
|
||||||
....
|
....
|
||||||
ls "$(./getvar -a A -g -n 0 m5out_dir)"
|
echo "$(./getvar -a A -g -n 0 m5out_dir)"
|
||||||
ls "$(./getvar -a A -g -n 1 m5out_dir)"
|
echo "$(./getvar -a A -g -n 1 m5out_dir)"
|
||||||
....
|
....
|
||||||
|
|
||||||
and the gem5 host executable stdout and stderr can be found at:
|
and the gem5 host executable stdout and stderr can be found at:
|
||||||
@@ -1153,21 +1160,13 @@ less "$(./getvar -a A -g -n 1 termout_file)"
|
|||||||
|
|
||||||
Each line is prepended with the timestamp in seconds since the start of the program when it appeared.
|
Each line is prepended with the timestamp in seconds since the start of the program when it appeared.
|
||||||
|
|
||||||
You can also add a prefix to the build ID before a period:
|
To have more semantic output directories names for later inspection, you can use a non numeric string for the run ID, and indicate the port offset explicitly:
|
||||||
|
|
||||||
....
|
....
|
||||||
./run -a A -g -n some-experiment.1
|
./run -a A -g -n some-experiment --port-offset 1
|
||||||
....
|
....
|
||||||
|
|
||||||
and makes it easier to remember afterwards which directory contains what.
|
`--port-offset` defaults to the run ID when that is a number.
|
||||||
|
|
||||||
However this still takes up the same ports as:
|
|
||||||
|
|
||||||
....
|
|
||||||
./run -a A -g -n 1
|
|
||||||
....
|
|
||||||
|
|
||||||
so you cannot run both at the same time.
|
|
||||||
|
|
||||||
Like <<cpu-architecture>>, you will need to pass the `-n` option to anything that needs to know runtime information, e.g. <<gdb>>:
|
Like <<cpu-architecture>>, you will need to pass the `-n` option to anything that needs to know runtime information, e.g. <<gdb>>:
|
||||||
|
|
||||||
|
|||||||
16
common.py
16
common.py
@@ -32,19 +32,23 @@ this = sys.modules[__name__]
|
|||||||
def base64_encode(string):
|
def base64_encode(string):
|
||||||
return base64.b64encode(string.encode()).decode()
|
return base64.b64encode(string.encode()).decode()
|
||||||
|
|
||||||
def get_argparse(**kwargs):
|
def get_argparse(default_args=None, argparse_args=None):
|
||||||
"""
|
"""
|
||||||
Return an argument parser with common arguments set.
|
Return an argument parser with common arguments set.
|
||||||
"""
|
"""
|
||||||
global this
|
global this
|
||||||
|
if default_args is None:
|
||||||
|
default_args = {}
|
||||||
|
if argparse_args is None:
|
||||||
|
argparse_args = {}
|
||||||
arch_choices = []
|
arch_choices = []
|
||||||
for key in this.arch_map:
|
for key in this.arch_map:
|
||||||
arch_choices.append(key)
|
arch_choices.append(key)
|
||||||
arch_choices.append(this.arch_map[key])
|
arch_choices.append(this.arch_map[key])
|
||||||
default_build_id='default'
|
default_build_id = 'default'
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
formatter_class=argparse.RawTextHelpFormatter,
|
formatter_class=argparse.RawTextHelpFormatter,
|
||||||
**kwargs
|
**argparse_args
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'-a', '--arch', choices=arch_choices, default='x86_64',
|
'-a', '--arch', choices=arch_choices, default='x86_64',
|
||||||
@@ -102,11 +106,13 @@ around when you checkout between branches.
|
|||||||
'-t', '--gem5-build-type', default='opt',
|
'-t', '--gem5-build-type', default='opt',
|
||||||
help='gem5 build type, most often used for "debug" builds. Default: %(default)s'
|
help='gem5 build type, most often used for "debug" builds. Default: %(default)s'
|
||||||
)
|
)
|
||||||
|
defaults = this.configs.copy()
|
||||||
|
defaults.update(default_args)
|
||||||
# A bit ugly as it actually changes the defaults shown on --help, but we can't do any better
|
# 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...
|
# 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/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
|
# - https://stackoverflow.com/questions/3609852/which-is-the-best-way-to-allow-configuration-options-be-overridden-at-the-comman
|
||||||
parser.set_defaults(**this.configs)
|
parser.set_defaults(**defaults)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
def print_cmd(cmd):
|
def print_cmd(cmd):
|
||||||
@@ -115,7 +121,7 @@ def print_cmd(cmd):
|
|||||||
out.extend([shlex.quote(arg), ' \\\n'])
|
out.extend([shlex.quote(arg), ' \\\n'])
|
||||||
print(''.join(out))
|
print(''.join(out))
|
||||||
|
|
||||||
def setup(parser):
|
def setup(parser, **extra_args):
|
||||||
"""
|
"""
|
||||||
Parse the command line arguments, and setup several variables based on them.
|
Parse the command line arguments, and setup several variables based on them.
|
||||||
Typically done after getting inputs from the command line arguments.
|
Typically done after getting inputs from the command line arguments.
|
||||||
|
|||||||
26
gem5-shell
26
gem5-shell
@@ -1,13 +1,13 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env python3
|
||||||
. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/common"
|
|
||||||
common_gem5=true
|
import subprocess
|
||||||
while getopts "${common_getopts_flags}" OPT; do
|
import sys
|
||||||
case "$OPT" in
|
|
||||||
?)
|
import common
|
||||||
common_getopts_case "$OPT"
|
|
||||||
;;
|
parser = common.get_argparse(
|
||||||
esac
|
default_args={'gem5':True},
|
||||||
done
|
argparse_args={'description':'Connect a terminal to a running gem5 instance'}
|
||||||
shift "$(($OPTIND - 1))"
|
)
|
||||||
common_setup
|
args = common.setup(parser)
|
||||||
"${common_gem5_m5term}" localhost "$common_gem5_telnet_port"
|
sys.exit(subprocess.Popen([str(common.gem5_m5term), 'localhost', str(common.gem5_telnet_port)]).wait())
|
||||||
|
|||||||
2
getvar
2
getvar
@@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
import common
|
import common
|
||||||
parser = common.get_argparse(
|
parser = common.get_argparse(
|
||||||
description='https://github.com/cirosantilli/linux-kernel-module-cheat#getvar'
|
argparse_args={'description':'https://github.com/cirosantilli/linux-kernel-module-cheat#getvar'}
|
||||||
)
|
)
|
||||||
parser.add_argument('variable')
|
parser.add_argument('variable')
|
||||||
args = common.setup(parser)
|
args = common.setup(parser)
|
||||||
|
|||||||
36
run
36
run
@@ -2,13 +2,14 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import shlex
|
import shlex
|
||||||
|
import signal
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import common
|
import common
|
||||||
|
|
||||||
# Argparse.
|
# Argparse.
|
||||||
parser = common.get_argparse(description='Run Linux on an emulator')
|
parser = common.get_argparse(argparse_args={'description':'Run Linux on an emulator'})
|
||||||
init_group = parser.add_mutually_exclusive_group()
|
init_group = parser.add_mutually_exclusive_group()
|
||||||
kvm_group = parser.add_mutually_exclusive_group()
|
kvm_group = parser.add_mutually_exclusive_group()
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
@@ -123,7 +124,7 @@ rare and don't affect performance, because `./configure
|
|||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'-U', '--tmux-args',
|
'-U', '--tmux-args', default='',
|
||||||
help='Pass extra parameters to the program running on the `-u` tmux split'
|
help='Pass extra parameters to the program running on the `-u` tmux split'
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
@@ -358,28 +359,37 @@ else:
|
|||||||
virtio_gpu_pci
|
virtio_gpu_pci
|
||||||
)
|
)
|
||||||
|
|
||||||
#if args.tmux:
|
if args.tmux:
|
||||||
# if args.gem5:
|
if args.gem5:
|
||||||
# eval "./tmu 'sleep 2;./gem5-shell -n ${common_run_id} ${tmux_args};'"
|
subprocess.Popen([os.path.join(common.root_dir, 'tmu'),
|
||||||
# elif args.debug:
|
'sleep 2;./gem5-shell -n {} {}' \
|
||||||
# eval "./tmu ./rungdb -a '${args.arch} -L ${common_linux_variant}' -n ${common_run_id} ${tmux_args}"
|
.format(args.run_id, args.tmux_args)
|
||||||
#if [ -n "${1:-}" ]; then
|
])
|
||||||
# extra_emulator_args="${extra_emulator_args}${@} \\
|
elif args.debug:
|
||||||
#"
|
# TODO find a nicer way to forward all those args automatically.
|
||||||
#fi
|
# Part of me wants to: https://github.com/jonathanslenders/pymux
|
||||||
|
# but it cannot be used as a library properly it seems, and it is
|
||||||
|
# slower than tmux.
|
||||||
|
subprocess.Popen([os.path.join(common.root_dir, 'tmu'),
|
||||||
|
"sleep 2;./rungdb -a '{}' -L '{}' -n '{}' {}" \
|
||||||
|
.format(args.arch, args.linux_build_id, args.run_id, args.tmux_args)
|
||||||
|
])
|
||||||
|
|
||||||
cmd += extra_emulator_args
|
cmd += extra_emulator_args
|
||||||
common.print_cmd(cmd)
|
common.print_cmd(cmd)
|
||||||
|
# Otherwise Ctrl + C gives an ugly Python stack trace for gem5 (QEMU takes over terminal and is fine).
|
||||||
|
signal.signal(signal.SIGINT, signal.SIG_IGN)
|
||||||
subprocess.Popen(cmd, env=env).wait()
|
subprocess.Popen(cmd, env=env).wait()
|
||||||
|
signal.signal(signal.SIGINT, signal.SIG_DFL)
|
||||||
|
|
||||||
#cmd="time \\
|
#cmd="time \\
|
||||||
#${cmd}${extra_emulator_args}"
|
#${cmd}${extra_emulator_args}"
|
||||||
#if [ -z "$debug_vm" ]; then
|
#if [ -z "$debug_vm" ]; then
|
||||||
# cmd="${cmd}\
|
# cmd="${cmd}\
|
||||||
#|& tee >(ts -s %.s > ${common_termout_file})\
|
#|& tee >(ts -s %.s > ${common.termout_file})\
|
||||||
#"
|
#"
|
||||||
#fi
|
#fi
|
||||||
#"${common_root_dir}/eeval" "$cmd" "${common_run_dir}/run.sh"
|
#"${common.root_dir}/eeval" "$cmd" "${common.run_dir}/run.sh"
|
||||||
#cmd_out=$?
|
#cmd_out=$?
|
||||||
#if [ "$cmd_out" -ne 0 ]; then
|
#if [ "$cmd_out" -ne 0 ]; then
|
||||||
# exit "$cmd_out"
|
# exit "$cmd_out"
|
||||||
|
|||||||
12
rungdb
12
rungdb
@@ -2,12 +2,13 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import shlex
|
import shlex
|
||||||
|
import sys
|
||||||
import signal
|
import signal
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
import common
|
import common
|
||||||
|
|
||||||
parser = common.get_argparse(description='Connect with GDB to an emulator to debug Linux itself')
|
parser = common.get_argparse(argparse_args={'description':'Connect with GDB to an emulator to debug Linux itself'})
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'-A', '--after', default='',
|
'-A', '--after', default='',
|
||||||
help='Pass extra arguments to GDB, to be appended after all other arguments'
|
help='Pass extra arguments to GDB, to be appended after all other arguments'
|
||||||
@@ -82,6 +83,9 @@ common.print_cmd(cmd)
|
|||||||
|
|
||||||
# TODO eeval
|
# TODO eeval
|
||||||
# "${common.root_dir}/eeval" "$cmd $after" "${common.run_dir}/rungdb.sh"
|
# "${common.root_dir}/eeval" "$cmd $after" "${common.run_dir}/rungdb.sh"
|
||||||
def signal_handler(sig, frame): pass
|
|
||||||
signal.signal(signal.SIGINT, signal_handler)
|
# Required, otherwise Ctrl + C kills Python and that kills GDB.
|
||||||
subprocess.Popen(cmd, cwd=common.linux_variant_dir).wait()
|
# https://stackoverflow.com/questions/19807134/does-python-always-raise-an-exception-if-you-do-ctrlc-when-a-subprocess-is-exec
|
||||||
|
signal.signal(signal.SIGINT, lambda *args: None)
|
||||||
|
|
||||||
|
sys.exit(subprocess.Popen(cmd, cwd=common.linux_variant_dir).wait())
|
||||||
|
|||||||
Reference in New Issue
Block a user