Working infrastructure for xCore200

This commit is contained in:
mbanth
2021-05-20 15:29:25 +01:00
parent 7836aacf47
commit ede81bd5f7
3 changed files with 178 additions and 75 deletions

View File

@@ -1,11 +1,14 @@
# Copyright 2021 XMOS LIMITED. # Copyright 2021 XMOS LIMITED.
# This Software is subject to the terms of the XMOS Public Licence: Version 1. # This Software is subject to the terms of the XMOS Public Licence: Version 1.
from __future__ import print_function
from builtins import str
import os.path import os.path
import pytest import pytest
import subprocess import subprocess
target = os.environ.get('TARGET', 'all_possible') target = os.environ.get('TARGET', 'all_possible')
print("target = ", target) print("target = ", target)
def pytest_collect_file(parent, path): def pytest_collect_file(parent, path):
if(path.ext == ".xe"): if(path.ext == ".xe"):
if(target == 'all_possible'): if(target == 'all_possible'):
@@ -27,24 +30,9 @@ class UnityTestSource(pytest.File):
# |-- runners/ <- Auto-generated buildable source of test binaries # |-- runners/ <- Auto-generated buildable source of test binaries
# |-- src/ <- Unity test functions # |-- src/ <- Unity test functions
# `-- wscript <- Build system file used to generate/build runners # `-- wscript <- Build system file used to generate/build runners
print("self.name = ",self.name) xe_name = ((os.path.basename(self.name)).split("."))[0] + ".xe"
#xe_name = ((os.path.basename(self.name)).split("."))[0] + ".xe" test_bin_path = os.path.join('bin', xe_name)
#test_bin_path = os.path.join('bin', xe_name)
#
#test_root_dir_name = os.path.basename(os.path.dirname(__file__))
#test_src_path = os.path.basename(str(self.fspath))
#test_src_name = os.path.splitext(test_src_path)[0]
#test_bin_name_si = os.path.join(
# test_src_name + '_single_issue.xe')
#test_bin_path_si = os.path.join('bin',
# test_bin_name_si)
#yield UnityTestExecutable.from_parent(self, name=test_bin_path_si)
#test_bin_name_di = os.path.join(
# test_src_name + '_dual_issue.xe')
#test_bin_path_di = os.path.join('bin',
# test_bin_name_di)
yield UnityTestExecutable.from_parent(self, name=self.name) yield UnityTestExecutable.from_parent(self, name=self.name)
@@ -83,7 +71,7 @@ class UnityTestExecutable(pytest.Item):
test_case = test_report[2] test_case = test_report[2]
result = test_report[3] result = test_report[3]
failure_reason = None failure_reason = None
print('\n {}()'.format(test_case)), print(('\n {}()'.format(test_case)), end=' ')
if result == 'PASS': if result == 'PASS':
unity_pass = True unity_pass = True
continue continue

View File

