dhrystone: create nicer custom build, baremetal almost working

This commit is contained in:
Ciro Santilli 六四事件 法轮功
2019-10-18 00:00:01 +00:00
parent 14a1bb62b6
commit 59f96b192a
8 changed files with 180 additions and 34 deletions

3
.gitmodules vendored
View File

@@ -14,6 +14,9 @@
path = submodules/crosstool-ng
# url = https://github.com/crosstool-ng/crosstool-ng
url = https://github.com/cirosantilli/crosstool-ng
[submodule "submodules/dhrystone"]
path = submodules/dhrystone
url = https://github.com/cirosantilli/dhrystone
[submodule "submodules/gcc"]
path = submodules/gcc
# url = git://gcc.gnu.org/git/gcc.git

View File

@@ -3957,7 +3957,9 @@ Source: link:userland/c/getchar.c[]
Let's see if user mode runs considerably faster than full system or not.
First we build Dhrystone manually statically since dynamic linking is broken in gem5 as explained at: xref:gem5-syscall-emulation-mode[xrefstyle=full].
First we build <<dhrystone>> manually statically since dynamic linking is broken in gem5 as explained at: xref:gem5-syscall-emulation-mode[xrefstyle=full].
TODO: move this section to our new custom dhrystone setup: xref:dhrystone[xrefstyle=full].
gem5 user mode:
@@ -10454,7 +10456,7 @@ gem5 however has tended towards intensive code generation in order to support al
OK, this is why we used gem5 in the first place, performance measurements!
Let's see how many cycles https://en.wikipedia.org/wiki/Dhrystone[Dhrystone], which Buildroot provides, takes for a few different input parameters.
Let's see how many cycles <<dhrystone>>, which Buildroot provides, takes for a few different input parameters.
We will do that for various input parameters on full system by taking a checkpoint after the boot finishes a fast atomic CPU boot, and then we will restore in a more detailed mode and run the benchmark:
@@ -10937,6 +10939,52 @@ Buildroot built-in libraries, mostly under Libraries > Other:
There are not yet enabled, but it should be easy to so, see: xref:add-new-buildroot-packages[xrefstyle=full]
===== Dhrystone
https://en.wikipedia.org/wiki/Dhrystone
Created in the 80's, it is not a representative measure of performance in modern computers anymore. It has mostly been replaced by https://en.wikipedia.org/wiki/SPECint[SPEC], which is... closed source! Unbelievable.
<<buildroot>> has a `dhrystone` package, but because it is so interesting to us, we decided to also build it ourselves, which allows things like static and baremetal compilation more easily.
Build and run on QEMU <<user-mode-simulation>>:
....
git submodule update --init submodules/dhrystone
./build-dhrystone --mode userland
./run --userland "$(./getvar userland_build_dir)/submodules/dhrystone/dhrystone"
....
Build and run on gem5 use mode:
....
./build-dhrystone --mode userland --static --force-rebuild
./run --emulator gem5 --userland "$(./getvar userland_build_dir)/submodules/dhrystone/dhrystone"
....
TODO automate run more nicely.
Build for <<baremetal>> execution and run it in baremetal QEMU:
....
./build-dhrystone --arch aarch64 --mode baremetal
./run --arch aarch64 --baremetal "$(./getvar baremetal_build_dir)/submodules/dhrystone/dhrystone"
....
TODO: fix the build, just need to factor out all run arguments from link:build-baremetal[] into link:common.py[] and it should just work, no missing syscalls.
If you really want the Buildroot package for some reason, build it with:
....
./build-buildroot --config 'BR2_PACKAGE_DHRYSTONE=y'
....
and run inside the guest from `PATH` with:
....
dhrystone
....
===== BST vs heap vs hashmap
The following benchmark setup works both:

View File

