| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340 |
- #!/bin/env python3
- import os
- import sys
- import traceback
- from itertools import combinations
- import random
- SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__))
- requirement_file = os.path.abspath(os.path.join(SCRIPT_DIR, "..", "requirements.txt"))
- try:
- import json
- import argparse
- import shutil
- import time
- import datetime
- except:
- print("Please install requried packages using: pip3 install -r %s" % (requirement_file))
- sys.exit(1)
- from nsdk_utils import *
- from nsdk_report import *
- from nsdk_runner import nsdk_runner
- FPGACIROOT = os.path.join(SCRIPT_DIR, "configs", "fpgaci")
- def valid_cpuarch(cpuarch):
- cpuarch = cpuarch.lower()
- if not cpuarch.startswith("rv64") and not cpuarch.startswith("rv32"):
- print("CPU arch should start with rv64 or rv32")
- return False
- # remove rv64/rv32
- arch = re.sub(r'rv\d\d', "", cpuarch)
- rst = re.search(r'[^imafdcbpvg]', arch)
- if rst:
- print("%s not valid arch" %(cpuarch))
- return False
- return True
- def gen_buildcfg(cpu, full_arch):
- buildcfg = dict()
- # if 'g'(imafd) exist
- rv_arch = re.sub(r'g', "imafd", full_arch)
- # remove rv64/rv32
- arch = re.sub(r'rv\d\d', "", rv_arch)
- arch_ext = re.sub(r'[imafdc]', "", arch)
- # core + f/p or fp
- core = cpu.replace('u', 'n') + re.sub(r'[imac%s]' %(arch_ext), "", arch)
- if "" == arch_ext:
- buildcfg = {full_arch:{"CORE": core}}
- else:
- buildcfg = {full_arch:{"CORE": core, "ARCH_EXT": arch_ext}}
- return buildcfg
- def gencfg_from_arch(cfgloc, core, cpuarch, maxnum):
- DEFAULT_VALID_MAX = 0
- # single, just itself
- ARCH_VALID = 1
- ARCH_AT_LEAST_VALID = 2
- arch_ext_comb = []
- arch_full = []
- cpucfgdict = dict()
- cpuarch = cpuarch.lower()
- # remove rv64/rv32
- arch = re.sub(r'rv\d\d', "", cpuarch)
- cpu_series = re.search(r'\d+', core).group()
- arch_prefix = re.match(r'rv\d\d', cpuarch).group()
- arch_base = ["imac"]
- if "f" in arch:
- arch_base.append('imafc')
- # if "d" exists, "f" exists
- if "d" in arch:
- arch_base.append('imafdc')
- # b/p/v
- arch_ext = re.sub(r'[imafdc]', "", arch)
- for i in range(1, len(arch_ext) + 1):
- for val in combinations(arch_ext, i):
- arch_ext_comb.append(''.join(val))
- # empty string on purpose to generate ones without ARCH_EXT
- arch_ext_comb.append("")
- arch_ext_comb.sort(key = lambda val:len(val), reverse = False)
- if maxnum >= ARCH_AT_LEAST_VALID and len(arch_ext_comb) > 1:
- arch_base = [arch_base[-1]]
- print("ARCH_AT_LEAST_VALID base : %s" %(arch_base))
- if maxnum >= ARCH_AT_LEAST_VALID:
- arch_ext_rest_cnt = 0
- if len(arch_ext_comb) > 2:
- arch_ext_rest_cnt = random.randint(0, len(arch_ext_comb) - 2)
- rand_rest_ext = random.sample(arch_ext_comb[1:-1], arch_ext_rest_cnt)
- # empty string ensures at least one element
- arch_ext_comb = [arch_ext_comb[0],arch_ext_comb[-1]]
- print("ARCH_AT_LEAST_VALID at least ext : %s, random rest ext : %s" %(arch_ext_comb, rand_rest_ext))
- arch_ext_comb.extend(rand_rest_ext)
- arch_ext_comb = list(set(arch_ext_comb))
- arch_base.sort(key = lambda val:len(val), reverse = False)
- arch_ext_comb.sort(key = lambda val:len(val), reverse = False)
- for idx_base, base in enumerate(arch_base):
- if ARCH_VALID == maxnum and idx_base != len(arch_base) - 1:
- print("Not ARCH_VALID base type, skip %s" %(base))
- continue
- for idx_ext, ext in enumerate(arch_ext_comb):
- if ARCH_VALID == maxnum and idx_ext != len(arch_ext_comb) - 1:
- print("Not ARCH_VALID ext type, skip %s" %(ext))
- continue
- if "imac" == base and 'v' in ext:
- print("v ext should not be with base imac, skip")
- continue
- arch_full.append(arch_prefix+base+ext)
- cpucfgdict["build_config"] = {"CPU_SERIES": cpu_series}
- cpucfgdict["build_configs"] = dict()
- for arch in arch_full:
- buildcfg = gen_buildcfg(core, arch)
- cpucfgdict["build_configs"].update(buildcfg)
- print("CPU config generated from arch = %s, mode = %s, number = %d: %s" %(cpuarch, maxnum, len(cpucfgdict["build_configs"]), cpucfgdict))
- cpucfg_name = core + "_" + cpuarch + ".json"
- cpucfg = os.path.join(cfgloc, cpucfg_name)
- save_json(cpucfg, cpucfgdict)
- return cpucfg
- # caseconfig is a dict
- # {
- # "core": "n300",
- # "locations": {
- # "fpgaloc": "",
- # "ncycmloc": "",
- # "cfgloc": ""
- # },
- # "ncycm": "xxxx",
- # "bitstream": "fpga.bit",
- # "fpga_serial": "xxxx",
- # "ftdi_serial": "xxxx",
- # "boardtype": "ddr200t",
- # "ocdcfg": "SoC/evalsoc/Board/nuclei_fpga_eval/openocd_evalsoc.cfg",
- # "cpucfg": "n300.json"
- # }
- def gen_runner_configs(casedir, caseconfig, genloc):
- if os.path.isdir(casedir) == False:
- return False
- if "core" not in caseconfig:
- print("No core is specified, please check!")
- return False
- # for ux1000_3w like, _3w should be stripped
- core = caseconfig["core"].split('_')[0]
- ocdcfg = caseconfig.get("ocdcfg", "SoC/evalsoc/Board/nuclei_fpga_eval/openocd_evalsoc.cfg")
- defbldcfg = dict()
- try:
- pathkeys = ocdcfg.replace("\\","/").split("/")
- defbldcfg = {"SOC": pathkeys[1], "BOARD": pathkeys[3]}
- except:
- defbldcfg = {"SOC": "evalsoc"}
- # get build_config from caseconfig
- glbldcfg = caseconfig.get("build_config", defbldcfg)
- runcfg = os.path.join(casedir, "%s.json" % (core))
- appcfg = os.path.join(casedir, "app.json")
- cfgcfg = os.path.join(casedir, "config.json")
- _, cfgconfig = load_json(cfgcfg)
- if cfgconfig is None:
- cfgconfig = {"choice": "mini"}
- choice = cfgconfig.get("choice", "mini")
- if os.path.isdir(genloc) == False:
- os.makedirs(genloc)
- cpuarch = caseconfig.get("cpuarch", "")
- # if specified user own cpu config use it
- if caseconfig.get("cpucfg", None):
- runcfgdict = gen_runcfg(caseconfig.get("cpucfg"), runcfg, glbldcfg)
- elif valid_cpuarch(cpuarch):
- # maxnum: 0, means generate default reasonable arch sets, max sets
- # 1, means generate cpuarch-same set
- # >1, means generate at least reasonable arch sets
- maxnum = int(caseconfig.get("archmaxnum", 1))
- cpucfgpath = gencfg_from_arch(genloc, core, cpuarch, maxnum)
- runcfgdict = gen_runcfg(cpucfgpath, runcfg, glbldcfg)
- else:
- # if not cpuarch or cpucfg file specified, then select cpu config via choice defined path
- runcfgdict = gen_coreruncfg(core, runcfg, choice, glbldcfg, casedir)
- caseconfig["gencfgtimestamp"] = str(datetime.datetime.now())
- # save casecfg.json/app.json/hw.json
- save_json(os.path.join(genloc, "casecfg.json"), caseconfig)
- save_json(os.path.join(genloc, "hw.json"), runcfgdict)
- shutil.copy(appcfg, os.path.join(genloc, "app.json"))
- locs = caseconfig.get("locations", dict())
- locs["cfgloc"] = "."
- fpga_serial = caseconfig.get("fpga_serial", INVAILD_SERNO)
- ftdi_serial = caseconfig.get("ftdi_serial", INVAILD_SERNO)
- cycm = caseconfig.get("ncycm", None)
- fpgabit = caseconfig.get("bitstream", "fpga.bit")
- if core in ["n200", "n300"]:
- boardtype = "ddr200t"
- elif core in ["n600", "ux600"]:
- boardtype = "ku060"
- else:
- boardtype = "vcu118"
- for btype in ["mcu200t", "ddr200t", "ku060", "vcu118"]:
- if btype in fpgabit:
- boardtype = btype
- break
- boardtype = caseconfig.get("boardtype", boardtype)
- appcfg = "app.json"
- hwcfg = "hw.json"
- # generate required runner yaml
- runyamldict = gen_runyaml(core, locs, fpga_serial, ftdi_serial, cycm, fpgabit, boardtype, ocdcfg, appcfg, hwcfg)
- save_yaml(os.path.join(genloc, "core.yaml"), runyamldict)
- return True
- if __name__ == '__main__':
- parser = argparse.ArgumentParser(description="Nuclei SDK CPU Runner")
- parser.add_argument('--cases', required=True, help="Case names, splitted by comma, such as barebench,clibbench")
- parser.add_argument('--casecfg', required=True, help="Case configuration for cycle model or fpga")
- parser.add_argument('--caseroot', default=FPGACIROOT, help="Case configuration root")
- parser.add_argument('--logdir', default='logs', help="logs directory, default logs")
- parser.add_argument('--sdk', help="Where SDK located in")
- parser.add_argument('--make_options', help="Extra make options passed to overwrite default build configuration passed via appcfg and hwcfg")
- parser.add_argument('--runon', default='qemu', help="Where to run these application")
- parser.add_argument('--timeout', help="Runner timeout for each application run, if not specified will use default one specified in json configuration")
- parser.add_argument('--verbose', action='store_true', help="If specified, will show detailed build/run messsage")
- parser.add_argument('--uniqueid', default="", help="Pass pipeline$CI_PIPELINE_ID, such as pipeline123456")
- args = parser.parse_args()
- if args.sdk is None:
- sdk_path = os.environ.get("NUCLEI_SDK_ROOT")
- if sdk_path is None or os.path.isdir(sdk_path) == False:
- args.sdk = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), "../../../"))
- else:
- args.sdk = sdk_path
- if not(args.sdk and os.path.isdir(args.sdk) and os.path.isfile(os.path.join(args.sdk, "npk.yml"))):
- print("SDK location %s is invalid, please check!" % (args.sdk))
- sys.exit(1)
- STOPONFAIL = get_env_flag("STOPONFAIL", True)
- print("Using sdk path in %s" % (args.sdk))
- ret, caseconfig = load_json(args.casecfg)
- if ret != JSON_OK:
- print("Invalid case configuration file %s, please check!" % (args.casecfg))
- sys.exit(1)
- passed_cases = []
- failed_cases = []
- torun_cases = list(set(args.cases.split(",")))
- tot_cases = []
- start_time = time.time()
- ret = True
- try:
- print("Prepare to do cases %s on %s, stop on fail %s" % (torun_cases, args.runon, STOPONFAIL))
- index = 0
- totlen = len(torun_cases)
- for case in torun_cases:
- case = case.strip()
- index += 1
- print("Run baremetal cpu test case %s now, progress %d/%d!" % (case, index, totlen))
- if case == "":
- print("Case %s is invaild, ignore it!" % (case))
- continue
- casedir = os.path.join(args.caseroot, case)
- if os.path.isdir(casedir) == False:
- print("Can't find case %s, ignore it!" % (casedir))
- continue
- tot_cases.append(case)
- caselogdir = os.path.join(args.logdir, case)
- casecfgdir = os.path.join(caselogdir, "gencfgs")
- caseconfig["execase"] = case
- if gen_runner_configs(casedir, caseconfig, casecfgdir) == False:
- print("No correct case configurations found in %s" % (casedir))
- ret = False
- # if stop on fail, it will break current execution and exit
- if STOPONFAIL:
- print("Stop early due to case %s failed" % (case))
- failed_cases.append(case)
- break
- else:
- print("Continue execution due to not stop on failed case")
- continue
- runneryaml = os.path.join(casecfgdir, "core.yaml")
- locations = dict()
- nsdk_ext = nsdk_runner(args.sdk, args.make_options, runneryaml, locations, args.verbose, args.timeout)
- casepassed = True
- for config in nsdk_ext.get_configs():
- print("Run case %s for configuration %s specified in yaml %s" % (case, config, runneryaml))
- if nsdk_ext.run_config(config, caselogdir, runon=args.runon, createsubdir=False) == False:
- print("Configuration %s failed" % (config))
- print("Case %s for configuration %s specified in yaml %s: FAILED" % (case, config, runneryaml))
- failed_cases.append(case)
- casepassed = False
- else:
- print("Case %s for configuration %s specified in yaml %s: PASSED" % (case, config, runneryaml))
- passed_cases.append(case)
- # only one configuration should be executed, so just break here
- break
- if casepassed == False:
- ret = False
- # if stop on fail, it will break current execution and exit
- if STOPONFAIL:
- print("Stop early due to case %s failed" % (case))
- break
- else:
- print("Continue execution due to not stop on failed case")
- except Exception as exc:
- print("Unexpected Error: %s during execute case %s" % (exc, case))
- if case not in failed_cases:
- failed_cases.append(case)
- # https://stackoverflow.com/questions/3702675/how-to-catch-and-print-the-full-exception-traceback-without-halting-exiting-the
- traceback.print_exc()
- ret = False
- runtime = round(time.time() - start_time, 2)
- print("Cost about %s seconds to do this running, passed %s!" % (runtime, ret))
- print("All the required cases are %s" % (torun_cases))
- print("Case %s passed out of executed %s" % (passed_cases, tot_cases))
- print("These following cases failed: %s" % (failed_cases))
- # At least passed or failed cases are not zero
- if (len(passed_cases) > 0 or len(failed_cases) > 0) and os.path.isdir(args.logdir):
- runcpustatustxt = os.path.join(args.logdir, "runcpustatus.txt")
- print("Save run cpu report status into %s" % (runcpustatustxt))
- with open(runcpustatustxt, "w") as rf:
- rf.write("PASSED:%s\n" % (",".join(passed_cases)))
- rf.write("FAILED:%s\n" % (",".join(failed_cases)))
- sys.stdout.flush()
- # Exit with ret value
- if ret:
- sys.exit(0)
- else:
- sys.exit(1)
|