1#!/usr/bin/env python
2
3# Copyright (c) 2018, Cornell University
4# All rights reserved.
5#
6# Redistribution and use in source and binary forms, with or
7# without modification, are permitted provided that the following
8# conditions are met:
9#
10# Redistributions of source code must retain the above copyright
11# notice, this list of conditions and the following disclaimer.
12#
13# Redistributions in binary form must reproduce the above
14# copyright notice, this list of conditions and the following
15# disclaimer in the documentation and/or other materials provided
16# with the distribution.
17#
18# Neither the name of Cornell University nor the names of its
19# contributors may be used to endorse or promote products derived
20# from this software without specific prior written permission.
21#
22# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
23# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
24# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
27# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
30# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
31# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34# POSSIBILITY OF SUCH DAMAGE.
35#
36# Authors: Tuan Ta
37
38import os
39import sys
40import argparse
41import subprocess
42
43from multiprocessing import Pool
44
45import clusterjob
46from clusterjob import *
47
48#-------------------------------------------------------------------------
49# utility function to run a process
50#-------------------------------------------------------------------------
51def execute(cmd):
52  try:
53    return subprocess.check_output(cmd, shell=True)
54  except subprocess.CalledProcessError, err:
55    print "ERROR: " + err.output
56
57#-------------------------------------------------------------------------
58# Input options
59#-------------------------------------------------------------------------
60
61# general options
62parser = argparse.ArgumentParser(description='run RISC-V assembly tests')
63parser.add_argument('--max-tick',
64                    help = 'maximum simulated tick',
65                    type = int,
66                    default = 10000000000)
67parser.add_argument('--num-cpus',
68                    help = 'number of CPUs\
69                            (some tests require at least 4 CPUs)',
70                    type = int,
71                    default = 4)
72parser.add_argument('--ruby',
73                    help = 'Use Ruby memory?',
74                    action = 'store_true')
75
76args = parser.parse_args()
77
78# convert all paths to absolute paths
79test_dir = os.path.abspath('../../bin/riscv/')
80test_summary_out = './test-summary.out'
81
82#-------------------------------------------------------------------------
83# gem5 variables
84#-------------------------------------------------------------------------
85gem5_dir = os.path.abspath('../../../../../')
86gem5_bin = os.path.join(gem5_dir, 'build', 'RISCV', 'gem5.opt')
87config = os.path.join(gem5_dir, 'configs', 'example', 'se.py')
88
89# list of CPU models to be tested
90cpu_models = ['AtomicSimpleCPU',
91              'TimingSimpleCPU',
92              'MinorCPU',
93              'DerivO3CPU']
94
95# get a list of test binaries in the given directory
96tests = []
97for line in execute("ls %s/*" % (test_dir)).splitlines():
98  if line:
99    tests.append(line.split('/')[-1])
100
101# total number of tests to run
102n_tests = len(tests) * len(cpu_models)
103
104# make a list of jobs
105job_cmds = []
106job_names = []
107for test in tests:
108  for model in cpu_models:
109    test_name = test + '-' + model
110    job_names.append(test_name)
111    job_cmds.append([gem5_bin,
112                     config,
113                     '-m', str(args.max_tick),
114                     '--cpu-type', model,
115                     '-n', str(args.num_cpus),
116                     '-c', test_dir + '/' + test,
117                     '--ruby' if args.ruby else '--caches',
118                    ])
119
120# execute all jobs
121job_pool = Pool(processes = n_tests)
122job_outputs = job_pool.map(subprocess.call, job_cmds)
123job_pool.close()
124
125# process job outputs
126file = open(test_summary_out, "w")
127
128job_outputs = zip(job_names, job_outputs)
129for entry in job_outputs:
130  # a negative return value indicates that the job was terminated
131  # by a signal
132  # a positive return value indicates that the job exited with a return
133  # value
134  if entry[1] < 0:
135    file.write("%-50s failed - signal = %d\n" % (entry[0], -1 * entry[1]))
136  elif entry[1] > 0:
137    file.write("%-50s failed - status = %d\n" % (entry[0], entry[1]))
138  else:
139    file.write("%-50s passed\n" % (entry[0]))
140
141file.close()
142