@@ -1,15 +1,21 @@
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/times.h>
#include <lkmc.h>
#define UART_DR(baseaddr) (*(unsigned int *)(baseaddr))
#define UART_FR(baseaddr) (*(((unsigned int *)(baseaddr))+6))
enum {
UART_FR_RXFE = 0x10,
};
#define UART_DR(baseaddr) (*(unsigned int *)(baseaddr))
#define UART_FR(baseaddr) (*(((unsigned int *)(baseaddr))+6))
extern char heap_low;
extern char heap_top;
char *heap_end = 0;
void lkmc_baremetal_on_exit_callback(int status, void *arg) {
(void)arg;
@@ -73,10 +79,15 @@ int _read(int file, char *ptr, int len) {
return todo;
}
char *heap_end = 0;
/* Dummy implementation that just increments an integer. */
_CLOCK_T_ _times_r (struct _reent *r, struct tms *ptms) {
static long long unsigned t = 0;
(void)r;
(void)ptms;
return t++;
}
caddr_t _sbrk(int incr) {
extern char heap_low;
extern char heap_top;
char *prev_heap_end;
if (heap_end == 0) {
heap_end = &heap_low;

View File

@@ -36,23 +36,6 @@ Build the baremetal examples with crosstool-NG.
self.env['baremetal_build_lib_dir'],
self.env['common_basename_noext'] + self.env['obj_ext']
)
syscalls_basename_noext = 'syscalls'
syscalls_src = os.path.join(
self.env['baremetal_source_lib_dir'],
syscalls_basename_noext + self.env['c_ext']
)
syscalls_obj = os.path.join(
self.env['baremetal_build_lib_dir'],
syscalls_basename_noext + self.env['obj_ext']
)
syscalls_asm_src = os.path.join(
self.env['baremetal_source_lib_dir'],
syscalls_basename_noext + '_asm' + self.env['asm_ext']
)
syscalls_asm_obj = os.path.join(
self.env['baremetal_build_lib_dir'],
syscalls_basename_noext + '_asm' + self.env['obj_ext']
)
cc_flags = [
'-I', self.env['root_dir'], LF,
'-O{}'.format(self.env['optimization_level']), LF,
@@ -101,8 +84,14 @@ Build the baremetal examples with crosstool-NG.
for in_path, out_path in [
(bootloader_src, extra_obj_baremetal_bootloader),
(self.env['common_c'], extra_obj_lkmc_common),
(syscalls_src, syscalls_obj),
(syscalls_asm_src, syscalls_asm_obj),
(
self.env['baremetal_syscalls_src'],
self.env['baremetal_syscalls_obj']
),
(
self.env['baremetal_syscalls_asm_src'],
self.env['baremetal_syscalls_asm_obj']
),
]:
self._build_one(
in_path=in_path,
@@ -133,7 +122,10 @@ Build the baremetal examples with crosstool-NG.
self.env['baremetal_link_script'],
self.env['common_h']
],
'extra_objs': [syscalls_obj, syscalls_asm_obj],
'extra_objs': [
self.env['baremetal_syscalls_obj'],
self.env['baremetal_syscalls_asm_obj']
],
'extra_objs_baremetal_bootloader': [extra_obj_baremetal_bootloader],
'extra_objs_lkmc_common': [extra_obj_lkmc_common],
'in_path': in_path,

62
build-dhrystone Executable file
View File

@@ -0,0 +1,62 @@
#!/usr/bin/env python3
import os
import shutil
import common
import shlex
from shell_helpers import LF
class Main(common.BuildCliFunction):
def __init__(self):
super().__init__(
description='''\
https://cirosantilli.com/linux-kernel-module-cheat#dhrystone
'''
)
self._add_argument('--ccflags')
self._add_argument('--force-rebuild')
self._add_argument('--optimization-level')
def setup(self, env):
self.root_relpath = os.path.join('submodules', 'dhrystone')
def build(self):
build_dir = self.get_build_dir()
cflags = ['-O{}'.format(self.env['optimization_level'])]
extra_flags = []
if self.env['static']:
cflags.extend(['-static'])
if self.env['force_rebuild']:
extra_flags.extend(['-B', LF])
if self.env['mode'] == 'baremetal':
extra_objs = [
self.env['baremetal_syscalls_obj'],
self.env['baremetal_syscalls_asm_obj']
]
else:
extra_objs = []
ret = self.sh.run_cmd(
[
'make', LF,
'-j', str(self.env['nproc']), LF,
'-C', os.path.join(self.env['submodules_dir'], 'dhrystone'), LF,
'CC={}'.format(self.env['gcc_path']), LF,
'CFLAGS={}'.format(' '.join(cflags)), LF,
'EXTRA_OBJS={}'.format(' '.join(extra_objs)), LF,
'OUT_DIR={}'.format(build_dir), LF,
]
+ extra_flags
)
if ret == 0 and self.env['mode'] == 'userland':
self.sh.copy_file_if_update(
os.path.join(build_dir, 'dhrystone'),
os.path.join(self.env['out_rootfs_overlay_lkmc_dir'], self.root_relpath),
)
return ret
def get_build_dir(self):
return os.path.join(self.env['build_dir'], self.root_relpath)
if __name__ == '__main__':
Main().cli()

View File

@@ -947,6 +947,23 @@ Incompatible archs are skipped.
env['simulator_name'] = 'qemu'
env['baremetal_build_dir'] = join(env['out_dir'], 'baremetal', env['arch'], env['simulator_name'], env['machine'])
env['baremetal_build_lib_dir'] = join(env['baremetal_build_dir'], env['baremetal_lib_basename'])
env['baremetal_syscalls_basename_noext'] = 'syscalls'
env['baremetal_syscalls_src'] = os.path.join(
env['baremetal_source_lib_dir'],
env['baremetal_syscalls_basename_noext'] + self.env['c_ext']
)
env['baremetal_syscalls_obj'] = os.path.join(
self.env['baremetal_build_lib_dir'],
env['baremetal_syscalls_basename_noext'] + self.env['obj_ext']
)
env['baremetal_syscalls_asm_src'] = os.path.join(
self.env['baremetal_source_lib_dir'],
env['baremetal_syscalls_basename_noext'] + '_asm' + self.env['asm_ext']
)
env['baremetal_syscalls_asm_obj'] = os.path.join(
self.env['baremetal_build_lib_dir'],
env['baremetal_syscalls_basename_noext'] + '_asm' + self.env['obj_ext']
)
# Userland / baremetal common source.
env['common_basename_noext'] = env['repo_short_id']
@@ -958,6 +975,10 @@ Incompatible archs are skipped.
env['root_dir'],
env['common_basename_noext'] + env['header_ext']
)
if env['mode'] == 'baremetal':
env['build_dir'] = env['baremetal_build_dir']
elif env['mode'] == 'userland':
env['build_dir'] = env['userland_build_dir']
# Docker
env['docker_build_dir'] = join(env['out_dir'], 'docker', env['arch'])
@@ -1022,8 +1043,10 @@ lunch aosp_{}-eng
'''.format(self.env['android_arch'])
# Toolchain.
if env['baremetal'] and not env['_args_given']['mode']:
env['mode'] = 'baremetal'
if not env['_args_given']['gcc_which']:
if env['baremetal']:
if env['mode'] == 'baremetal':
env['gcc_which'] = 'crosstool-ng'
if env['gcc_which'] == 'buildroot':
env['toolchain_prefix'] = os.path.join(

View File

@@ -162,6 +162,15 @@ class ShellHelpers:
ending = last_newline + ';'
return newline_separator.join(out) + ending
def copy_file_if_update(self, src, dest):
if os.path.isdir(dest):
dest = os.path.join(dest, os.path.basename(src))
if (
not os.path.exists(dest) or \
os.path.getmtime(src) > os.path.getmtime(dest)
):
self.cp(src, dest)
def copy_dir_if_update_non_recursive(
self,
srcdir,
@@ -178,12 +187,9 @@ class ShellHelpers:
src = os.path.join(srcdir, basename)
if os.path.isfile(src) or os.path.islink(src):
noext, ext = os.path.splitext(basename)
dest = os.path.join(destdir, basename)
if (
(filter_ext is None or ext == filter_ext) and
(not os.path.exists(dest) or os.path.getmtime(src) > os.path.getmtime(dest))
):
self.cp(src, dest)
if (filter_ext is None or ext == filter_ext):
dest = os.path.join(destdir, basename)
self.copy_file_if_update(src, dest)
def copy_dir_if_update(
self,

1
submodules/dhrystone Submodule

Submodule submodules/dhrystone added at fb5e01298a