mirror of
https://github.com/cirosantilli/linux-kernel-module-cheat.git
synced 2026-01-28 04:24:26 +01:00
userland: make libs work
Working for build, but now test-user-mode-in-tree is not using --in-tree, TODO fix later on.
This commit is contained in:
52
README.adoc
52
README.adoc
@@ -973,7 +973,7 @@ This is the most reproducible and controlled environment, and all examples work
|
|||||||
|
|
||||||
With this setup, we will use the host toolchain and execute executables directly on the host.
|
With this setup, we will use the host toolchain and execute executables directly on the host.
|
||||||
|
|
||||||
No installation or toolchain build is reuqired, so you can just jump straight into it.
|
No installation or toolchain build is required, so you can just jump straight into it.
|
||||||
|
|
||||||
Build, run and example, and clean it in-tree with:
|
Build, run and example, and clean it in-tree with:
|
||||||
|
|
||||||
@@ -1002,13 +1002,22 @@ cd userland/c
|
|||||||
./test
|
./test
|
||||||
....
|
....
|
||||||
|
|
||||||
You can install those libraries and do the build in one go with:
|
As mentioned at <<user-mode-tests>>, tests under link:userland/libs[] require certain optional libraries to be installed, and are not built or tested by default.
|
||||||
|
|
||||||
|
You can install those libraries with:
|
||||||
|
|
||||||
....
|
....
|
||||||
cd linux-kernel-module-cheat
|
cd linux-kernel-module-cheat
|
||||||
./build --download-dependencies userland-host
|
./build --download-dependencies userland-host
|
||||||
....
|
....
|
||||||
|
|
||||||
|
and then build the examples and test with:
|
||||||
|
|
||||||
|
....
|
||||||
|
./build --package-all
|
||||||
|
./test --package-all
|
||||||
|
....
|
||||||
|
|
||||||
Pass custom compiler options:
|
Pass custom compiler options:
|
||||||
|
|
||||||
....
|
....
|
||||||
@@ -3536,7 +3545,7 @@ This script skips a manually configured list of tests, notably:
|
|||||||
* tests that take perceptible ammounts of time
|
* tests that take perceptible ammounts of time
|
||||||
* known bugs we didn't have time to fix ;-)
|
* known bugs we didn't have time to fix ;-)
|
||||||
|
|
||||||
Tests under link:userland/libs/[] depend on certain libraries being available on the target, e.g. <<blas>> for link:userland/libs/blas[]. They are not run by default, but can be enabled with `--has-package` and `--has-all-packages`.
|
Tests under link:userland/libs/[] depend on certain libraries being available on the target, e.g. <<blas>> for link:userland/libs/blas[]. They are not run by default, but can be enabled with `--package` and `--package-all`.
|
||||||
|
|
||||||
The gem5 tests require building statically with build id `static`, see also: <<gem5-syscall-emulation-mode>>. TODO automate this better.
|
The gem5 tests require building statically with build id `static`, see also: <<gem5-syscall-emulation-mode>>. TODO automate this better.
|
||||||
|
|
||||||
@@ -3695,7 +3704,7 @@ So programs that rely on those libraries might not compile as GCC can't find the
|
|||||||
For example, if we try to build <<blas>> statically:
|
For example, if we try to build <<blas>> statically:
|
||||||
|
|
||||||
....
|
....
|
||||||
./build-userland --has-package openblas --static -- userland/libs/openblas/hello.c
|
./build-userland --package openblas --static -- userland/libs/openblas/hello.c
|
||||||
....
|
....
|
||||||
|
|
||||||
it fails with:
|
it fails with:
|
||||||
@@ -8302,7 +8311,7 @@ DRM / DRI is the new interface that supersedes `fbdev`:
|
|||||||
|
|
||||||
....
|
....
|
||||||
./build-buildroot --config 'BR2_PACKAGE_LIBDRM=y'
|
./build-buildroot --config 'BR2_PACKAGE_LIBDRM=y'
|
||||||
./build-userland --has-package libdrm -- userland/libs/libdrm/modeset.c
|
./build-userland --package libdrm -- userland/libs/libdrm/modeset.c
|
||||||
./run --eval-after './libs/libdrm/modeset.out' --graphic
|
./run --eval-after './libs/libdrm/modeset.out' --graphic
|
||||||
....
|
....
|
||||||
|
|
||||||
@@ -8314,7 +8323,7 @@ TODO not working for `aarch64`, it takes over the screen for a few seconds and t
|
|||||||
|
|
||||||
....
|
....
|
||||||
./build-buildroot --config 'BR2_PACKAGE_LIBDRM=y'
|
./build-buildroot --config 'BR2_PACKAGE_LIBDRM=y'
|
||||||
./build-userland --has-package libdrm
|
./build-userland --package libdrm
|
||||||
./build-buildroot
|
./build-buildroot
|
||||||
./run --eval-after './libs/libdrm/modeset.out' --graphic
|
./run --eval-after './libs/libdrm/modeset.out' --graphic
|
||||||
....
|
....
|
||||||
@@ -10061,7 +10070,7 @@ Buildroot supports it, which makes everything just trivial:
|
|||||||
|
|
||||||
....
|
....
|
||||||
./build-buildroot --config 'BR2_PACKAGE_OPENBLAS=y'
|
./build-buildroot --config 'BR2_PACKAGE_OPENBLAS=y'
|
||||||
./build-userland --has-package openblas -- userland/libs/openblas/hello.c
|
./build-userland --package openblas -- userland/libs/openblas/hello.c
|
||||||
./run --eval-after './libs/openblas/hello.out; echo $?'
|
./run --eval-after './libs/openblas/hello.out; echo $?'
|
||||||
....
|
....
|
||||||
|
|
||||||
@@ -10101,7 +10110,7 @@ Header only linear algebra library with a mainline Buildroot package:
|
|||||||
|
|
||||||
....
|
....
|
||||||
./build-buildroot --config 'BR2_PACKAGE_EIGEN=y'
|
./build-buildroot --config 'BR2_PACKAGE_EIGEN=y'
|
||||||
./build-userland --has-package eigen -- userland/libs/eigen/hello.cpp
|
./build-userland --package eigen -- userland/libs/eigen/hello.cpp
|
||||||
....
|
....
|
||||||
|
|
||||||
Just create an array and print it:
|
Just create an array and print it:
|
||||||
@@ -13351,7 +13360,7 @@ We have link:https://buildroot.org/downloads/manual/manual.html#ccache[enabled c
|
|||||||
* absolute paths are used and GDB can find source files
|
* absolute paths are used and GDB can find source files
|
||||||
* but builds are not reused across separated LKMC directories
|
* but builds are not reused across separated LKMC directories
|
||||||
|
|
||||||
=== Rebuild buildroot while running
|
=== Rebuild Buildroot while running
|
||||||
|
|
||||||
It is not possible to rebuild the root filesystem while running QEMU because QEMU holds the file qcow2 file:
|
It is not possible to rebuild the root filesystem while running QEMU because QEMU holds the file qcow2 file:
|
||||||
|
|
||||||
@@ -13640,6 +13649,31 @@ We chose this awkward name so that our includes will have an `lkmc/` prefix.
|
|||||||
|
|
||||||
Another option would have been to name it as `includes/lkmc`, but that would make paths longer, and we might want to store source code in that directory as well in the future.
|
Another option would have been to name it as `includes/lkmc`, but that would make paths longer, and we might want to store source code in that directory as well in the future.
|
||||||
|
|
||||||
|
===== Userland objects vs header-only
|
||||||
|
|
||||||
|
When factoring out functionality across userland examples, there are two main options:
|
||||||
|
|
||||||
|
* use header-only implementations
|
||||||
|
* use separate C files and link to separate objects.
|
||||||
|
|
||||||
|
The downsides of the header-only implementation are:
|
||||||
|
|
||||||
|
* slower compilation time, especially for C++
|
||||||
|
* cannot call C implementations from assembly files
|
||||||
|
|
||||||
|
The advantages of header-only implementations are:
|
||||||
|
|
||||||
|
* easier to use, just `#include` and you are done, no need to modify build metadata.
|
||||||
|
|
||||||
|
As a result, we are currently using the following rule:
|
||||||
|
|
||||||
|
* if something is only going to be used from C and not assembly, define it in a header which is easier to use
|
||||||
|
+
|
||||||
|
The slower compilation should be OK as long as split functionality amongst different headers and only include the required ones.
|
||||||
|
+
|
||||||
|
Also we don't have a choice in the case of C++ template, which must stay in headers.
|
||||||
|
* if the functionality will be called from assembly, then we don't have a choice, and must add it to a separate source file and link against it.
|
||||||
|
|
||||||
==== buildroot_packages directory
|
==== buildroot_packages directory
|
||||||
|
|
||||||
Source: link:buildroot_packages/[]
|
Source: link:buildroot_packages/[]
|
||||||
|
|||||||
110
build-userland
110
build-userland
@@ -17,21 +17,6 @@ class Main(common.BuildCliFunction):
|
|||||||
Build our compiled userland examples.
|
Build our compiled userland examples.
|
||||||
'''
|
'''
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.add_argument(
|
|
||||||
'--has-package',
|
|
||||||
action='append',
|
|
||||||
help='''\
|
|
||||||
Indicate that a given package is present in the root filesystem, which
|
|
||||||
allows us to build examples that rely on it.
|
|
||||||
''',
|
|
||||||
)
|
|
||||||
self.add_argument(
|
|
||||||
'--has-all-packages',
|
|
||||||
action='store_true',
|
|
||||||
help='''\
|
|
||||||
Indicate that all packages from --has-package are available.
|
|
||||||
''',
|
|
||||||
)
|
|
||||||
self.add_argument(
|
self.add_argument(
|
||||||
'targets',
|
'targets',
|
||||||
default=[],
|
default=[],
|
||||||
@@ -49,7 +34,7 @@ Default: build all examples that have their package dependencies met, e.g.:
|
|||||||
- userland/arch/ programs only build if the target arch matches
|
- userland/arch/ programs only build if the target arch matches
|
||||||
- an OpenBLAS example can only be built if the target root filesystem
|
- an OpenBLAS example can only be built if the target root filesystem
|
||||||
has the OpenBLAS libraries and headers installed, which you must inform
|
has the OpenBLAS libraries and headers installed, which you must inform
|
||||||
with --has-package
|
with --package
|
||||||
''',
|
''',
|
||||||
nargs='*',
|
nargs='*',
|
||||||
)
|
)
|
||||||
@@ -87,9 +72,6 @@ Default: build all examples that have their package dependencies met, e.g.:
|
|||||||
std = path_properties.default_c_std
|
std = path_properties.default_c_std
|
||||||
else:
|
else:
|
||||||
std = c_std
|
std = c_std
|
||||||
cc_flags.extend([
|
|
||||||
'-fopenmp', LF,
|
|
||||||
])
|
|
||||||
elif in_ext == self.env['cxx_ext']:
|
elif in_ext == self.env['cxx_ext']:
|
||||||
cc = self.env['gxx']
|
cc = self.env['gxx']
|
||||||
if cxx_std is None:
|
if cxx_std is None:
|
||||||
@@ -109,10 +91,6 @@ Default: build all examples that have their package dependencies met, e.g.:
|
|||||||
in_path, LF,
|
in_path, LF,
|
||||||
] +
|
] +
|
||||||
self.sh.add_newlines(extra_objs) +
|
self.sh.add_newlines(extra_objs) +
|
||||||
[
|
|
||||||
'-lm', LF,
|
|
||||||
'-pthread', LF,
|
|
||||||
] +
|
|
||||||
cc_flags_after
|
cc_flags_after
|
||||||
),
|
),
|
||||||
extra_paths=[self.env['ccache_dir']],
|
extra_paths=[self.env['ccache_dir']],
|
||||||
@@ -121,16 +99,9 @@ Default: build all examples that have their package dependencies met, e.g.:
|
|||||||
|
|
||||||
def build(self):
|
def build(self):
|
||||||
build_dir = self.get_build_dir()
|
build_dir = self.get_build_dir()
|
||||||
has_packages = set(self.env['has_package'])
|
|
||||||
has_all_packages = self.env['has_all_packages']
|
|
||||||
cc_flags = [
|
cc_flags = [
|
||||||
'-I', self.env['root_dir'], LF,
|
'-I', self.env['root_dir'], LF,
|
||||||
'-O{}'.format(self.env['optimization_level']), LF,
|
'-O{}'.format(self.env['optimization_level']), LF,
|
||||||
'-Wall', LF,
|
|
||||||
'-Werror', LF,
|
|
||||||
'-Wextra', LF,
|
|
||||||
'-Wno-unused-function', LF,
|
|
||||||
'-ggdb3', LF,
|
|
||||||
] + self.sh.shlex_split(self.env['ccflags'])
|
] + self.sh.shlex_split(self.env['ccflags'])
|
||||||
if self.env['static']:
|
if self.env['static']:
|
||||||
cc_flags.extend(['-static', LF])
|
cc_flags.extend(['-static', LF])
|
||||||
@@ -168,7 +139,7 @@ Default: build all examples that have their package dependencies met, e.g.:
|
|||||||
eigen_root = '/'
|
eigen_root = '/'
|
||||||
else:
|
else:
|
||||||
eigen_root = self.env['buildroot_staging_dir']
|
eigen_root = self.env['buildroot_staging_dir']
|
||||||
pkgs = {
|
packages = {
|
||||||
'eigen': {
|
'eigen': {
|
||||||
# TODO: was failing with:
|
# TODO: was failing with:
|
||||||
# fatal error: Eigen/Dense: No such file or directory as of
|
# fatal error: Eigen/Dense: No such file or directory as of
|
||||||
@@ -187,8 +158,6 @@ Default: build all examples that have their package dependencies met, e.g.:
|
|||||||
# Header only.
|
# Header only.
|
||||||
'cc_flags_after': [],
|
'cc_flags_after': [],
|
||||||
},
|
},
|
||||||
'libdrm': {},
|
|
||||||
'openblas': {},
|
|
||||||
}
|
}
|
||||||
rootdir_abs_len = len(self.env['userland_source_dir'])
|
rootdir_abs_len = len(self.env['userland_source_dir'])
|
||||||
with ThreadPool(
|
with ThreadPool(
|
||||||
@@ -206,42 +175,10 @@ Default: build all examples that have their package dependencies met, e.g.:
|
|||||||
build_dir,
|
build_dir,
|
||||||
dirpath_relative_root
|
dirpath_relative_root
|
||||||
)
|
)
|
||||||
common_objs_dir = []
|
|
||||||
cc_flags_after = []
|
|
||||||
cc_flags_dir = cc_flags.copy()
|
|
||||||
if dirpath_relative_root_components_len > 0:
|
|
||||||
if dirpath_relative_root_components[0] == 'arch':
|
|
||||||
cc_flags_dir.extend([
|
|
||||||
'-I', os.path.join(self.env['userland_source_arch_arch_dir']), LF,
|
|
||||||
'-I', os.path.join(self.env['userland_source_arch_dir']), LF,
|
|
||||||
])
|
|
||||||
elif dirpath_relative_root_components[0] == 'libs':
|
|
||||||
if dirpath_relative_root_components_len > 1:
|
|
||||||
pkg_key = dirpath_relative_root_components[1]
|
|
||||||
if not (has_all_packages or pkg_key in has_packages):
|
|
||||||
continue
|
|
||||||
pkg = pkgs[pkg_key]
|
|
||||||
if 'cc_flags' in pkg:
|
|
||||||
cc_flags_dir.extend(pkg['cc_flags'])
|
|
||||||
else:
|
|
||||||
pkg_config_output = subprocess.check_output([
|
|
||||||
self.env['pkg_config'],
|
|
||||||
'--cflags',
|
|
||||||
pkg_key
|
|
||||||
]).decode()
|
|
||||||
cc_flags_dir.extend(self.sh.shlex_split(pkg_config_output))
|
|
||||||
if 'cc_flags_after' in pkg:
|
|
||||||
cc_flags_dir.extend(pkg['cc_flags_after'])
|
|
||||||
else:
|
|
||||||
pkg_config_output = subprocess.check_output([
|
|
||||||
self.env['pkg_config'],
|
|
||||||
'--libs',
|
|
||||||
pkg_key
|
|
||||||
]).decode()
|
|
||||||
cc_flags_after.extend(self.sh.shlex_split(pkg_config_output))
|
|
||||||
for in_filename in in_filenames:
|
for in_filename in in_filenames:
|
||||||
in_path = os.path.join(path, in_filename)
|
in_path = os.path.join(path, in_filename)
|
||||||
cc_flags_file = cc_flags_dir.copy()
|
cc_flags_file = cc_flags.copy()
|
||||||
|
cc_flags_after = []
|
||||||
in_ext = os.path.splitext(in_filename)[1]
|
in_ext = os.path.splitext(in_filename)[1]
|
||||||
if not in_ext in self.env['userland_in_exts']:
|
if not in_ext in self.env['userland_in_exts']:
|
||||||
continue
|
continue
|
||||||
@@ -250,10 +187,41 @@ Default: build all examples that have their package dependencies met, e.g.:
|
|||||||
dirpath_relative_root,
|
dirpath_relative_root,
|
||||||
in_filename
|
in_filename
|
||||||
))
|
))
|
||||||
if my_path_properties.should_be_built(self.env['arch']):
|
if my_path_properties.should_be_built(self.env):
|
||||||
if my_path_properties['pedantic']:
|
if dirpath_relative_root_components_len > 0:
|
||||||
|
if dirpath_relative_root_components[0] == 'arch':
|
||||||
|
cc_flags_file.extend([
|
||||||
|
'-I', os.path.join(self.env['userland_source_arch_arch_dir']), LF,
|
||||||
|
'-I', os.path.join(self.env['userland_source_arch_dir']), LF,
|
||||||
|
])
|
||||||
|
elif dirpath_relative_root_components[0] == 'libs':
|
||||||
|
if dirpath_relative_root_components_len > 1:
|
||||||
|
package_key = dirpath_relative_root_components[1]
|
||||||
|
if package_key in packages:
|
||||||
|
package = packages[package_key]
|
||||||
|
else:
|
||||||
|
package = {}
|
||||||
|
if 'cc_flags' in package:
|
||||||
|
cc_flags_file.extend(package['cc_flags'])
|
||||||
|
else:
|
||||||
|
pkg_config_output = subprocess.check_output([
|
||||||
|
self.env['pkg_config'],
|
||||||
|
'--cflags',
|
||||||
|
package_key
|
||||||
|
]).decode()
|
||||||
|
cc_flags_file.extend(self.sh.shlex_split(pkg_config_output))
|
||||||
|
if 'cc_flags_after' in package:
|
||||||
|
cc_flags_file.extend(package['cc_flags_after'])
|
||||||
|
else:
|
||||||
|
pkg_config_output = subprocess.check_output([
|
||||||
|
self.env['pkg_config'],
|
||||||
|
'--libs',
|
||||||
|
package_key
|
||||||
|
]).decode()
|
||||||
|
cc_flags_after.extend(self.sh.shlex_split(pkg_config_output))
|
||||||
|
if my_path_properties['cc_pedantic']:
|
||||||
cc_flags_file.extend(['-pedantic', LF])
|
cc_flags_file.extend(['-pedantic', LF])
|
||||||
common_objs_file = common_objs_dir.copy()
|
common_objs_file = []
|
||||||
if my_path_properties['extra_objs_lkmc_common']:
|
if my_path_properties['extra_objs_lkmc_common']:
|
||||||
common_objs_file.append(common_obj)
|
common_objs_file.append(common_obj)
|
||||||
if my_path_properties['extra_objs_userland_asm']:
|
if my_path_properties['extra_objs_userland_asm']:
|
||||||
@@ -261,7 +229,7 @@ Default: build all examples that have their package dependencies met, e.g.:
|
|||||||
error = thread_pool.submit({
|
error = thread_pool.submit({
|
||||||
'c_std': my_path_properties['c_std'],
|
'c_std': my_path_properties['c_std'],
|
||||||
'cc_flags': cc_flags_file + my_path_properties['cc_flags'],
|
'cc_flags': cc_flags_file + my_path_properties['cc_flags'],
|
||||||
'cc_flags_after': cc_flags_after,
|
'cc_flags_after': cc_flags_after + my_path_properties['cc_flags_after'],
|
||||||
'cxx_std': my_path_properties['cxx_std'],
|
'cxx_std': my_path_properties['cxx_std'],
|
||||||
'extra_objs': common_objs_file,
|
'extra_objs': common_objs_file,
|
||||||
'in_path': in_path,
|
'in_path': in_path,
|
||||||
|
|||||||
17
common.py
17
common.py
@@ -436,6 +436,22 @@ Machine type:
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Userland.
|
# Userland.
|
||||||
|
self.add_argument(
|
||||||
|
'--package',
|
||||||
|
action='append',
|
||||||
|
help='''\
|
||||||
|
Request to install a package in the target root filesystem, or indicate that it is present
|
||||||
|
when building examples that rely on it or running tests for those examples.
|
||||||
|
''',
|
||||||
|
)
|
||||||
|
self.add_argument(
|
||||||
|
'--package-all',
|
||||||
|
action='store_true',
|
||||||
|
help='''\
|
||||||
|
Indicate that all packages used by our userland/ examples with --package
|
||||||
|
are available.
|
||||||
|
''',
|
||||||
|
)
|
||||||
self.add_argument(
|
self.add_argument(
|
||||||
'--static',
|
'--static',
|
||||||
default=False,
|
default=False,
|
||||||
@@ -772,6 +788,7 @@ Incompatible archs are skipped.
|
|||||||
env['userland_build_dir'] = self.env['userland_source_dir']
|
env['userland_build_dir'] = self.env['userland_source_dir']
|
||||||
else:
|
else:
|
||||||
env['userland_build_dir'] = join(env['out_dir'], 'userland', env['userland_build_id'], env['arch'])
|
env['userland_build_dir'] = join(env['out_dir'], 'userland', env['userland_build_id'], env['arch'])
|
||||||
|
env['package'] = set(env['package'])
|
||||||
|
|
||||||
# Kernel modules.
|
# Kernel modules.
|
||||||
env['kernel_modules_build_dir'] = join(env['kernel_modules_build_base_dir'], env['arch'])
|
env['kernel_modules_build_dir'] = join(env['kernel_modules_build_base_dir'], env['arch'])
|
||||||
|
|||||||
15
lkmc.c
15
lkmc.c
@@ -11,24 +11,11 @@ void lkmc_assert(bool condition) {
|
|||||||
lkmc_assert_fail();
|
lkmc_assert_fail();
|
||||||
}
|
}
|
||||||
|
|
||||||
void lkmc_assert_fail() {
|
void lkmc_assert_fail(void) {
|
||||||
puts("lkmc_test_fail");
|
puts("lkmc_test_fail");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool lkmc_vector_equal(size_t n, double *v1, double *v2, double max_err) {
|
|
||||||
double sum = 0.0;
|
|
||||||
double diff;
|
|
||||||
size_t i;
|
|
||||||
for (i = 0; i < n; ++i) {
|
|
||||||
diff = v1[i] - v2[i];
|
|
||||||
sum += diff * diff;
|
|
||||||
}
|
|
||||||
if (sqrt(sum)/n > max_err)
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(__aarch64__)
|
#if defined(__aarch64__)
|
||||||
#define LKMC_SYSREG_READ_WRITE(type, name) \
|
#define LKMC_SYSREG_READ_WRITE(type, name) \
|
||||||
type LKMC_CONCAT(LKMC_CONCAT(LKMC_SYSREG_SYMBOL_PREFIX, name), _read(void)) { \
|
type LKMC_CONCAT(LKMC_CONCAT(LKMC_SYSREG_SYMBOL_PREFIX, name), _read(void)) { \
|
||||||
|
|||||||
1
lkmc.h
1
lkmc.h
@@ -11,7 +11,6 @@
|
|||||||
|
|
||||||
void lkmc_assert(bool);
|
void lkmc_assert(bool);
|
||||||
void lkmc_assert_fail();
|
void lkmc_assert_fail();
|
||||||
bool lkmc_vector_equal(size_t n, double *v1, double *v2, double max_err);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* https://stackoverflow.com/questions/1489932/how-to-concatenate-twice-with-the-c-preprocessor-and-expand-a-macro-as-in-arg */
|
/* https://stackoverflow.com/questions/1489932/how-to-concatenate-twice-with-the-c-preprocessor-and-expand-a-macro-as-in-arg */
|
||||||
|
|||||||
20
lkmc/math.h
Normal file
20
lkmc/math.h
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#ifndef LKMC_MATH_H
|
||||||
|
#define LKMC_MATH_H
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
bool lkmc_vector_equal(size_t n, double *v1, double *v2, double max_err) {
|
||||||
|
double sum = 0.0;
|
||||||
|
double diff;
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < n; ++i) {
|
||||||
|
diff = v1[i] - v2[i];
|
||||||
|
sum += diff * diff;
|
||||||
|
}
|
||||||
|
if (sqrt(sum)/n > max_err)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -5,6 +5,33 @@ import os
|
|||||||
from shell_helpers import LF
|
from shell_helpers import LF
|
||||||
|
|
||||||
class PathProperties:
|
class PathProperties:
|
||||||
|
property_keys = {
|
||||||
|
'allowed_archs',
|
||||||
|
'c_std',
|
||||||
|
'cc_flags',
|
||||||
|
'cc_flags_after',
|
||||||
|
'cc_pedantic',
|
||||||
|
'cxx_std',
|
||||||
|
'exit_status',
|
||||||
|
'interactive',
|
||||||
|
# We should get rid of this if we ever properly implement dependency graphs.
|
||||||
|
'extra_objs_lkmc_common',
|
||||||
|
'extra_objs_userland_asm',
|
||||||
|
# We were lazy to properly classify why we are skipping these tests.
|
||||||
|
# TODO get it done.
|
||||||
|
'skip_run_unclassified',
|
||||||
|
'more_than_1s',
|
||||||
|
# The path does not generate an executable in itself, e.g.
|
||||||
|
# it only generates intermediate object files.
|
||||||
|
'no_executable',
|
||||||
|
# the test receives a signal. We skip those tests for now,
|
||||||
|
# on userland because we are lazy to figure out the exact semantics
|
||||||
|
# of how Python + QEMU + gem5 determine the exit status of signals.
|
||||||
|
'receives_signal',
|
||||||
|
'requires_kernel_modules',
|
||||||
|
'uses_dynamic_library',
|
||||||
|
}
|
||||||
|
|
||||||
'''
|
'''
|
||||||
Encodes properties of userland and baremetal paths.
|
Encodes properties of userland and baremetal paths.
|
||||||
For directories, it applies to all files under the directory.
|
For directories, it applies to all files under the directory.
|
||||||
@@ -12,37 +39,12 @@ class PathProperties:
|
|||||||
'''
|
'''
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
**kwargs
|
properties
|
||||||
):
|
):
|
||||||
property_keys = {
|
for key in properties:
|
||||||
'allowed_archs',
|
if not key in self.property_keys:
|
||||||
'c_std',
|
|
||||||
'cc_flags',
|
|
||||||
'cc_pedantic',
|
|
||||||
'cxx_std',
|
|
||||||
'exit_status',
|
|
||||||
'interactive',
|
|
||||||
# We should get rid of this if we ever properly implement dependency graphs.
|
|
||||||
'extra_objs_lkmc_common',
|
|
||||||
'extra_objs_userland_asm',
|
|
||||||
# We were lazy to properly classify why we are skipping these tests.
|
|
||||||
# TODO get it done.
|
|
||||||
'skip_run_unclassified',
|
|
||||||
'more_than_1s',
|
|
||||||
# The path does not generate an executable in itself, e.g.
|
|
||||||
# it only generates intermediate object files.
|
|
||||||
'no_executable',
|
|
||||||
'pedantic',
|
|
||||||
# the test receives a signal. We skip those tests for now,
|
|
||||||
# on userland because we are lazy to figure out the exact semantics
|
|
||||||
# of how Python + QEMU + gem5 determine the exit status of signals.
|
|
||||||
'receives_signal',
|
|
||||||
'requires_kernel_modules',
|
|
||||||
}
|
|
||||||
for key in kwargs:
|
|
||||||
if not key in property_keys:
|
|
||||||
raise ValueError('Unknown key: {}'.format(key))
|
raise ValueError('Unknown key: {}'.format(key))
|
||||||
self.properties = kwargs
|
self.properties = properties.copy()
|
||||||
|
|
||||||
def __getitem__(self, key):
|
def __getitem__(self, key):
|
||||||
return self.properties[key]
|
return self.properties[key]
|
||||||
@@ -50,29 +52,38 @@ class PathProperties:
|
|||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return str(self.properties)
|
return str(self.properties)
|
||||||
|
|
||||||
|
def set_path_components(self, path_components):
|
||||||
|
self.path_components = path_components
|
||||||
|
|
||||||
|
def should_be_built(self, env):
|
||||||
|
if len(self.path_components) > 1 and \
|
||||||
|
self.path_components[1] == 'libs' and \
|
||||||
|
not env['package_all'] and \
|
||||||
|
not self.path_components[2] in env['package']:
|
||||||
|
return False
|
||||||
|
return \
|
||||||
|
not self['no_executable'] and \
|
||||||
|
(
|
||||||
|
self['allowed_archs'] is None or
|
||||||
|
env['arch'] in self['allowed_archs']
|
||||||
|
)
|
||||||
|
|
||||||
|
def should_be_tested(self, env):
|
||||||
|
return \
|
||||||
|
self.should_be_built(env) and \
|
||||||
|
not self['interactive'] and \
|
||||||
|
not self['more_than_1s'] and \
|
||||||
|
not self['receives_signal'] and \
|
||||||
|
not self['requires_kernel_modules'] and \
|
||||||
|
not self['skip_run_unclassified'] and \
|
||||||
|
not (self['uses_dynamic_library'] and env['emulator'] == 'gem5')
|
||||||
|
|
||||||
def update(self, other):
|
def update(self, other):
|
||||||
other_tmp_properties = other.properties.copy()
|
other_tmp_properties = other.properties.copy()
|
||||||
if 'cc_flags' in self.properties and 'cc_flags' in other_tmp_properties:
|
if 'cc_flags' in self.properties and 'cc_flags' in other_tmp_properties:
|
||||||
other_tmp_properties['cc_flags'] = self.properties['cc_flags'] + other_tmp_properties['cc_flags']
|
other_tmp_properties['cc_flags'] = self.properties['cc_flags'] + other_tmp_properties['cc_flags']
|
||||||
return self.properties.update(other_tmp_properties)
|
return self.properties.update(other_tmp_properties)
|
||||||
|
|
||||||
def should_be_built(self, arch):
|
|
||||||
return \
|
|
||||||
not self['no_executable'] and \
|
|
||||||
(
|
|
||||||
self['allowed_archs'] is None or
|
|
||||||
arch in self['allowed_archs']
|
|
||||||
)
|
|
||||||
|
|
||||||
def should_be_tested(self, arch):
|
|
||||||
return \
|
|
||||||
self.should_be_built(arch) and \
|
|
||||||
not self['interactive'] and \
|
|
||||||
not self['more_than_1s'] and \
|
|
||||||
not self['receives_signal'] and \
|
|
||||||
not self['requires_kernel_modules'] and \
|
|
||||||
not self['skip_run_unclassified']
|
|
||||||
|
|
||||||
class PrefixTree:
|
class PrefixTree:
|
||||||
def __init__(self, path_properties_dict=None, children=None):
|
def __init__(self, path_properties_dict=None, children=None):
|
||||||
if path_properties_dict is None:
|
if path_properties_dict is None:
|
||||||
@@ -80,7 +91,7 @@ class PrefixTree:
|
|||||||
if children is None:
|
if children is None:
|
||||||
children = {}
|
children = {}
|
||||||
self.children = children
|
self.children = children
|
||||||
self.path_properties = PathProperties(**path_properties_dict)
|
self.path_properties = PathProperties(path_properties_dict)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def make_from_tuples(tuples):
|
def make_from_tuples(tuples):
|
||||||
@@ -100,15 +111,17 @@ class PrefixTree:
|
|||||||
todo_trees.append(new_tree)
|
todo_trees.append(new_tree)
|
||||||
return top_tree
|
return top_tree
|
||||||
|
|
||||||
def get(test_path):
|
def get(path):
|
||||||
cur_node = path_properties_tree
|
cur_node = path_properties_tree
|
||||||
path_properties = PathProperties(**cur_node.path_properties.properties)
|
path_components = path.split(os.sep)
|
||||||
for path_component in test_path.split(os.sep):
|
path_properties = PathProperties(cur_node.path_properties.properties.copy())
|
||||||
|
for path_component in path_components:
|
||||||
if path_component in cur_node.children:
|
if path_component in cur_node.children:
|
||||||
cur_node = cur_node.children[path_component]
|
cur_node = cur_node.children[path_component]
|
||||||
path_properties.update(cur_node.path_properties)
|
path_properties.update(cur_node.path_properties)
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
|
path_properties.set_path_components(path_components)
|
||||||
return path_properties
|
return path_properties
|
||||||
|
|
||||||
default_c_std = 'c11'
|
default_c_std = 'c11'
|
||||||
@@ -128,24 +141,32 @@ freestanding_properties = {
|
|||||||
}
|
}
|
||||||
path_properties_tuples = (
|
path_properties_tuples = (
|
||||||
{
|
{
|
||||||
'c_std': default_c_std,
|
|
||||||
'cxx_std': default_cxx_std,
|
|
||||||
'pedantic': True,
|
|
||||||
'allowed_archs': None,
|
'allowed_archs': None,
|
||||||
'c_std': None,
|
'c_std': default_c_std,
|
||||||
'cc_flags': [],
|
'cc_flags': [
|
||||||
|
'-Wall', LF,
|
||||||
|
'-Werror', LF,
|
||||||
|
'-Wextra', LF,
|
||||||
|
'-Wno-unused-function', LF,
|
||||||
|
'-fopenmp', LF,
|
||||||
|
'-ggdb3', LF,
|
||||||
|
],
|
||||||
|
'cc_flags_after': [
|
||||||
|
'-lm', LF,
|
||||||
|
'-pthread', LF,
|
||||||
|
],
|
||||||
'cc_pedantic': True,
|
'cc_pedantic': True,
|
||||||
'cxx_std': None,
|
'cxx_std': default_cxx_std,
|
||||||
'exit_status': 0,
|
'exit_status': 0,
|
||||||
'extra_objs_lkmc_common': False,
|
'extra_objs_lkmc_common': False,
|
||||||
'extra_objs_userland_asm': False,
|
'extra_objs_userland_asm': False,
|
||||||
'interactive': False,
|
'interactive': False,
|
||||||
'skip_run_unclassified': False,
|
|
||||||
'more_than_1s': False,
|
'more_than_1s': False,
|
||||||
'no_executable': False,
|
'no_executable': False,
|
||||||
'pedantic': False,
|
|
||||||
'receives_signal': False,
|
'receives_signal': False,
|
||||||
'requires_kernel_modules': False,
|
'requires_kernel_modules': False,
|
||||||
|
'skip_run_unclassified': False,
|
||||||
|
'uses_dynamic_library': False,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'userland': (
|
'userland': (
|
||||||
@@ -240,10 +261,10 @@ path_properties_tuples = (
|
|||||||
'lkmc': (
|
'lkmc': (
|
||||||
{'extra_objs_lkmc_common': True},
|
{'extra_objs_lkmc_common': True},
|
||||||
{
|
{
|
||||||
'assert_fail.c': {'exit_status': 1}
|
'assert_fail.c': {'exit_status': 1},
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
'libs': {'skip_run_unclassified': True},
|
'libs': {'uses_dynamic_library': True},
|
||||||
'linux': {**gnu_extension_properties, **{'skip_run_unclassified': True}},
|
'linux': {**gnu_extension_properties, **{'skip_run_unclassified': True}},
|
||||||
'posix': (
|
'posix': (
|
||||||
{},
|
{},
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ If given, run only the given tests. Otherwise, run all tests.
|
|||||||
if os.path.splitext(in_filename)[1] in self.env['userland_in_exts']:
|
if os.path.splitext(in_filename)[1] in self.env['userland_in_exts']:
|
||||||
path_relative_root = os.path.join(dirpath_relative_root, in_filename)
|
path_relative_root = os.path.join(dirpath_relative_root, in_filename)
|
||||||
my_path_properties = path_properties.get(path_relative_root)
|
my_path_properties = path_properties.get(path_relative_root)
|
||||||
if my_path_properties.should_be_tested(self.env['arch']):
|
if my_path_properties.should_be_tested(self.env):
|
||||||
cur_run_args = run_args.copy()
|
cur_run_args = run_args.copy()
|
||||||
cur_run_args.update({
|
cur_run_args.update({
|
||||||
'background': True,
|
'background': True,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* https://github.com/cirosantilli/linux-kernel-module-cheat#bst-vs-heap */
|
// https://github.com/cirosantilli/linux-kernel-module-cheat#bst-vs-heap
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* https://github.com/cirosantilli/linux-kernel-module-cheat#sanity-checks */
|
// https://github.com/cirosantilli/linux-kernel-module-cheat#sanity-checks
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
/* https://github.com/cirosantilli/linux-kernel-module-cheat#eigen
|
// https://github.com/cirosantilli/linux-kernel-module-cheat#eigen
|
||||||
* Adapted from: https://eigen.tuxfamily.org/dox/GettingStarted.html
|
// Adapted from: https://eigen.tuxfamily.org/dox/GettingStarted.html
|
||||||
*/
|
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <cblas.h>
|
#include <cblas.h>
|
||||||
|
|
||||||
#include <lkmc.h>
|
#include <lkmc/math.h>
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
double A[6] = {
|
double A[6] = {
|
||||||
|
|||||||
Reference in New Issue
Block a user