@@ -0,0 +1,120 @@
# Copyright 2021 XMOS LIMITED.
# This Software is subject to the terms of the XMOS Public Licence: Version 1.
import glob
import os.path
import subprocess
import sys
UNITY_TEST_DIR = 'src'
UNITY_TEST_PREFIX = 'test_'
UNITY_RUNNER_DIR = 'runners'
UNITY_RUNNER_SUFFIX = '_Runner'
project_root = os.path.join('..', '..', '..')
def get_ruby():
"""
Check ruby is avaliable and return the command to invoke it.
"""
interpreter_name = 'ruby'
try:
dev_null = open(os.devnull, 'w')
# Call the version command to check the interpreter can be run
subprocess.check_call([interpreter_name, '--version'],
stdout=dev_null,
close_fds=True)
except OSError as e:
print("Failed to run Ruby interpreter: {}".format(e), file=sys.stderr)
exit(1) # TODO: Check this is the correct way to kill xwaf on error
return interpreter_name
def get_unity_runner_generator(project_root_path):
"""
Check the Unity generate_test_runner script is avaliable, and return the
path to it.
"""
unity_runner_generator = os.path.join(
project_root_path, 'Unity', 'auto', 'generate_test_runner.rb')
if not os.path.exists(unity_runner_generator):
print("Unity repo not found in workspace", file=sys.stderr)
exit(1) # TODO: Check this is the correct way to kill xwaf on error
return unity_runner_generator
def get_test_name(test_path):
"""
Return the test name by removing the extension from the filename.
"""
return os.path.splitext(os.path.basename(test_path))[0]
def get_file_type(filename):
"""
Return the extension from the filename.
"""
return filename.rsplit('.')[-1:][0]
def generate_unity_runner(project_root_path, unity_test_path, unity_runner_dir,
unity_runner_suffix):
"""
Invoke the Unity runner generation script for the given test file, and
return the path to the generated file. The output directory will be created
if it does not already exist.
"""
runner_path = os.path.join(os.path.join(unity_runner_dir, get_test_name(unity_test_path)))
if not os.path.exists(runner_path):
os.makedirs(runner_path)
unity_runner_path = os.path.join(
runner_path, get_test_name(unity_test_path) + unity_runner_suffix
+ '.' + 'c')
try:
subprocess.check_call([get_ruby(),
get_unity_runner_generator(project_root_path),
unity_test_path,
unity_runner_path])
except OSError as e:
print("Ruby generator failed for {}\n\t{}".format(unity_test_path, e),
file=sys.stderr)
exit(1) # TODO: Check this is the correct way to kill xwaf on error
def find_unity_test_paths(unity_test_dir, unity_test_prefix):
"""
Return a list of all file paths with the unity_test_prefix found in the
unity_test_dir.
"""
return glob.glob(os.path.join(unity_test_dir, unity_test_prefix+'*'))
def find_unity_tests(unity_test_dir, unity_test_prefix):
"""
Return a dictionary of all {test names, test language} pairs with the
unity_test_prefix found in the unity_test_dir.
"""
unity_test_paths = find_unity_test_paths(unity_test_dir, unity_test_prefix)
print('unity_test_paths = ', unity_test_paths)
return {get_test_name(path): get_file_type(path)
for path in unity_test_paths}
def find_unity_test_paths(unity_test_dir, unity_test_prefix):
"""
Return a list of all file paths with the unity_test_prefix found in the
unity_test_dir.
"""
return glob.glob(os.path.join(unity_test_dir, unity_test_prefix+'*'))
def generate_runners():
UNITY_TESTS = find_unity_tests(UNITY_TEST_DIR, UNITY_TEST_PREFIX)
print('UNITY_TESTS = ',UNITY_TESTS)
unity_test_paths = find_unity_test_paths(UNITY_TEST_DIR, UNITY_TEST_PREFIX)
print('unity_test_paths = ',unity_test_paths)
for unity_test_path in unity_test_paths:
generate_unity_runner(project_root, unity_test_path, UNITY_RUNNER_DIR, UNITY_RUNNER_SUFFIX)
if __name__ == "__main__":
generate_runners()

View File

