create userland tests

Fix some more tabs.

Parse the "Simulated exit code not 0!" string in gem5 and exit with the proper status
This commit is contained in:
Ciro Santilli 六四事件 法轮功
2019-01-22 00:00:00 +00:00
parent 780e9ceeb4
commit f2e73bac83
18 changed files with 183 additions and 67 deletions

View File

@@ -3065,6 +3065,32 @@ Step debug also works:
; ;
.... ....
===== gem5 syscall emulation exit status
As of gem5 7fa4c946386e7207ad5859e8ade0bbfc14000d91, the crappy `se.py` script does not forward the exit status of syscall emulation mode, you can test it with:
....
./run --dry-run --gem5 --userland false --userland-build-id static
....
Source: link:userland/false[].
Then manually run the generated gem5 CLI, and do:
....
echo $?
....
and the output is always `0`.
Instead, it just outputs a message to stdout just like for <<m5-fail>>:
....
Simulated exit code not 0! Exit code is 1
....
which we parse in link:run[] and then exit with the correct result ourselves...
==== User mode vs full system benchmark ==== User mode vs full system benchmark
Let's see if user mode runs considerably faster than full system or not. Let's see if user mode runs considerably faster than full system or not.
@@ -3125,6 +3151,18 @@ Result on <<p51>> at bad30f513c46c1b0995d3a10c0d9bc2a33dc4fa0:
* QEMU user: 45 seconds * QEMU user: 45 seconds
* QEMU full system: 223 seconds * QEMU full system: 223 seconds
=== User mode testing
Automatically run non-interactive userland tests that don't depend on nay kernel modules:
....
./test-userland
....
Source: link:test-userland[]
The gem5 tests require building statically with build id `static`, see also: <<gem5-syscall-emulation-mode>>. TODO automate this better.
== Kernel module utilities == Kernel module utilities
=== insmod === insmod
@@ -7390,7 +7428,7 @@ Looks like a more raw alternative to libdrm:
.... ....
./build-buildroot --config 'BR2_PACKABE_LIBDRI2=y' ./build-buildroot --config 'BR2_PACKABE_LIBDRI2=y'
wget \ wget \
-O "$(./getvar userland_src_dir)/dri2test.c" \ -O "$(./getvar userland_source_dir)/dri2test.c" \
https://raw.githubusercontent.com/robclark/libdri2/master/test/dri2test.c \ https://raw.githubusercontent.com/robclark/libdri2/master/test/dri2test.c \
; ;
./build-userland ./build-userland
@@ -9551,7 +9589,9 @@ Simulated exit code not 0! Exit code is 1
and exits with status 0. and exits with status 0.
TODO: it used to exit non 0, be like that, but it actually got changed to just print the message. Why? https://gem5-review.googlesource.com/c/public/gem5/+/4880 We then parse that string ourselves in link:run[] and exit with the correct status...
TODO: it used to be like that, but it actually got changed to just print the message. Why? https://gem5-review.googlesource.com/c/public/gem5/+/4880
`m5 fail` is just a superset of `m5 exit`, which is just: `m5 fail` is just a superset of `m5 exit`, which is just:

View File

