1#*************************************************************************************** 2# Copyright (c) 2024 Beijing Institute of Open Source Chip (BOSC) 3# Copyright (c) 2020-2024 Institute of Computing Technology, Chinese Academy of Sciences 4# Copyright (c) 2020-2021 Peng Cheng Laboratory 5# 6# XiangShan is licensed under Mulan PSL v2. 7# You can use this software according to the terms and conditions of the Mulan PSL v2. 8# You may obtain a copy of Mulan PSL v2 at: 9# http://license.coscl.org.cn/MulanPSL2 10# 11# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 12# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 13# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 14# 15# See the Mulan PSL v2 for more details. 16#*************************************************************************************** 17 18# Simple version of xiangshan python wrapper 19 20import argparse 21import json 22import os 23import random 24import signal 25import subprocess 26import sys 27import time 28import shlex 29import psutil 30import re 31 32def load_all_gcpt(gcpt_path, json_path): 33 all_gcpt = [] 34 with open(json_path) as f: 35 data = json.load(f) 36 for benchspec in data: 37 for point in data[benchspec]: 38 weight = data[benchspec][point] 39 gcpt = os.path.join(gcpt_path, "_".join([benchspec, point, weight])) 40 bin_dir = os.path.join(gcpt, "0") 41 bin_file = list(os.listdir(bin_dir)) 42 assert(len(bin_file) == 1) 43 bin_path = os.path.join(bin_dir, bin_file[0]) 44 assert(os.path.isfile(bin_path)) 45 all_gcpt.append(bin_path) 46 return all_gcpt 47 48class XSArgs(object): 49 script_path = os.path.realpath(__file__) 50 # default path to the repositories 51 noop_home = os.path.join(os.path.dirname(script_path), "..") 52 nemu_home = os.path.join(noop_home, "../NEMU") 53 am_home = os.path.join(noop_home, "../nexus-am") 54 dramsim3_home = os.path.join(noop_home, "../DRAMsim3") 55 rvtest_home = os.path.join(noop_home, "../riscv-tests") 56 default_wave_home = os.path.join(noop_home, "build") 57 wave_home = default_wave_home 58 59 def __init__(self, args): 60 # all path environment variables that should be set 61 all_path = [ 62 # (python argument, environment variable, default, target function) 63 (None, "NOOP_HOME", self.noop_home, self.set_noop_home), 64 (args.nemu, "NEMU_HOME", self.nemu_home, self.set_nemu_home), 65 (args.am, "AM_HOME", self.am_home, self.set_am_home), 66 (args.dramsim3, "DRAMSIM3_HOME", self.dramsim3_home, self.set_dramsim3_home), 67 (args.rvtest, "RVTEST_HOME", self.rvtest_home, self.set_rvtest_home), 68 ] 69 for (arg_in, env, default, set_func) in all_path: 70 set_func(self.__extract_path(arg_in, env, default)) 71 # Chisel arguments 72 self.enable_log = args.enable_log 73 self.num_cores = args.num_cores 74 # Makefile arguments 75 self.threads = args.threads 76 self.with_dramsim3 = 1 if args.with_dramsim3 else None 77 self.is_release = 1 if args.release else None 78 self.is_spike = "Spike" if args.spike else None 79 self.trace = 1 if args.trace or not args.disable_fork and not args.trace_fst else None 80 self.trace_fst = "fst" if args.trace_fst else None 81 self.config = args.config 82 self.emu_optimize = args.emu_optimize 83 self.xprop = 1 if args.xprop else None 84 self.with_chiseldb = 0 if args.no_db else 1 85 # emu arguments 86 self.max_instr = args.max_instr 87 self.ram_size = args.ram_size 88 self.seed = random.randint(0, 9999) 89 self.numa = args.numa 90 self.diff = args.diff 91 if args.spike and "nemu" in args.diff: 92 self.diff = self.diff.replace("nemu-interpreter", "spike") 93 self.fork = not args.disable_fork 94 self.disable_diff = args.no_diff 95 self.disable_db = args.no_db 96 self.gcpt_restore_bin = args.gcpt_restore_bin 97 self.pgo = args.pgo 98 self.pgo_max_cycle = args.pgo_max_cycle 99 self.pgo_emu_args = args.pgo_emu_args 100 self.llvm_profdata = args.llvm_profdata 101 # wave dump path 102 if args.wave_dump is not None: 103 self.set_wave_home(args.wave_dump) 104 else: 105 self.set_wave_home(self.default_wave_home) 106 107 def get_env_variables(self): 108 all_env = { 109 "NOOP_HOME" : self.noop_home, 110 "NEMU_HOME" : self.nemu_home, 111 "WAVE_HOME" : self.wave_home, 112 "AM_HOME" : self.am_home, 113 "DRAMSIM3_HOME": self.dramsim3_home, 114 "MODULEPATH": "/usr/share/Modules/modulefiles:/etc/modulefiles" 115 } 116 return all_env 117 118 def get_chisel_args(self, prefix=None): 119 chisel_args = [ 120 (self.enable_log, "enable-log") 121 ] 122 args = map(lambda x: x[1], filter(lambda arg: arg[0], chisel_args)) 123 if prefix is not None: 124 args = map(lambda x: prefix + x, args) 125 return args 126 127 def get_makefile_args(self): 128 makefile_args = [ 129 (self.threads, "EMU_THREADS"), 130 (self.with_dramsim3, "WITH_DRAMSIM3"), 131 (self.is_release, "RELEASE"), 132 (self.is_spike, "REF"), 133 (self.trace, "EMU_TRACE"), 134 (self.trace_fst, "EMU_TRACE"), 135 (self.config, "CONFIG"), 136 (self.num_cores, "NUM_CORES"), 137 (self.emu_optimize, "EMU_OPTIMIZE"), 138 (self.xprop, "ENABLE_XPROP"), 139 (self.with_chiseldb, "WITH_CHISELDB"), 140 (self.pgo, "PGO_WORKLOAD"), 141 (self.pgo_max_cycle, "PGO_MAX_CYCLE"), 142 (self.pgo_emu_args, "PGO_EMU_ARGS"), 143 (self.llvm_profdata, "LLVM_PROFDATA"), 144 ] 145 args = filter(lambda arg: arg[0] is not None, makefile_args) 146 args = [(shlex.quote(str(arg[0])), arg[1]) for arg in args] # shell escape 147 return args 148 149 def get_emu_args(self): 150 emu_args = [ 151 (self.max_instr, "max-instr"), 152 (self.diff, "diff"), 153 (self.seed, "seed"), 154 (self.ram_size, "ram-size"), 155 ] 156 args = filter(lambda arg: arg[0] is not None, emu_args) 157 return args 158 159 def show(self): 160 print("Extra environment variables:") 161 env = self.get_env_variables() 162 for env_name in env: 163 print(f"{env_name}: {env[env_name]}") 164 print() 165 print("Chisel arguments:") 166 print(" ".join(self.get_chisel_args())) 167 print() 168 print("Makefile arguments:") 169 for val, name in self.get_makefile_args(): 170 print(f"{name}={val}") 171 print() 172 print("emu arguments:") 173 for val, name in self.get_emu_args(): 174 print(f"--{name} {val}") 175 print() 176 177 def __extract_path(self, path, env=None, default=None): 178 if path is None and env is not None: 179 path = os.getenv(env) 180 if path is None and default is not None: 181 path = default 182 path = os.path.realpath(path) 183 return path 184 185 def set_noop_home(self, path): 186 self.noop_home = path 187 188 def set_nemu_home(self, path): 189 self.nemu_home = path 190 191 def set_am_home(self, path): 192 self.am_home = path 193 194 def set_dramsim3_home(self, path): 195 self.dramsim3_home = path 196 197 def set_rvtest_home(self, path): 198 self.rvtest_home = path 199 200 def set_wave_home(self, path): 201 print(f"set wave home to {path}") 202 self.wave_home = path 203 204# XiangShan environment 205class XiangShan(object): 206 def __init__(self, args): 207 self.args = XSArgs(args) 208 self.timeout = args.timeout 209 210 def show(self): 211 self.args.show() 212 213 def make_clean(self): 214 print("Clean up CI workspace") 215 self.show() 216 return_code = self.__exec_cmd(f'make -C $NOOP_HOME clean') 217 return return_code 218 219 def generate_verilog(self): 220 print("Generating XiangShan verilog with the following configurations:") 221 self.show() 222 sim_args = " ".join(self.args.get_chisel_args(prefix="--")) 223 make_args = " ".join(map(lambda arg: f"{arg[1]}={arg[0]}", self.args.get_makefile_args())) 224 return_code = self.__exec_cmd(f'make -C $NOOP_HOME verilog SIM_ARGS="{sim_args}" {make_args}') 225 return return_code 226 227 def generate_sim_verilog(self): 228 print("Generating XiangShan sim-verilog with the following configurations:") 229 self.show() 230 sim_args = " ".join(self.args.get_chisel_args(prefix="--")) 231 make_args = " ".join(map(lambda arg: f"{arg[1]}={arg[0]}", self.args.get_makefile_args())) 232 return_code = self.__exec_cmd(f'make -C $NOOP_HOME sim-verilog SIM_ARGS="{sim_args}" {make_args}') 233 return return_code 234 235 def build_emu(self): 236 print("Building XiangShan emu with the following configurations:") 237 self.show() 238 sim_args = " ".join(self.args.get_chisel_args(prefix="--")) 239 make_args = " ".join(map(lambda arg: f"{arg[1]}={arg[0]}", self.args.get_makefile_args())) 240 return_code = self.__exec_cmd(f'make -C $NOOP_HOME emu -j200 SIM_ARGS="{sim_args}" {make_args}') 241 return return_code 242 243 def build_simv(self): 244 print("Building XiangShan simv with the following configurations") 245 self.show() 246 make_args = " ".join(map(lambda arg: f"{arg[1]}={arg[0]}", self.args.get_makefile_args())) 247 # TODO: make the following commands grouped as unseen scripts 248 return_code = self.__exec_cmd(f'\ 249 eval `/usr/bin/modulecmd zsh load license`;\ 250 eval `/usr/bin/modulecmd zsh load synopsys/vcs/Q-2020.03-SP2`;\ 251 eval `/usr/bin/modulecmd zsh load synopsys/verdi/S-2021.09-SP1`;\ 252 VERDI_HOME=/nfs/tools/synopsys/verdi/S-2021.09-SP1 \ 253 make -C $NOOP_HOME simv {make_args} CONSIDER_FSDB=1') # set CONSIDER_FSDB for compatibility 254 return return_code 255 256 def run_emu(self, workload): 257 print("Running XiangShan emu with the following configurations:") 258 self.show() 259 emu_args = " ".join(map(lambda arg: f"--{arg[1]} {arg[0]}", self.args.get_emu_args())) 260 print("workload:", workload) 261 numa_args = "" 262 if self.args.numa: 263 numa_info = get_free_cores(self.args.threads) 264 numa_args = f"numactl -m {numa_info[0]} -C {numa_info[1]}-{numa_info[2]}" 265 fork_args = "--enable-fork -X 10" if self.args.fork else "" 266 diff_args = "--no-diff" if self.args.disable_diff else "" 267 chiseldb_args = "--dump-db" if not self.args.disable_db else "" 268 gcpt_restore_args = f"-r {self.args.gcpt_restore_bin}" if len(self.args.gcpt_restore_bin) != 0 else "" 269 return_code = self.__exec_cmd(f'ulimit -s {32 * 1024}; {numa_args} $NOOP_HOME/build/emu -i {workload} {emu_args} {fork_args} {diff_args} {chiseldb_args} {gcpt_restore_args}') 270 return return_code 271 272 def run_simv(self, workload): 273 print("Running XiangShan simv with the following configurations:") 274 self.show() 275 diff_args = "$NOOP_HOME/"+ args.diff 276 assert_args = "-assert finish_maxfail=30 -assert global_finish_maxfail=10000" 277 return_code = self.__exec_cmd(f'cd $NOOP_HOME/build && ./simv +workload={workload} +diff={diff_args} +dump-wave=fsdb {assert_args} | tee simv.log') 278 with open(f"{self.args.noop_home}/build/simv.log") as f: 279 content = f.read() 280 if "Offending" in content or "HIT GOOD TRAP" not in content: 281 return 1 282 return return_code 283 284 def run(self, args): 285 if args.ci is not None: 286 return self.run_ci(args.ci) 287 if args.ci_vcs is not None: 288 return self.run_ci_vcs(args.ci_vcs) 289 actions = [ 290 (args.generate, lambda _ : self.generate_verilog()), 291 (args.vcs_gen, lambda _ : self.generate_sim_verilog()), 292 (args.build, lambda _ : self.build_emu()), 293 (args.vcs_build, lambda _ : self.build_simv()), 294 (args.workload, lambda args: self.run_emu(args.workload)), 295 (args.clean, lambda _ : self.make_clean()) 296 ] 297 valid_actions = map(lambda act: act[1], filter(lambda act: act[0], actions)) 298 for i, action in enumerate(valid_actions): 299 print(f"Action {i}:") 300 ret = action(args) 301 if ret: 302 return ret 303 return 0 304 305 def __exec_cmd(self, cmd): 306 env = dict(os.environ) 307 env.update(self.args.get_env_variables()) 308 print("subprocess call cmd:", cmd) 309 start = time.time() 310 proc = subprocess.Popen(cmd, shell=True, env=env, preexec_fn=os.setsid) 311 try: 312 return_code = proc.wait(self.timeout) 313 end = time.time() 314 print(f"Elapsed time: {end - start} seconds") 315 return return_code 316 except (KeyboardInterrupt, subprocess.TimeoutExpired): 317 os.killpg(os.getpgid(proc.pid), signal.SIGINT) 318 print(f"KeyboardInterrupt or TimeoutExpired.") 319 return 0 320 321 def __get_ci_cputest(self, name=None): 322 # base_dir = os.path.join(self.args.am_home, "tests/cputest/build") 323 base_dir = "/nfs/home/share/ci-workloads/nexus-am-workloads/tests/cputest" 324 cputest = os.listdir(base_dir) 325 cputest = filter(lambda x: x.endswith(".bin"), cputest) 326 cputest = map(lambda x: os.path.join(base_dir, x), cputest) 327 return cputest 328 329 def __get_ci_rvtest(self, name=None): 330 base_dir = os.path.join(self.args.rvtest_home, "isa/build") 331 riscv_tests = os.listdir(base_dir) 332 riscv_tests = filter(lambda x: x.endswith(".bin"), riscv_tests) 333 all_rv_tests = ["rv64ui", "rv64um", "rv64ua", "rv64uf", "rv64ud", "rv64mi"] 334 riscv_tests = filter(lambda x: x[:6] in all_rv_tests, riscv_tests) 335 riscv_tests = map(lambda x: os.path.join(base_dir, x), riscv_tests) 336 return riscv_tests 337 338 def __get_ci_misc(self, name=None): 339 base_dir = "/nfs/home/share/ci-workloads" 340 workloads = [ 341 "bitmanip/bitMisc.bin", 342 "crypto/crypto-riscv64-noop.bin", 343 # "coremark_rv64gc_o2/coremark-riscv64-xs.bin", 344 # "coremark_rv64gc_o3/coremark-riscv64-xs.bin", 345 # "coremark_rv64gcb_o3/coremark-riscv64-xs.bin", 346 "nexus-am-workloads/amtest/external_intr-riscv64-xs.bin", 347 "nexus-am-workloads/tests/aliastest/aliastest-riscv64-xs.bin", 348 "Svinval/rv64mi-p-svinval.bin", 349 "pmp/pmp.riscv.bin", 350 "nexus-am-workloads/amtest/pmp_test-riscv64-xs.bin", 351 "nexus-am-workloads/amtest/sv39_hp_atom_test-riscv64-xs.bin", 352 "asid/asid.bin", 353 "isa_misc/xret_clear_mprv.bin", 354 "isa_misc/satp_ppn.bin", 355 "cache-management/softprefetchtest-riscv64-xs.bin" 356 ] 357 misc_tests = map(lambda x: os.path.join(base_dir, x), workloads) 358 return misc_tests 359 360 def __get_ci_rvhtest(self, name=None): 361 base_dir = "/nfs/home/share/ci-workloads/H-extension-tests" 362 workloads = [ 363 "riscv-hyp-tests/rvh_test.bin", 364 "xvisor_wboxtest/checkpoint.gz", 365 ] 366 rvh_tests = map(lambda x: os.path.join(base_dir, x), workloads) 367 return rvh_tests 368 369 def __get_ci_rvvbench(self, name=None): 370 base_dir = "/nfs/home/share/ci-workloads" 371 workloads = [ 372 "rvv-bench/poly1305.bin", 373 "rvv-bench/mergelines.bin" 374 ] 375 rvvbench = map(lambda x: os.path.join(base_dir, x), workloads) 376 return rvvbench 377 378 def __get_ci_rvvtest(self, name=None): 379 base_dir = "/nfs/home/share/ci-workloads/V-extension-tests" 380 workloads = [ 381 "rvv-test/vluxei32.v-0.bin", 382 "rvv-test/vlsseg4e32.v-0.bin", 383 "rvv-test/vlseg4e32.v-0.bin", 384 "rvv-test/vsetvl-0.bin", 385 "rvv-test/vsetivli-0.bin", 386 "rvv-test/vsuxei32.v-0.bin", 387 "rvv-test/vse16.v-0.bin", 388 "rvv-test/vsse16.v-1.bin", 389 "rvv-test/vlse32.v-0.bin", 390 "rvv-test/vsetvli-0.bin", 391 "rvv-test/vle16.v-0.bin", 392 "rvv-test/vle32.v-0.bin", 393 "rvv-test/vfsgnj.vv-0.bin", 394 "rvv-test/vfadd.vf-0.bin", 395 "rvv-test/vfsub.vf-0.bin", 396 "rvv-test/vslide1down.vx-0.bin" 397 ] 398 rvv_test = map(lambda x: os.path.join(base_dir, x), workloads) 399 return rvv_test 400 401 def __get_ci_F16test(self, name=None): 402 base_dir = "/nfs/home/share/ci-workloads/vector/F16-tests/build" 403 workloads = [ 404 "rv64uzfhmin-p-fzfhmincvt.bin", 405 "rv64uzfh-p-fadd.bin", 406 "rv64uzfh-p-fclass.bin", 407 "rv64uzfh-p-fcmp.bin", 408 "rv64uzfh-p-fcvt.bin", 409 "rv64uzfh-p-fcvt_w.bin", 410 "rv64uzfh-p-fdiv.bin", 411 "rv64uzfh-p-fmadd.bin", 412 "rv64uzfh-p-fmin.bin", 413 "rv64uzfh-p-ldst.bin", 414 "rv64uzfh-p-move.bin", 415 "rv64uzfh-p-recoding.bin", 416 "rv64uzvfh-p-vfadd.bin", 417 "rv64uzvfh-p-vfclass.bin", 418 "rv64uzvfh-p-vfcvtfx.bin", 419 "rv64uzvfh-p-vfcvtfxu.bin", 420 "rv64uzvfh-p-vfcvtrxf.bin", 421 "rv64uzvfh-p-vfcvtrxuf.bin", 422 "rv64uzvfh-p-vfcvtxf.bin", 423 "rv64uzvfh-p-vfcvtxuf.bin", 424 "rv64uzvfh-p-vfdiv.bin", 425 "rv64uzvfh-p-vfdown.bin", 426 "rv64uzvfh-p-vfmacc.bin", 427 "rv64uzvfh-p-vfmadd.bin", 428 "rv64uzvfh-p-vfmax.bin", 429 "rv64uzvfh-p-vfmerge.bin", 430 "rv64uzvfh-p-vfmin.bin", 431 "rv64uzvfh-p-vfmsac.bin", 432 "rv64uzvfh-p-vfmsub.bin", 433 "rv64uzvfh-p-vfmul.bin", 434 "rv64uzvfh-p-vfmv.bin", 435 "rv64uzvfh-p-vfncvtff.bin", 436 "rv64uzvfh-p-vfncvtfx.bin", 437 "rv64uzvfh-p-vfncvtfxu.bin", 438 "rv64uzvfh-p-vfncvtrff.bin", 439 "rv64uzvfh-p-vfncvtrxf.bin", 440 "rv64uzvfh-p-vfncvtrxuf.bin", 441 "rv64uzvfh-p-vfncvtxf.bin", 442 "rv64uzvfh-p-vfncvtxuf.bin", 443 "rv64uzvfh-p-vfnmacc.bin", 444 "rv64uzvfh-p-vfnmadd.bin", 445 "rv64uzvfh-p-vfnmsac.bin", 446 "rv64uzvfh-p-vfnmsub.bin", 447 "rv64uzvfh-p-vfrdiv.bin", 448 "rv64uzvfh-p-vfrec7.bin", 449 "rv64uzvfh-p-vfredmax.bin", 450 "rv64uzvfh-p-vfredmin.bin", 451 "rv64uzvfh-p-vfredosum.bin", 452 "rv64uzvfh-p-vfredusum.bin", 453 "rv64uzvfh-p-vfrsqrt7.bin", 454 "rv64uzvfh-p-vfrsub.bin", 455 "rv64uzvfh-p-vfsgnj.bin", 456 "rv64uzvfh-p-vfsgnjn.bin", 457 "rv64uzvfh-p-vfsgnjx.bin", 458 "rv64uzvfh-p-vfsqrt.bin", 459 "rv64uzvfh-p-vfsub.bin", 460 "rv64uzvfh-p-vfup.bin", 461 "rv64uzvfh-p-vfwadd.bin", 462 "rv64uzvfh-p-vfwadd-w.bin", 463 "rv64uzvfh-p-vfwcvtff.bin", 464 "rv64uzvfh-p-vfwcvtfx.bin", 465 "rv64uzvfh-p-vfwcvtfxu.bin", 466 "rv64uzvfh-p-vfwcvtrxf.bin", 467 "rv64uzvfh-p-vfwcvtrxuf.bin", 468 "rv64uzvfh-p-vfwcvtxf.bin", 469 "rv64uzvfh-p-vfwcvtxuf.bin", 470 "rv64uzvfh-p-vfwmacc.bin", 471 "rv64uzvfh-p-vfwmsac.bin", 472 "rv64uzvfh-p-vfwmul.bin", 473 "rv64uzvfh-p-vfwnmacc.bin", 474 "rv64uzvfh-p-vfwnmsac.bin", 475 "rv64uzvfh-p-vfwredosum.bin", 476 "rv64uzvfh-p-vfwredusum.bin", 477 "rv64uzvfh-p-vfwsub.bin", 478 "rv64uzvfh-p-vfwsub-w.bin", 479 "rv64uzvfh-p-vmfeq.bin", 480 "rv64uzvfh-p-vmfge.bin", 481 "rv64uzvfh-p-vmfgt.bin", 482 "rv64uzvfh-p-vmfle.bin", 483 "rv64uzvfh-p-vmflt.bin", 484 "rv64uzvfh-p-vmfne.bin" 485 ] 486 f16_test = map(lambda x: os.path.join(base_dir, x), workloads) 487 return f16_test 488 def __get_ci_zcbtest(self, name=None): 489 base_dir = "/nfs/home/share/ci-workloads/zcb-test" 490 workloads = [ 491 "zcb-test-riscv64-xs.bin" 492 ] 493 zcb_test = map(lambda x: os.path.join(base_dir, x), workloads) 494 return zcb_test 495 496 def __get_ci_mc(self, name=None): 497 base_dir = "/nfs/home/share/ci-workloads" 498 workloads = [ 499 "nexus-am-workloads/tests/dualcoretest/ldvio-riscv64-xs.bin" 500 ] 501 mc_tests = map(lambda x: os.path.join(base_dir, x), workloads) 502 return mc_tests 503 504 def __get_ci_nodiff(self, name=None): 505 base_dir = "/nfs/home/share/ci-workloads" 506 workloads = [ 507 "cache-management/cacheoptest-riscv64-xs.bin" 508 ] 509 tests = map(lambda x: os.path.join(base_dir, x), workloads) 510 return tests 511 512 def __am_apps_path(self, bench): 513 base_dir = '/nfs/home/share/ci-workloads/nexus-am-workloads/apps' 514 filename = f"{bench}-riscv64-xs.bin" 515 return [os.path.join(base_dir, bench, filename)] 516 517 def __get_ci_workloads(self, name): 518 workloads = { 519 "linux-hello": "bbl.bin", 520 "linux-hello-smp": "bbl.bin", 521 "linux-hello-opensbi": "fw_payload.bin", 522 "linux-hello-smp-opensbi": "fw_payload.bin", 523 "linux-hello-new": "bbl.bin", 524 "linux-hello-smp-new": "bbl.bin", 525 "povray": "_700480000000_.gz", 526 "mcf": "_17520000000_.gz", 527 "xalancbmk": "_266100000000_.gz", 528 "gcc": "_39720000000_.gz", 529 "namd": "_434640000000_.gz", 530 "milc": "_103620000000_.gz", 531 "lbm": "_140840000000_.gz", 532 "gromacs": "_275480000000_.gz", 533 "wrf": "_1916220000000_.gz", 534 "astar": "_122060000000_.gz" 535 } 536 if name in workloads: 537 return [os.path.join("/nfs/home/share/ci-workloads", name, workloads[name])] 538 # select a random SPEC checkpoint 539 assert(name == "random") 540 all_cpt = [ 541 "/nfs-nvme/home/share/checkpoints_profiles/spec06_rv64gcb_o2_20m/take_cpt", 542 "/nfs-nvme/home/share/checkpoints_profiles/spec06_rv64gcb_o3_20m/take_cpt", 543 "/nfs-nvme/home/share/checkpoints_profiles/spec06_rv64gc_o2_20m/take_cpt", 544 "/nfs-nvme/home/share/checkpoints_profiles/spec06_rv64gc_o2_50m/take_cpt", 545 "/nfs-nvme/home/share/checkpoints_profiles/spec17_rv64gcb_o2_20m/take_cpt", 546 "/nfs-nvme/home/share/checkpoints_profiles/spec17_rv64gcb_o3_20m/take_cpt", 547 "/nfs-nvme/home/share/checkpoints_profiles/spec17_rv64gc_o2_50m/take_cpt", 548 "/nfs-nvme/home/share/checkpoints_profiles/spec17_speed_rv64gcb_o3_20m/take_cpt" 549 ] 550 all_json = [ 551 "/nfs-nvme/home/share/checkpoints_profiles/spec06_rv64gcb_o2_20m/json/simpoint_summary.json", 552 "/nfs-nvme/home/share/checkpoints_profiles/spec06_rv64gcb_o3_20m/simpoint_summary.json", 553 "/nfs-nvme/home/share/checkpoints_profiles/spec06_rv64gc_o2_20m/simpoint_summary.json", 554 "/nfs-nvme/home/share/checkpoints_profiles/spec06_rv64gc_o2_50m/simpoint_summary.json", 555 "/nfs-nvme/home/share/checkpoints_profiles/spec17_rv64gcb_o2_20m/simpoint_summary.json", 556 "/nfs-nvme/home/share/checkpoints_profiles/spec17_rv64gcb_o3_20m/simpoint_summary.json", 557 "/nfs-nvme/home/share/checkpoints_profiles/spec17_rv64gc_o2_50m/simpoint_summary.json", 558 "/nfs-nvme/home/share/checkpoints_profiles/spec17_speed_rv64gcb_o3_20m/simpoint_summary.json" 559 ] 560 assert(len(all_cpt) == len(all_json)) 561 cpt_path, json_path = random.choice(list(zip(all_cpt, all_json))) 562 all_gcpt = load_all_gcpt(cpt_path, json_path) 563 return [random.choice(all_gcpt)] 564 565 def run_ci(self, test): 566 all_tests = { 567 "cputest": self.__get_ci_cputest, 568 "riscv-tests": self.__get_ci_rvtest, 569 "misc-tests": self.__get_ci_misc, 570 "mc-tests": self.__get_ci_mc, 571 "nodiff-tests": self.__get_ci_nodiff, 572 "rvh-tests": self.__get_ci_rvhtest, 573 "microbench": self.__am_apps_path, 574 "coremark": self.__am_apps_path, 575 "coremark-1-iteration": self.__am_apps_path, 576 "rvv-bench": self.__get_ci_rvvbench, 577 "rvv-test": self.__get_ci_rvvtest, 578 "f16_test": self.__get_ci_F16test, 579 "zcb-test": self.__get_ci_zcbtest 580 } 581 for target in all_tests.get(test, self.__get_ci_workloads)(test): 582 print(target) 583 ret = self.run_emu(target) 584 if ret: 585 if self.args.default_wave_home != self.args.wave_home: 586 print("copy wave file to " + self.args.wave_home) 587 self.__exec_cmd(f"cp $NOOP_HOME/build/*.vcd $WAVE_HOME") 588 self.__exec_cmd(f"cp $NOOP_HOME/build/emu $WAVE_HOME") 589 self.__exec_cmd(f"cp $NOOP_HOME/build/rtl/SimTop.v $WAVE_HOME") 590 self.__exec_cmd(f"cp $NOOP_HOME/build/*.db $WAVE_HOME") 591 return ret 592 return 0 593 594 def run_ci_vcs(self, test): 595 all_tests = { 596 "cputest": self.__get_ci_cputest, 597 "riscv-tests": self.__get_ci_rvtest, 598 "misc-tests": self.__get_ci_misc, 599 "mc-tests": self.__get_ci_mc, 600 "nodiff-tests": self.__get_ci_nodiff, 601 "rvh-tests": self.__get_ci_rvhtest, 602 "microbench": self.__am_apps_path, 603 "coremark": self.__am_apps_path, 604 "coremark-1-iteration": self.__am_apps_path, 605 "rvv-bench": self.__get_ci_rvvbench, 606 "rvv-test": self.__get_ci_rvvtest, 607 "f16_test": self.__get_ci_F16test, 608 "zcb-test": self.__get_ci_zcbtest 609 } 610 for target in all_tests.get(test, self.__get_ci_workloads)(test): 611 print(target) 612 ret = self.run_simv(target) 613 if ret: 614 if self.args.default_wave_home != self.args.wave_home: 615 print("copy wave file to " + self.args.wave_home) 616 self.__exec_cmd(f"cp $NOOP_HOME/build/*.fsdb $WAVE_HOME") 617 self.__exec_cmd(f"cp $NOOP_HOME/build/simv $WAVE_HOME") 618 self.__exec_cmd(f"cp $NOOP_HOME/build/rtl/SimTop.v $WAVE_HOME") 619 self.__exec_cmd(f"cp $NOOP_HOME/build/*.db $WAVE_HOME") 620 return ret 621 return 0 622 623def get_free_cores(n): 624 numa_re = re.compile(r'.*numactl +.*-C +([0-9]+)-([0-9]+).*') 625 while True: 626 disable_cores = [] 627 for proc in psutil.process_iter(): 628 try: 629 joint = ' '.join(proc.cmdline()) 630 numa_match = numa_re.match(joint) 631 if numa_match and 'ssh' not in proc.name(): 632 disable_cores.extend(range(int(numa_match.group(1)), int(numa_match.group(2)) + 1)) 633 except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess): 634 pass 635 num_logical_core = psutil.cpu_count(logical=False) 636 core_usage = psutil.cpu_percent(interval=1, percpu=True) 637 num_window = num_logical_core // n 638 for i in range(num_window): 639 if set(disable_cores) & set(range(i * n, i * n + n)): 640 continue 641 window_usage = core_usage[i * n : i * n + n] 642 if sum(window_usage) < 30 * n and True not in map(lambda x: x > 90, window_usage): 643 return (((i * n) % num_logical_core) // (num_logical_core // 2), i * n, i * n + n - 1) 644 print(f"No free {n} cores found. CPU usage: {core_usage}\n") 645 time.sleep(random.uniform(1, 60)) 646 647if __name__ == "__main__": 648 parser = argparse.ArgumentParser(description='Python wrapper for XiangShan') 649 parser.add_argument('workload', nargs='?', type=str, default="", 650 help='input workload file in binary format') 651 # actions 652 parser.add_argument('--build', action='store_true', help='build XS emu') 653 parser.add_argument('--generate', action='store_true', help='generate XS verilog') 654 parser.add_argument('--vcs-gen', action='store_true', help='generate XS sim verilog for vcs') 655 parser.add_argument('--vcs-build', action='store_true', help='build XS simv') 656 parser.add_argument('--ci', nargs='?', type=str, const="", help='run CI tests') 657 parser.add_argument('--ci-vcs', nargs='?', type=str, const="", help='run CI tests on simv') 658 parser.add_argument('--clean', action='store_true', help='clean up XiangShan CI workspace') 659 parser.add_argument('--timeout', nargs='?', type=int, default=None, help='timeout (in seconds)') 660 # environment variables 661 parser.add_argument('--nemu', nargs='?', type=str, help='path to nemu') 662 parser.add_argument('--am', nargs='?', type=str, help='path to nexus-am') 663 parser.add_argument('--dramsim3', nargs='?', type=str, help='path to dramsim3') 664 parser.add_argument('--rvtest', nargs='?', type=str, help='path to riscv-tests') 665 parser.add_argument('--wave-dump', nargs='?', type=str , help='path to dump wave') 666 # chisel arguments 667 parser.add_argument('--enable-log', action='store_true', help='enable log') 668 parser.add_argument('--num-cores', type=int, help='number of cores') 669 # makefile arguments 670 parser.add_argument('--release', action='store_true', help='enable release') 671 parser.add_argument('--spike', action='store_true', help='enable spike diff') 672 parser.add_argument('--with-dramsim3', action='store_true', help='enable dramsim3') 673 parser.add_argument('--threads', nargs='?', type=int, help='number of emu threads') 674 parser.add_argument('--trace', action='store_true', help='enable vcd waveform') 675 parser.add_argument('--trace-fst', action='store_true', help='enable fst waveform') 676 parser.add_argument('--config', nargs='?', type=str, help='config') 677 parser.add_argument('--emu-optimize', nargs='?', type=str, help='verilator optimization letter') 678 parser.add_argument('--xprop', action='store_true', help='enable xprop for vcs') 679 # emu arguments 680 parser.add_argument('--numa', action='store_true', help='use numactl') 681 parser.add_argument('--diff', nargs='?', default="./ready-to-run/riscv64-nemu-interpreter-so", type=str, help='nemu so') 682 parser.add_argument('--max-instr', nargs='?', type=int, help='max instr') 683 parser.add_argument('--disable-fork', action='store_true', help='disable lightSSS') 684 parser.add_argument('--no-diff', action='store_true', help='disable difftest') 685 parser.add_argument('--ram-size', nargs='?', type=str, help='manually set simulation memory size (8GB by default)') 686 parser.add_argument('--gcpt-restore-bin', type=str, default="", help="specify the bin used to restore from gcpt") 687 # both makefile and emu arguments 688 parser.add_argument('--no-db', action='store_true', help='disable chiseldb dump') 689 parser.add_argument('--pgo', nargs='?', type=str, help='workload for pgo (null to disable pgo)') 690 parser.add_argument('--pgo-max-cycle', nargs='?', default=400000, type=int, help='maximun cycle to train pgo') 691 parser.add_argument('--pgo-emu-args', nargs='?', default='--no-diff', type=str, help='emu arguments for pgo') 692 parser.add_argument('--llvm-profdata', nargs='?', type=str, help='corresponding llvm-profdata command of clang to compile emu, do not set with GCC') 693 694 args = parser.parse_args() 695 696 xs = XiangShan(args) 697 ret = xs.run(args) 698 699 sys.exit(ret) 700