xref: /XiangShan/scripts/xiangshan.py (revision b86f926fddda503ee55a9bdf4b8937f569ff1374)
1c6d43980SLemover#***************************************************************************************
2c6d43980SLemover# Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences
3f320e0f0SYinan Xu# Copyright (c) 2020-2021 Peng Cheng Laboratory
4c6d43980SLemover#
5c6d43980SLemover# XiangShan is licensed under Mulan PSL v2.
6c6d43980SLemover# You can use this software according to the terms and conditions of the Mulan PSL v2.
7c6d43980SLemover# You may obtain a copy of Mulan PSL v2 at:
8c6d43980SLemover#          http://license.coscl.org.cn/MulanPSL2
9c6d43980SLemover#
10c6d43980SLemover# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
11c6d43980SLemover# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
12c6d43980SLemover# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
13c6d43980SLemover#
14c6d43980SLemover# See the Mulan PSL v2 for more details.
15c6d43980SLemover#***************************************************************************************
16c6d43980SLemover
17c11a4d2cSYinan Xu# Simple version of xiangshan python wrapper
18c11a4d2cSYinan Xu
19c11a4d2cSYinan Xuimport argparse
2059bcbb59SYinan Xuimport os
2159bcbb59SYinan Xuimport random
22c11a4d2cSYinan Xuimport subprocess
2359bcbb59SYinan Xuimport sys
245ef7374fSLi Qianruoimport time
25c11a4d2cSYinan Xu
2694e266cbSYinan Xuimport psutil
2794e266cbSYinan Xu
28c11a4d2cSYinan Xu
29c11a4d2cSYinan Xuclass XSArgs(object):
30c11a4d2cSYinan Xu    script_path = os.path.realpath(__file__)
31c11a4d2cSYinan Xu    # default path to the repositories
32c11a4d2cSYinan Xu    noop_home = os.path.join(os.path.dirname(script_path), "..")
33c11a4d2cSYinan Xu    nemu_home = os.path.join(noop_home, "../NEMU")
34c11a4d2cSYinan Xu    am_home = os.path.join(noop_home, "../nexus-am")
35c11a4d2cSYinan Xu    dramsim3_home = os.path.join(noop_home, "../DRAMsim3")
36c11a4d2cSYinan Xu    rvtest_home = os.path.join(noop_home, "../riscv-tests")
3724e2eab6SJinYue    default_wave_home = os.path.join(noop_home, "build")
3824e2eab6SJinYue    wave_home   = default_wave_home
39c11a4d2cSYinan Xu
40c11a4d2cSYinan Xu    def __init__(self, args):
41c11a4d2cSYinan Xu        # all path environment variables that should be set
42c11a4d2cSYinan Xu        all_path = [
43c11a4d2cSYinan Xu            # (python argument, environment variable, default, target function)
44c11a4d2cSYinan Xu            (None, "NOOP_HOME", self.noop_home, self.set_noop_home),
45c11a4d2cSYinan Xu            (args.nemu, "NEMU_HOME", self.nemu_home, self.set_nemu_home),
46c11a4d2cSYinan Xu            (args.am, "AM_HOME", self.am_home, self.set_am_home),
47c11a4d2cSYinan Xu            (args.dramsim3, "DRAMSIM3_HOME", self.dramsim3_home, self.set_dramsim3_home),
48c11a4d2cSYinan Xu            (args.rvtest, "RVTEST_HOME", self.rvtest_home, self.set_rvtest_home),
49c11a4d2cSYinan Xu        ]
50c11a4d2cSYinan Xu        for (arg_in, env, default, set_func) in all_path:
51c11a4d2cSYinan Xu            set_func(self.__extract_path(arg_in, env, default))
52c11a4d2cSYinan Xu        # Chisel arguments
531545277aSYinan Xu        self.enable_log = args.enable_log
545ef7374fSLi Qianruo        self.num_cores = args.num_cores
55c11a4d2cSYinan Xu        # Makefile arguments
56c11a4d2cSYinan Xu        self.threads = args.threads
57c11a4d2cSYinan Xu        self.with_dramsim3 = 1 if args.with_dramsim3 else None
581545277aSYinan Xu        self.is_release = 1 if args.release else None
5938e9143dSYinan Xu        self.is_spike = "spike" if args.spike else None
60eb852d4cSJinYue        self.trace = 1 if args.trace or not args.disable_fork  else None
616c0058d3SYinan Xu        self.config = args.config
62c11a4d2cSYinan Xu        # emu arguments
63c11a4d2cSYinan Xu        self.max_instr = args.max_instr
6459bcbb59SYinan Xu        self.seed = random.randint(0, 9999)
65c11a4d2cSYinan Xu        self.numa = args.numa
66f9930da0SYinan Xu        self.diff = args.diff
6738e9143dSYinan Xu        if args.spike and "nemu" in args.diff:
6838e9143dSYinan Xu            self.diff = self.diff.replace("nemu-interpreter", "spike")
69078fde2bSJinYue        self.fork = not args.disable_fork
709c297294SWilliam Wang        self.disable_diff = args.no_diff
7124e2eab6SJinYue        # wave dump path
7224e2eab6SJinYue        if args.wave_dump is not None:
7324e2eab6SJinYue            self.set_wave_home(args.wave_dump)
7424e2eab6SJinYue        else:
7524e2eab6SJinYue            self.set_wave_home(self.default_wave_home)
76c11a4d2cSYinan Xu
77c11a4d2cSYinan Xu    def get_env_variables(self):
78c11a4d2cSYinan Xu        all_env = {
79c11a4d2cSYinan Xu            "NOOP_HOME"    : self.noop_home,
80c11a4d2cSYinan Xu            "NEMU_HOME"    : self.nemu_home,
8124e2eab6SJinYue            "WAVE_HOME"    : self.wave_home,
82c11a4d2cSYinan Xu            "AM_HOME"      : self.am_home,
83c11a4d2cSYinan Xu            "DRAMSIM3_HOME": self.dramsim3_home
84c11a4d2cSYinan Xu        }
85c11a4d2cSYinan Xu        return all_env
86c11a4d2cSYinan Xu
87c11a4d2cSYinan Xu    def get_chisel_args(self, prefix=None):
88c11a4d2cSYinan Xu        chisel_args = [
891545277aSYinan Xu            (self.enable_log, "enable-log")
90c11a4d2cSYinan Xu        ]
91c11a4d2cSYinan Xu        args = map(lambda x: x[1], filter(lambda arg: arg[0], chisel_args))
92c11a4d2cSYinan Xu        if prefix is not None:
93c11a4d2cSYinan Xu            args = map(lambda x: prefix + x, args)
94c11a4d2cSYinan Xu        return args
95c11a4d2cSYinan Xu
96c11a4d2cSYinan Xu    def get_makefile_args(self):
97c11a4d2cSYinan Xu        makefile_args = [
98c11a4d2cSYinan Xu            (self.threads,       "EMU_THREADS"),
99c11a4d2cSYinan Xu            (self.with_dramsim3, "WITH_DRAMSIM3"),
1001545277aSYinan Xu            (self.is_release,    "RELEASE"),
10138e9143dSYinan Xu            (self.is_spike,      "REF"),
1026c0058d3SYinan Xu            (self.trace,         "EMU_TRACE"),
1035ef7374fSLi Qianruo            (self.config,        "CONFIG"),
1045ef7374fSLi Qianruo            (self.num_cores,     "NUM_CORES")
105c11a4d2cSYinan Xu        ]
106c11a4d2cSYinan Xu        args = filter(lambda arg: arg[0] is not None, makefile_args)
107c11a4d2cSYinan Xu        return args
108c11a4d2cSYinan Xu
109c11a4d2cSYinan Xu    def get_emu_args(self):
110c11a4d2cSYinan Xu        emu_args = [
11159bcbb59SYinan Xu            (self.max_instr, "max-instr"),
112f9930da0SYinan Xu            (self.diff,      "diff"),
11359bcbb59SYinan Xu            (self.seed,      "seed")
114c11a4d2cSYinan Xu        ]
115c11a4d2cSYinan Xu        args = filter(lambda arg: arg[0] is not None, emu_args)
116c11a4d2cSYinan Xu        return args
117c11a4d2cSYinan Xu
118c11a4d2cSYinan Xu    def show(self):
119c11a4d2cSYinan Xu        print("Extra environment variables:")
120c11a4d2cSYinan Xu        env = self.get_env_variables()
121c11a4d2cSYinan Xu        for env_name in env:
122c11a4d2cSYinan Xu            print(f"{env_name}: {env[env_name]}")
123c11a4d2cSYinan Xu        print()
124c11a4d2cSYinan Xu        print("Chisel arguments:")
125c11a4d2cSYinan Xu        print(" ".join(self.get_chisel_args()))
126c11a4d2cSYinan Xu        print()
127c11a4d2cSYinan Xu        print("Makefile arguments:")
128c11a4d2cSYinan Xu        for val, name in self.get_makefile_args():
129c11a4d2cSYinan Xu            print(f"{name}={val}")
130c11a4d2cSYinan Xu        print()
131c11a4d2cSYinan Xu        print("emu arguments:")
132c11a4d2cSYinan Xu        for val, name in self.get_emu_args():
133c11a4d2cSYinan Xu            print(f"--{name} {val}")
134c11a4d2cSYinan Xu        print()
135c11a4d2cSYinan Xu
136c11a4d2cSYinan Xu    def __extract_path(self, path, env=None, default=None):
137c11a4d2cSYinan Xu        if path is None and env is not None:
138c11a4d2cSYinan Xu            path = os.getenv(env)
139c11a4d2cSYinan Xu        if path is None and default is not None:
140c11a4d2cSYinan Xu            path = default
141c11a4d2cSYinan Xu        path = os.path.realpath(path)
142c11a4d2cSYinan Xu        return path
143c11a4d2cSYinan Xu
144c11a4d2cSYinan Xu    def set_noop_home(self, path):
145c11a4d2cSYinan Xu        self.noop_home = path
146c11a4d2cSYinan Xu
147c11a4d2cSYinan Xu    def set_nemu_home(self, path):
148c11a4d2cSYinan Xu        self.nemu_home = path
149c11a4d2cSYinan Xu
150c11a4d2cSYinan Xu    def set_am_home(self, path):
151c11a4d2cSYinan Xu        self.am_home = path
152c11a4d2cSYinan Xu
153c11a4d2cSYinan Xu    def set_dramsim3_home(self, path):
154c11a4d2cSYinan Xu        self.dramsim3_home = path
155c11a4d2cSYinan Xu
156c11a4d2cSYinan Xu    def set_rvtest_home(self, path):
157c11a4d2cSYinan Xu        self.rvtest_home = path
158c11a4d2cSYinan Xu
15924e2eab6SJinYue    def set_wave_home(self, path):
16024e2eab6SJinYue        print(f"set wave home to {path}")
16124e2eab6SJinYue        self.wave_home = path
16224e2eab6SJinYue
163c11a4d2cSYinan Xu# XiangShan environment
164c11a4d2cSYinan Xuclass XiangShan(object):
165c11a4d2cSYinan Xu    def __init__(self, args):
166c11a4d2cSYinan Xu        self.args = XSArgs(args)
167c11a4d2cSYinan Xu
168c11a4d2cSYinan Xu    def show(self):
169c11a4d2cSYinan Xu        self.args.show()
170c11a4d2cSYinan Xu
171ef3b5b96SWilliam Wang    def make_clean(self):
172ef3b5b96SWilliam Wang        print("Clean up CI workspace")
173ef3b5b96SWilliam Wang        self.show()
174ef3b5b96SWilliam Wang        return_code = self.__exec_cmd(f'make -C $NOOP_HOME clean')
175ef3b5b96SWilliam Wang        return return_code
176ef3b5b96SWilliam Wang
177c11a4d2cSYinan Xu    def generate_verilog(self):
178c11a4d2cSYinan Xu        print("Generating XiangShan verilog with the following configurations:")
179c11a4d2cSYinan Xu        self.show()
180c11a4d2cSYinan Xu        sim_args = " ".join(self.args.get_chisel_args(prefix="--"))
181c11a4d2cSYinan Xu        make_args = " ".join(map(lambda arg: f"{arg[1]}={arg[0]}", self.args.get_makefile_args()))
182c11a4d2cSYinan Xu        return_code = self.__exec_cmd(f'make -C $NOOP_HOME verilog SIM_ARGS="{sim_args}" {make_args}')
183c11a4d2cSYinan Xu        return return_code
184c11a4d2cSYinan Xu
185c11a4d2cSYinan Xu    def build_emu(self):
186c11a4d2cSYinan Xu        print("Building XiangShan emu with the following configurations:")
187c11a4d2cSYinan Xu        self.show()
188c11a4d2cSYinan Xu        sim_args = " ".join(self.args.get_chisel_args(prefix="--"))
189c11a4d2cSYinan Xu        make_args = " ".join(map(lambda arg: f"{arg[1]}={arg[0]}", self.args.get_makefile_args()))
190a3e87608SWilliam Wang        return_code = self.__exec_cmd(f'make -C $NOOP_HOME emu -j200 SIM_ARGS="{sim_args}" {make_args}')
191c11a4d2cSYinan Xu        return return_code
192c11a4d2cSYinan Xu
193c11a4d2cSYinan Xu    def run_emu(self, workload):
194c11a4d2cSYinan Xu        print("Running XiangShan emu with the following configurations:")
195c11a4d2cSYinan Xu        self.show()
196c11a4d2cSYinan Xu        emu_args = " ".join(map(lambda arg: f"--{arg[1]} {arg[0]}", self.args.get_emu_args()))
197c11a4d2cSYinan Xu        print("workload:", workload)
198c9d90c8dSYinan Xu        numa_args = ""
199c9d90c8dSYinan Xu        if self.args.numa:
20094e266cbSYinan Xu            numa_info = get_free_cores(self.args.threads)
201c9d90c8dSYinan Xu            numa_args = f"numactl -m {numa_info[0]} -C {numa_info[1]}-{numa_info[2]}"
202078fde2bSJinYue        fork_args = "--enable-fork" if self.args.fork else ""
2039c297294SWilliam Wang        diff_args = "--no-diff" if self.args.disable_diff else ""
2049c297294SWilliam Wang        return_code = self.__exec_cmd(f'{numa_args} $NOOP_HOME/build/emu -i {workload} {emu_args} {fork_args} {diff_args}')
205c11a4d2cSYinan Xu        return return_code
206c11a4d2cSYinan Xu
207c11a4d2cSYinan Xu    def run(self, args):
208c11a4d2cSYinan Xu        if args.ci is not None:
209c11a4d2cSYinan Xu            return self.run_ci(args.ci)
210c11a4d2cSYinan Xu        actions = [
211c11a4d2cSYinan Xu            (args.generate, lambda _ : self.generate_verilog()),
212c11a4d2cSYinan Xu            (args.build, lambda _ : self.build_emu()),
213ef3b5b96SWilliam Wang            (args.workload, lambda args: self.run_emu(args.workload)),
214ef3b5b96SWilliam Wang            (args.clean, lambda _ : self.make_clean())
215c11a4d2cSYinan Xu        ]
216c11a4d2cSYinan Xu        valid_actions = map(lambda act: act[1], filter(lambda act: act[0], actions))
217c11a4d2cSYinan Xu        for i, action in enumerate(valid_actions):
218c11a4d2cSYinan Xu            print(f"Action {i}:")
219c11a4d2cSYinan Xu            ret = action(args)
220c11a4d2cSYinan Xu            if ret:
221c11a4d2cSYinan Xu                return ret
222c11a4d2cSYinan Xu        return 0
223c11a4d2cSYinan Xu
224c11a4d2cSYinan Xu    def __exec_cmd(self, cmd):
225c11a4d2cSYinan Xu        env = dict(os.environ)
226c11a4d2cSYinan Xu        env.update(self.args.get_env_variables())
227c11a4d2cSYinan Xu        print("subprocess call cmd:", cmd)
2285ef7374fSLi Qianruo        start = time.time()
229c11a4d2cSYinan Xu        return_code = subprocess.call(cmd, shell=True, env=env)
2305ef7374fSLi Qianruo        end = time.time()
2315ef7374fSLi Qianruo        print(f"Elapsed time: {end - start} seconds")
232c11a4d2cSYinan Xu        return return_code
233c11a4d2cSYinan Xu
234c11a4d2cSYinan Xu    def __get_ci_cputest(self, name=None):
235c11a4d2cSYinan Xu        base_dir = os.path.join(self.args.am_home, "tests/cputest/build")
236c11a4d2cSYinan Xu        cputest = os.listdir(base_dir)
237c11a4d2cSYinan Xu        cputest = filter(lambda x: x.endswith(".bin"), cputest)
238c11a4d2cSYinan Xu        cputest = map(lambda x: os.path.join(base_dir, x), cputest)
239c11a4d2cSYinan Xu        return cputest
240c11a4d2cSYinan Xu
241c11a4d2cSYinan Xu    def __get_ci_rvtest(self, name=None):
242c11a4d2cSYinan Xu        base_dir = os.path.join(self.args.rvtest_home, "isa/build")
243c11a4d2cSYinan Xu        riscv_tests = os.listdir(base_dir)
244c11a4d2cSYinan Xu        riscv_tests = filter(lambda x: x.endswith(".bin"), riscv_tests)
245c11a4d2cSYinan Xu        all_rv_tests = ["rv64ui", "rv64um", "rv64ua", "rv64uf", "rv64ud"]
246c11a4d2cSYinan Xu        riscv_tests = filter(lambda x: x[:6] in all_rv_tests, riscv_tests)
247c11a4d2cSYinan Xu        riscv_tests = map(lambda x: os.path.join(base_dir, x), riscv_tests)
248c11a4d2cSYinan Xu        return riscv_tests
249c11a4d2cSYinan Xu
250675acc68SYinan Xu    def __get_ci_misc(self, name=None):
251da3b568bSYinan Xu        base_dir = "/nfs/home/share/ci-workloads"
252675acc68SYinan Xu        workloads = [
253675acc68SYinan Xu            "bitmanip/bitMisc.bin",
2543feeca58Szfw            "crypto/crypto-riscv64-noop.bin",
255675acc68SYinan Xu            "coremark_rv64gc_o2/coremark-riscv64-xs.bin",
256675acc68SYinan Xu            "coremark_rv64gc_o3/coremark-riscv64-xs.bin",
25764a887e0SYinan Xu            "coremark_rv64gcb_o3/coremark-riscv64-xs.bin",
25835620aa8Swakafa            "ext_intr/amtest-riscv64-xs.bin",
2593f4ec46fSCODE-JTZ            "cache-alias/aliastest-riscv64-xs.bin",
260af2f7849Shappy-lx            "Svinval/rv64mi-p-svinval.bin",
261b6982e83SLemover            "pmp/pmp.riscv.bin",
26245f497a4Shappy-lx            "asid/asid.bin",
2637d9edc86SLemover            "isa_misc/xret_clear_mprv.bin",
264705cbec3SLemover            "isa_misc/satp_ppn.bin",
2659c297294SWilliam Wang            "cache-management/softprefetchtest-riscv64-xs.bin"
266675acc68SYinan Xu        ]
267675acc68SYinan Xu        misc_tests = map(lambda x: os.path.join(base_dir, x), workloads)
268675acc68SYinan Xu        return misc_tests
269675acc68SYinan Xu
270ef3b5b96SWilliam Wang    def __get_ci_mc(self, name=None):
271ef3b5b96SWilliam Wang        base_dir = "/nfs/home/share/ci-workloads"
272ef3b5b96SWilliam Wang        workloads = [
273ef3b5b96SWilliam Wang            "dualcoretest/ldvio-riscv64-xs.bin"
274ef3b5b96SWilliam Wang        ]
275ef3b5b96SWilliam Wang        mc_tests = map(lambda x: os.path.join(base_dir, x), workloads)
276ef3b5b96SWilliam Wang        return mc_tests
277ef3b5b96SWilliam Wang
2789c297294SWilliam Wang    def __get_ci_nodiff(self, name=None):
279da3b568bSYinan Xu        base_dir = "/nfs/home/share/ci-workloads"
2809c297294SWilliam Wang        workloads = [
2819c297294SWilliam Wang            "cache-management/cacheoptest-riscv64-xs.bin"
2829c297294SWilliam Wang        ]
2839c297294SWilliam Wang        tests = map(lambda x: os.path.join(base_dir, x), workloads)
2849c297294SWilliam Wang        return tests
2859c297294SWilliam Wang
286c11a4d2cSYinan Xu    def __am_apps_path(self, bench):
287c11a4d2cSYinan Xu        filename = f"{bench}-riscv64-noop.bin"
288c11a4d2cSYinan Xu        return [os.path.join(self.args.am_home, "apps", bench, "build", filename)]
289c11a4d2cSYinan Xu
290c11a4d2cSYinan Xu    def __get_ci_workloads(self, name):
291c11a4d2cSYinan Xu        workloads = {
292c11a4d2cSYinan Xu            "linux-hello": "bbl.bin",
293fac0ab56Swakafa            "linux-hello-smp": "bbl.bin",
2945092a298Szfw            "povray": "_700480000000_.gz",
2955092a298Szfw            "mcf": "_17520000000_.gz",
2965092a298Szfw            "xalancbmk": "_266100000000_.gz",
2975092a298Szfw            "gcc": "_39720000000_.gz",
2985092a298Szfw            "namd": "_434640000000_.gz",
2995092a298Szfw            "milc": "_103620000000_.gz",
3005092a298Szfw            "lbm": "_140840000000_.gz",
3017b441e5eSYinan Xu            "gromacs": "_275480000000_.gz",
3027b441e5eSYinan Xu            "wrf": "_1916220000000_.gz",
3037b441e5eSYinan Xu            "astar": "_122060000000_.gz"
304c11a4d2cSYinan Xu        }
305da3b568bSYinan Xu        return [os.path.join("/nfs/home/share/ci-workloads", name, workloads[name])]
306c11a4d2cSYinan Xu
307c11a4d2cSYinan Xu    def run_ci(self, test):
308c11a4d2cSYinan Xu        all_tests = {
309c11a4d2cSYinan Xu            "cputest": self.__get_ci_cputest,
310c11a4d2cSYinan Xu            "riscv-tests": self.__get_ci_rvtest,
311675acc68SYinan Xu            "misc-tests": self.__get_ci_misc,
312ef3b5b96SWilliam Wang            "mc-tests": self.__get_ci_mc,
3139c297294SWilliam Wang            "nodiff-tests": self.__get_ci_nodiff,
314c11a4d2cSYinan Xu            "microbench": self.__am_apps_path,
315c11a4d2cSYinan Xu            "coremark": self.__am_apps_path
316c11a4d2cSYinan Xu        }
317c11a4d2cSYinan Xu        for target in all_tests.get(test, self.__get_ci_workloads)(test):
318c11a4d2cSYinan Xu            print(target)
319c11a4d2cSYinan Xu            ret = self.run_emu(target)
320c11a4d2cSYinan Xu            if ret:
32124e2eab6SJinYue                if self.args.default_wave_home != self.args.wave_home:
32224e2eab6SJinYue                    print("copy wave file to " + self.args.wave_home)
32324e2eab6SJinYue                    self.__exec_cmd(f"cp $NOOP_HOME/build/*.vcd $WAVE_HOME")
324bc063562SLemover                    self.__exec_cmd(f"cp $NOOP_HOME/build/emu $WAVE_HOME")
325bc063562SLemover                    self.__exec_cmd(f"cp $NOOP_HOME/build/SimTop.v $WAVE_HOME")
326c11a4d2cSYinan Xu                return ret
327c11a4d2cSYinan Xu        return 0
328c11a4d2cSYinan Xu
32994e266cbSYinan Xudef get_free_cores(n):
33094e266cbSYinan Xu    while True:
33194e266cbSYinan Xu        # To avoid potential conflicts, we allow CI to use SMT.
332*b86f926fSYinan Xu        num_logical_core = psutil.cpu_count(logical=False)
33394e266cbSYinan Xu        core_usage = psutil.cpu_percent(interval=1, percpu=True)
33494e266cbSYinan Xu        num_window = num_logical_core // n
33594e266cbSYinan Xu        for i in range(num_window):
33694e266cbSYinan Xu            window_usage = core_usage[i * n : i * n + n]
33794e266cbSYinan Xu            if sum(window_usage) < 0.3 * n and True not in map(lambda x: x > 0.5, window_usage):
33894e266cbSYinan Xu                return (((i * n) % 128)// 64, i * n, i * n + n - 1)
33994e266cbSYinan Xu        print(f"No free {n} cores found. CPU usage: {core_usage}\n")
34094e266cbSYinan Xu
341c11a4d2cSYinan Xuif __name__ == "__main__":
342c11a4d2cSYinan Xu    parser = argparse.ArgumentParser(description='Python wrapper for XiangShan')
343c11a4d2cSYinan Xu    parser.add_argument('workload', nargs='?', type=str, default="",
344c11a4d2cSYinan Xu                        help='input workload file in binary format')
345c11a4d2cSYinan Xu    # actions
346c11a4d2cSYinan Xu    parser.add_argument('--build', action='store_true', help='build XS emu')
347c11a4d2cSYinan Xu    parser.add_argument('--generate', action='store_true', help='generate XS verilog')
348c11a4d2cSYinan Xu    parser.add_argument('--ci', nargs='?', type=str, const="", help='run CI tests')
349ef3b5b96SWilliam Wang    parser.add_argument('--clean', action='store_true', help='clean up XiangShan CI workspace')
350c11a4d2cSYinan Xu    # environment variables
351c11a4d2cSYinan Xu    parser.add_argument('--nemu', nargs='?', type=str, help='path to nemu')
352c11a4d2cSYinan Xu    parser.add_argument('--am', nargs='?', type=str, help='path to nexus-am')
353c11a4d2cSYinan Xu    parser.add_argument('--dramsim3', nargs='?', type=str, help='path to dramsim3')
354c11a4d2cSYinan Xu    parser.add_argument('--rvtest', nargs='?', type=str, help='path to riscv-tests')
35524e2eab6SJinYue    parser.add_argument('--wave-dump', nargs='?', type=str , help='path to dump wave')
356c11a4d2cSYinan Xu    # chisel arguments
3571545277aSYinan Xu    parser.add_argument('--enable-log', action='store_true', help='enable log')
3585ef7374fSLi Qianruo    parser.add_argument('--num-cores', type=int, help='number of cores')
359c11a4d2cSYinan Xu    # makefile arguments
3601545277aSYinan Xu    parser.add_argument('--release', action='store_true', help='enable release')
36138e9143dSYinan Xu    parser.add_argument('--spike', action='store_true', help='enable spike diff')
362c11a4d2cSYinan Xu    parser.add_argument('--with-dramsim3', action='store_true', help='enable dramsim3')
363c11a4d2cSYinan Xu    parser.add_argument('--threads', nargs='?', type=int, help='number of emu threads')
364c11a4d2cSYinan Xu    parser.add_argument('--trace', action='store_true', help='enable waveform')
3656c0058d3SYinan Xu    parser.add_argument('--config', nargs='?', type=str, help='config')
366c11a4d2cSYinan Xu    # emu arguments
367c11a4d2cSYinan Xu    parser.add_argument('--numa', action='store_true', help='use numactl')
368f9930da0SYinan Xu    parser.add_argument('--diff', nargs='?', default="./ready-to-run/riscv64-nemu-interpreter-so", type=str, help='nemu so')
369c11a4d2cSYinan Xu    parser.add_argument('--max-instr', nargs='?', type=int, help='max instr')
370078fde2bSJinYue    parser.add_argument('--disable-fork', action='store_true', help='disable lightSSS')
3719c297294SWilliam Wang    parser.add_argument('--no-diff', action='store_true', help='disable difftest')
37224e2eab6SJinYue    # ci action head sha
373c11a4d2cSYinan Xu
374c11a4d2cSYinan Xu    args = parser.parse_args()
375c11a4d2cSYinan Xu
376c11a4d2cSYinan Xu    xs = XiangShan(args)
377c11a4d2cSYinan Xu    ret = xs.run(args)
378c11a4d2cSYinan Xu
379c11a4d2cSYinan Xu    sys.exit(ret)
380