@@ -61,7 +61,7 @@ has the OpenBLAS libraries and headers installed.
'make', LF, 'make', LF,
'-j', str(self.env['nproc']), LF, '-j', str(self.env['nproc']), LF,
'ARCH={}'.format(self.env['arch']), LF, 'ARCH={}'.format(self.env['arch']), LF,
'CCFLAGS_SCRIPT={} {}'.format('-I', self.env['userland_src_dir']), LF, 'CCFLAGS_SCRIPT={} {}'.format('-I', self.env['userland_source_dir']), LF,
'COMMON_DIR={}'.format(self.env['root_dir']), LF, 'COMMON_DIR={}'.format(self.env['root_dir']), LF,
'CC={}'.format(cc), LF, 'CC={}'.format(cc), LF,
'CXX={}'.format(cxx), LF, 'CXX={}'.format(cxx), LF,
@@ -73,7 +73,7 @@ has the OpenBLAS libraries and headers installed.
shlex.split(self.env['make_args']) + shlex.split(self.env['make_args']) +
self.sh.add_newlines([os.path.join(build_dir, os.path.splitext(os.path.split(target)[1])[0]) + self.env['userland_build_ext'] for target in self.env['targets']]) self.sh.add_newlines([os.path.join(build_dir, os.path.splitext(os.path.split(target)[1])[0]) + self.env['userland_build_ext'] for target in self.env['targets']])
), ),
cwd=self.env['userland_src_dir'], cwd=self.env['userland_source_dir'],
extra_paths=[self.env['ccache_dir']], extra_paths=[self.env['ccache_dir']],
) )
self.sh.copy_dir_if_update_non_recursive( self.sh.copy_dir_if_update_non_recursive(

View File

@@ -3,6 +3,7 @@
import argparse import argparse
import imp import imp
import os import os
import sys
class _Argument: class _Argument:
def __init__( def __init__(
@@ -193,6 +194,12 @@ class CliFunction:
args = parser.parse_args(args=cli_args) args = parser.parse_args(args=cli_args)
return self(**vars(args)) return self(**vars(args))
def cli_exit(self, *args, **kwargs):
'''
Same as cli, but also exit the program with int(cli().
'''
sys.exit(int(self.cli(*args, **kwargs)))
@staticmethod @staticmethod
def get_key(*args, **kwargs): def get_key(*args, **kwargs):
return _Argument.get_key(*args, **kwargs) return _Argument.get_key(*args, **kwargs)

View File

@@ -49,7 +49,7 @@ consts['packages_dir'] = os.path.join(consts['root_dir'], 'buildroot_packages')
consts['kernel_modules_subdir'] = 'kernel_modules' consts['kernel_modules_subdir'] = 'kernel_modules'
consts['kernel_modules_src_dir'] = os.path.join(consts['root_dir'], consts['kernel_modules_subdir']) consts['kernel_modules_src_dir'] = os.path.join(consts['root_dir'], consts['kernel_modules_subdir'])
consts['userland_subdir'] = 'userland' consts['userland_subdir'] = 'userland'
consts['userland_src_dir'] = os.path.join(consts['root_dir'], consts['userland_subdir']) consts['userland_source_dir'] = os.path.join(consts['root_dir'], consts['userland_subdir'])
consts['userland_build_ext'] = '.out' consts['userland_build_ext'] = '.out'
consts['include_subdir'] = 'include' consts['include_subdir'] = 'include'
consts['include_src_dir'] = os.path.join(consts['root_dir'], consts['include_subdir']) consts['include_src_dir'] = os.path.join(consts['root_dir'], consts['include_subdir'])
@@ -783,7 +783,7 @@ Use gem5 instead of QEMU. Shortcut for `--emulator gem5`.
def resolve_userland(self, path): def resolve_userland(self, path):
return self.resolve_executable( return self.resolve_executable(
path, path,
self.env['userland_src_dir'], self.env['userland_source_dir'],
self.env['userland_build_dir'], self.env['userland_build_dir'],
self.env['userland_build_ext'], self.env['userland_build_ext'],
) )

View File

@@ -1,17 +1,23 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import sys
import common import common
from shell_helpers import LF from shell_helpers import LF
parser = self.get_argparse( class Main(common.LkmcCliFunction):
default_args={'gem5':True}, def __init__(self):
argparse_args={'description':'Connect a terminal to a running gem5 instance'} super().__init__(
defaults={
'gem5': True,
},
description='Connect a terminal to a running gem5 instance',
) )
args = self.setup(parser) def timed_main(self):
sys.exit(self.sh.run_cmd([ return self.sh.run_cmd([
kwargs['gem5_m5term'], LF, self.env['gem5_m5term'],
'localhost', LF, 'localhost',
str(kwargs['gem5_telnet_port']), LF, str(self.env['gem5_telnet_port']),
])) LF,
])
if __name__ == '__main__':
Main().cli_exit()

27
run
View File

@@ -343,7 +343,7 @@ Run QEMU with VNC instead of the default SDL. Connect to it with:
if self.env['userland'] is not None: if self.env['userland'] is not None:
cmd.extend([ cmd.extend([
self.env['gem5_se_file'], LF, self.env['gem5_se_file'], LF,
'-c', self.resolve_userland(self.env['userland']), LF, '--cmd', self.resolve_userland(self.env['userland']), LF,
]) ])
else: else:
if self.env['gem5_script'] == 'fs': if self.env['gem5_script'] == 'fs':
@@ -578,7 +578,8 @@ Run QEMU with VNC instead of the default SDL. Connect to it with:
tmux_args += " --baremetal '{}'".format(self.env['baremetal']) tmux_args += " --baremetal '{}'".format(self.env['baremetal'])
if self.env['userland']: if self.env['userland']:
tmux_args += " --userland '{}'".format(self.env['userland']) tmux_args += " --userland '{}'".format(self.env['userland'])
tmux_args += ' {}'.format(self.env['tmux']) if self.env['tmux_args'] is not None:
tmux_args += ' {}'.format(self.env['tmux_args'])
subprocess.Popen([ subprocess.Popen([
os.path.join(self.env['root_dir'], 'tmu'), os.path.join(self.env['root_dir'], 'tmu'),
"sleep 2;{} {}".format(tmux_cmd, tmux_args) "sleep 2;{} {}".format(tmux_cmd, tmux_args)
@@ -599,22 +600,24 @@ Run QEMU with VNC instead of the default SDL. Connect to it with:
panic_msg = b'Kernel panic - not syncing' panic_msg = b'Kernel panic - not syncing'
panic_re = re.compile(panic_msg) panic_re = re.compile(panic_msg)
error_string_found = False error_string_found = False
exit_status = 0
if out_file is not None and not self.env['dry_run']: if out_file is not None and not self.env['dry_run']:
with open(self.env['termout_file'], 'br') as logfile: with open(self.env['termout_file'], 'br') as logfile:
for line in logfile: for line in logfile:
if panic_re.search(line): if panic_re.search(line):
error_string_found = True exit_status = 1
last_line = line.rstrip()
match = re.search(b'Simulated exit code not 0! Exit code is (\d+)', last_line)
if match:
exit_status = int(match.group(1))
if not self.env['userland']:
if os.path.exists(self.env['guest_terminal_file']): if os.path.exists(self.env['guest_terminal_file']):
with open(self.env['guest_terminal_file'], 'br') as logfile: with open(self.env['guest_terminal_file'], 'br') as logfile:
lines = logfile.readlines() if logfile.readlines()[-1].rstrip() == self.env['magic_fail_string']:
if lines: exit_status = 1
last_line = lines[-1] if exit_status != 0:
if last_line.rstrip() == self.env['magic_fail_string']:
error_string_found = True
if error_string_found:
self.log_error('simulation error detected by parsing logs') self.log_error('simulation error detected by parsing logs')
return 1 return exit_status
return 0
if __name__ == '__main__': if __name__ == '__main__':
Main().cli() Main().cli_exit()

View File

@@ -1,6 +1,5 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import functools
import threading import threading
import os import os
@@ -29,13 +28,15 @@ class Main(common.LkmcCliFunction):
arch=arch, arch=arch,
background=True, background=True,
baremetal=test_script_noext, baremetal=test_script_noext,
print_time=False,
emulator=emulator, emulator=emulator,
wait_gdb=True wait_gdb=True
)) ))
run_thread.start() run_thread.start()
run_gdb( run_gdb(
arch=arch, baremetal=test_script_noext, print_time=False, emulator=emulator, test=True arch=arch,
baremetal=test_script_noext,
emulator=emulator,
test=True,
) )
run_thread.join() run_thread.join()

47
test-userland Executable file
View File

@@ -0,0 +1,47 @@
#!/usr/bin/env python3
import os
import common
class Main(common.LkmcCliFunction):
def timed_main(self):
run = self.import_path('run').Main()
sources = [
'add.c',
'hello.c',
'hello_cpp.cpp',
'print_argv.c',
]
# for emulator in self.env['emulators']:
for emulator in ['gem5']:
if emulator == 'gem5':
extra_args = {
'userland_build_id': 'static',
}
else:
extra_args = {}
for arch in self.env['all_archs']:
if arch == 'x86_64':
arch_sources = [
'asm_hello'
]
elif arch == 'aarch64':
arch_sources = [
'asm_hello'
]
else:
arch_sources = []
arch_sources[:] = [os.path.join('arch', arch, arch_source) for arch_source in arch_sources]
for source in sources + arch_sources:
exit_status = run(
arch=arch,
userland=source,
emulator=emulator,
**extra_args,
)
if exit_status != 0:
raise Exception('Test failed: {} {} {} {}'.format(emulator, arch, source, exit_status))
if __name__ == '__main__':
Main().cli()

View File

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

13
userland/false.c Normal file
View File

@@ -0,0 +1,13 @@
/* Test that emulators forward the exit status properly. */
#include <stdlib.h>
int main(int argc, char **argv) {
int ret;
if (argc == 1) {
ret = 1;
} else {
ret = strtoull(argv[1], NULL, 0);
}
return ret;
}