@@ -3,11 +3,10 @@ import glob
import os.path import os.path
import subprocess import subprocess
import sys import sys
from waflib import Options, Errors from waflib import Options
from waflib.Build import BuildContext, CleanContext from waflib.Build import BuildContext, CleanContext
#TARGETS = ['xcore200', 'xcoreai'] TARGETS = ['xcore200', 'xcoreai']
TARGETS = ['xcore200'] # Target xcore200 only for the time being
def get_ruby(): def get_ruby():
""" """
@@ -68,6 +67,7 @@ def generate_unity_runner(project_root_path, unity_test_path, unity_runner_dir,
unity_runner_path = os.path.join( unity_runner_path = os.path.join(
runner_path, get_test_name(unity_test_path) + unity_runner_suffix runner_path, get_test_name(unity_test_path) + unity_runner_suffix
+ '.' + 'c') + '.' + 'c')
try: try:
subprocess.check_call([get_ruby(), subprocess.check_call([get_ruby(),
get_unity_runner_generator(project_root_path), get_unity_runner_generator(project_root_path),
@@ -79,51 +79,36 @@ def generate_unity_runner(project_root_path, unity_test_path, unity_runner_dir,
exit(1) # TODO: Check this is the correct way to kill xwaf on error exit(1) # TODO: Check this is the correct way to kill xwaf on error
def set_common_build_config(waf_conf, project_root_path, unity_test_path, def add_unity_runner_build_config(waf_conf, project_root_path, unity_test_path,
unity_runner_build_flags): unity_runner_build_flags, target):
""" """
Set the common xwaf config variables. Add a config to xwaf to build each Unity test runner into an xCORE
executable.
""" """
print(f"get_test_name(unity_test_path) = {get_test_name(unity_test_path)}. target = {target}")
waf_conf.setenv(get_test_name(unity_test_path) + '_' + target)
waf_conf.load('xwaf.compiler_xcc') waf_conf.load('xwaf.compiler_xcc')
waf_conf.env.XCC_FLAGS = unity_runner_build_flags waf_conf.env.XCC_FLAGS = unity_runner_build_flags
waf_conf.env.PROJECT_ROOT = project_root_path waf_conf.env.PROJECT_ROOT = project_root_path
# TODO: can the xwaf boilerplate help here? # TODO: can the xwaf boilerplate help here?
def add_single_issue_unity_runner_build_config(waf_conf, project_root_path,
unity_test_path,
unity_runner_build_flags, target):
"""
Add a single issue config to xwaf to build each Unity test runner into an
xCORE executable.
"""
waf_conf.setenv(get_test_name(unity_test_path) + '_single_issue' + '_' + target)
set_common_build_config(waf_conf, project_root_path, unity_test_path,
unity_runner_build_flags + '-mno-dual-issue')
def prepare_unity_test_for_build(waf_conf, project_root_path, unity_test_path, def prepare_unity_test_for_build(waf_conf, project_root_path, unity_test_path,
unity_runner_dir, unity_runner_suffix, target): unity_runner_dir, unity_runner_suffix, target):
generate_unity_runner(project_root_path, unity_test_path, generate_unity_runner(project_root_path, unity_test_path,
unity_runner_dir, unity_runner_suffix) unity_runner_dir, unity_runner_suffix)
runner_build_flags = '' # Could extract flags from the test name runner_build_flags = '' # Could extract flags from the test name
add_single_issue_unity_runner_build_config(waf_conf, project_root_path, add_unity_runner_build_config(waf_conf, project_root_path, unity_test_path,
unity_test_path,
runner_build_flags, target) runner_build_flags, target)
def find_unity_test_paths(unity_test_dir, unity_test_prefix): def find_unity_test_paths(unity_test_dir, unity_test_prefix):
""" """
Return a list of all file paths with the unity_test_prefix found in the Return a list of all file paths with the unity_test_prefix found in the
unity_test_dir. unity_test_dir.
""" """
file_list = [] return glob.glob(os.path.join(unity_test_dir, unity_test_prefix+'*'))
for root, dirs, files in os.walk(unity_test_dir):
for f in files:
if f.startswith(unity_test_prefix):
file_list.append(os.path.join(root,f))
return file_list
def find_unity_tests(unity_test_dir, unity_test_prefix): def find_unity_tests(unity_test_dir, unity_test_prefix):
""" """
@@ -155,17 +140,19 @@ def generate_all_unity_runners(waf_conf, project_root_path,
def create_waf_contexts(configs): def create_waf_contexts(configs):
for trgt in TARGETS: for trgt in TARGETS:
for test_name, test_language in configs.items(): for test_name, test_language in configs.items():
# Single issue test configurations print(f"test_name {test_name}, test_language {test_language}")
for ctx in (BuildContext, CleanContext): for ctx in (BuildContext, CleanContext):
raw_context = ctx.__name__.replace('Context', '').lower() raw_context = ctx.__name__.replace('Context', '').lower()
class si_tmp(ctx): class tmp(ctx):
cmd = raw_context + '_' + test_name + '_single_issue' + '_' + trgt cmd = raw_context + '_' + test_name + '_' + trgt
variant = test_name + '_single_issue' + '_' + trgt variant = test_name + '_' + trgt
source = test_name #cmd = raw_context + '_' + test_name
#variant = test_name
language = test_language language = test_language
target = trgt target = trgt
runner = test_name runner = test_name
print(f"cmd {cmd}, variant {variant}, language {language}")
UNITY_TEST_DIR = 'src' UNITY_TEST_DIR = 'src'
@@ -177,8 +164,8 @@ UNITY_TESTS = find_unity_tests(UNITY_TEST_DIR, UNITY_TEST_PREFIX)
create_waf_contexts(UNITY_TESTS) create_waf_contexts(UNITY_TESTS)
def options(opt): def options(opt):
opt.load('xwaf.xcommon')
opt.add_option('--target', action='store', default='xcore200') opt.add_option('--target', action='store', default='xcore200')
opt.load('xwaf.xcommon')
def configure(conf): def configure(conf):
# TODO: move the call to generate_all_unity_runners() to build() # TODO: move the call to generate_all_unity_runners() to build()
@@ -191,6 +178,7 @@ def configure(conf):
def build(bld): def build(bld):
if not bld.variant: if not bld.variant:
print('Adding test runners to build queue')
trgt = [ trgt = [
c for c in TARGETS if c == bld.options.target c for c in TARGETS if c == bld.options.target
] ]
@@ -198,34 +186,25 @@ def build(bld):
if len(trgt) == 0: if len(trgt) == 0:
bld.fatal('specify a target with --target.\nAvailable targets: {}'.format(', '.join(TARGETS))) bld.fatal('specify a target with --target.\nAvailable targets: {}'.format(', '.join(TARGETS)))
return return
print('Adding test runners to build queue')
for name in UNITY_TESTS: for name in UNITY_TESTS:
Options.commands.insert(0, 'build_' + name + '_single_issue' + '_' + trgt[0]) Options.commands.insert(0, 'build_' + name + '_' + trgt[0])
#Options.commands.insert(0, 'build_' + name)
print('Build queue {}'.format(Options.commands)) print('Build queue {}'.format(Options.commands))
else: else:
print('Building runner {}'.format(bld.runner)) print('Building runner {}'.format(bld.runner))
if(bld.target == 'xcoreai'):
bld.env.TARGET_ARCH = 'XCORE-AI-EXPLORER'
else:
bld.env.TARGET_ARCH = 'XCORE-200-EXPLORER'
bld.env.XSCOPE = bld.path.find_resource('config.xscope') bld.env.XSCOPE = bld.path.find_resource('config.xscope')
# The issue mode for each build is set during the configure step,
# as the string bld.env.XCC_FLAGS. We append this to the list last to
# ensure it takes precedence over other flags set here.
bld.env.XCC_FLAGS = ['-O2', '-g', '-Wall', '-DUNITY_SUPPORT_64',
'-DUNITY_INCLUDE_DOUBLE', bld.env.XCC_FLAGS]
depends_on = ['lib_xud', 'lib_xua', 'Unity'] depends_on = ['lib_xua',
include = ['.'] 'lib_xud',
source = [ 'lib_spdif',
os.path.join(UNITY_TEST_DIR, 'lib_mic_array',
'{}.{}'.format(bld.source, bld.language)), 'lib_logging',
os.path.join(UNITY_RUNNER_DIR, 'lib_xassert',
'{}{}.{}'.format(bld.source, UNITY_RUNNER_SUFFIX, 'Unity']
'c'))]
makefile_opts = {} makefile_opts = {}
makefile_opts['SOURCE_DIRS'] = [os.path.join('src',bld.runner), os.path.join('runners',bld.runner)] makefile_opts['SOURCE_DIRS'] = ['src', os.path.join('runners',bld.runner)]
if(bld.target == 'xcoreai'): if(bld.target == 'xcoreai'):
print('TARGET XCOREAI') print('TARGET XCOREAI')
makefile_opts['TARGET'] = ['XCORE-AI-EXPLORER'] makefile_opts['TARGET'] = ['XCORE-AI-EXPLORER']
@@ -233,13 +212,29 @@ def build(bld):
print('TARGET XCORE200') print('TARGET XCORE200')
makefile_opts['TARGET'] = ['XCORE-200-EXPLORER'] makefile_opts['TARGET'] = ['XCORE-200-EXPLORER']
makefile_opts['INCLUDE_DIRS'] = ['src'] makefile_opts['INCLUDE_DIRS'] = ['src',
makefile_opts['XCC_FLAGS'] = ['-O2', '-g', '-Wall', '-DUNITY_SUPPORT_64', '-DUNITY_INCLUDE_DOUBLE'] '../../lib_xua/src/core/pdm_mics',
'../../lib_xua/api',
'../../../lib_xud/lib_xud/src/user/class']
makefile_opts['XCC_FLAGS'] = ['-O2', '-g', '-Wall', '-DUNITY_SUPPORT_64', '-DUNITY_INCLUDE_DOUBLE', '-DXUD_CORE_CLOCK=600']
makefile_opts['APP_NAME'] = [bld.variant] makefile_opts['APP_NAME'] = [bld.variant]
makefile_opts['USED_MODULES'] = depends_on makefile_opts['USED_MODULES'] = depends_on
makefile_opts['XCOMMON_MAKEFILE'] = ['Makefile.common'] makefile_opts['XCOMMON_MAKEFILE'] = ['Makefile.common']
bld.do_xcommon(makefile_opts) bld.do_xcommon(makefile_opts)
def test(bld):
# Call pytest to run Unity tests inside axe or xsim
try:
test_output = subprocess.check_output(['pytest'])
except subprocess.CalledProcessError as e:
# pytest exits non-zero if an assertion fails
test_output = e.output
print(test_output)
# TODO: ensure clean deletes the runners dir/
def dist(ctx): def dist(ctx):
ctx.load('xwaf.xcommon') ctx.load('xwaf.xcommon')