source: benchmark/rmit.py @ b39e6566

ADTarm-ehast-experimentalenumforall-pointer-decayjacob/cs343-translationnew-ast-unique-exprpthread-emulationqualifiedEnum
Last change on this file since b39e6566 was af333e3, checked in by Thierry Delisle <tdelisle@…>, 4 years ago

Dropped support for raw/csv format in rmit script.
Json output is now formated as the programs run rather than at the end.
Extra options no longer need the -o prefix

  • Property mode set to 100755
File size: 6.0 KB
Line 
1#!/usr/bin/python3
2"""
3Python Script to implement R.M.I.T. testing : Randomized Multiple Interleaved Trials
4
5./rmit.py run COMMAND CANDIDATES
6-t trials
7-o option:values
8"""
9
10
11import argparse
12import datetime
13import itertools
14import json
15import os
16import random
17import re
18import subprocess
19import sys
20
21
22def parse_range(x):
23    result = []
24    for part in x.split(','):
25        if '-' in part:
26            a, b = part.split('-')
27            a, b = int(a), int(b)
28            result.extend(range(a, b + 1))
29        else:
30            a = int(part)
31            result.append(a)
32    return result
33
34class DependentOpt:
35        def __init__(self, key, value):
36                self.key = key
37                self.value = value
38                self.vars = re.findall("[a-zA-Z]", value)
39
40def parse_option(key, values):
41        try:
42                num = int(values)
43                return key, [num]
44        except:
45                pass
46
47        if re.search("^[0-9-,]+$", values):
48                values = parse_range(values)
49                return key, [v for v in values]
50        else:
51                return key, DependentOpt(key, values)
52
53def eval_one(fmt, vals):
54        orig = fmt
55        for k, v in vals:
56                fmt = fmt.replace(k, str(v))
57
58        if not re.search("^[0-9-/*+ ]+$", fmt):
59                print('ERROR: pattern option {} (interpreted as {}) could not be evaluated'.format(orig, fmt), file=sys.stderr)
60                sys.exit(1)
61
62        return eval(fmt)
63
64def eval_options(opts):
65        dependents = [d for d in opts.values() if type(d) is DependentOpt]
66        processed = []
67        nopts = []
68        for d in dependents:
69                processed.append(d.key)
70                lists = []
71                for dvar in d.vars:
72                        if not dvar in opts.keys():
73                                print('ERROR: extra pattern option {}:{} uses unknown key {}'.format(d.key,d.value,dvar), file=sys.stderr)
74                                sys.exit(1)
75
76                        lists.append([(dvar, o) for o in opts[dvar]])
77                        processed.append(dvar)
78
79                kopt = []
80                for vals in list(itertools.product(*lists)):
81                        res = ['-{}'.format(d.key), "{}".format(eval_one(d.value, vals))]
82                        for k, v in vals:
83                                res.extend(['-{}'.format(k), "{}".format(v)])
84                        kopt.append(res)
85                nopts.append(kopt)
86
87
88        for k, vals in opts.items():
89                if k not in processed:
90                        kopt = []
91                        for v in vals:
92                                kopt.append(['-{}'.format(k), "{}".format(v)])
93                        nopts.append(kopt)
94
95        return nopts
96
97def actions_eta(actions):
98        time = 0
99        for a in actions:
100                i = 0
101                while i < len(a):
102                        if a[i] == '-d':
103                                i += 1
104                                if i != len(a):
105                                        time += int(a[i])
106                        i += 1
107        return time
108
109if __name__ == "__main__":
110        # ================================================================================
111        # parse command line arguments
112        formats = ['raw', 'csv', 'json']
113        parser = argparse.ArgumentParser(description='Python Script to implement R.M.I.T. testing : Randomized Multiple Interleaved Trials')
114        parser.add_argument('--list', help='List all the commands that would be run', action='store_true')
115        parser.add_argument('--file', nargs='?', type=argparse.FileType('w'), default=sys.stdout)
116        parser.add_argument('--trials', help='Number of trials to run per combinaison', type=int, default=3)
117        parser.add_argument('command', metavar='command', type=str, nargs=1, help='the command prefix to run')
118        parser.add_argument('candidates', metavar='candidates', type=str, nargs='*', help='the candidate suffix to run')
119
120        try:
121                options, unknown =  parser.parse_known_args()
122
123                options.option = []
124                while unknown:
125                        key = unknown.pop(0)
126                        val = unknown.pop(0)
127
128                        if key[0] != '-':
129                                raise ValueError
130
131                        options.option.append((key[1:], val))
132
133        except:
134                print('ERROR: invalid arguments', file=sys.stderr)
135                parser.print_help(sys.stderr)
136                sys.exit(1)
137
138        # ================================================================================
139        # Identify the commands to run
140        commands = ["./" + options.command[0] + "-" + c for c in options.candidates]
141        for c in commands:
142                if not os.path.isfile(c):
143                        print('ERROR: invalid command {}, file does not exist'.format(c), file=sys.stderr)
144                        sys.exit(1)
145
146                if not os.access(c, os.X_OK):
147                        print('ERROR: invalid command {}, file not executable'.format(c), file=sys.stderr)
148                        sys.exit(1)
149
150
151        # ================================================================================
152        # Identify the options to run
153        opts = dict([parse_option(k, v) for k, v in options.option])
154
155        # Evaluate the options (options can depend on the value of other options)
156        opts = eval_options(opts)
157
158        # ================================================================================
159        # Figure out all the combinations to run
160        actions = []
161        for p in itertools.product(range(options.trials), commands, *opts):
162                act = [p[1]]
163                for o in p[2:]:
164                        act.extend(o)
165                actions.append(act)
166
167        # ================================================================================
168        # Figure out all the combinations to run
169        if options.list:
170                for a in actions:
171                        print(" ".join(a))
172                sys.exit(0)
173
174
175        # ================================================================================
176        # Prepare to run
177
178        # find expected time
179        time = actions_eta(actions)
180        print("Running {} trials{}".format(len(actions), "" if time == 0 else " (expecting to take {})".format(str(datetime.timedelta(seconds=int(time)))) ))
181
182        random.shuffle(actions)
183
184        # ================================================================================
185        # Run
186        options.file.write("[")
187        first = True
188        for i, a in enumerate(actions):
189                sa = " ".join(a)
190                if first:
191                        first = False
192                else:
193                        options.file.write(",")
194                if options.file != sys.stdout:
195                        print("{}/{} : {}          \r".format(i, len(actions), sa), end = '')
196                fields = {}
197                with subprocess.Popen( a, stdout  = subprocess.PIPE, stderr  = subprocess.PIPE) as proc:
198                        out, err = proc.communicate()
199                        if proc.returncode != 0:
200                                print("ERROR: command '{}' encountered error, returned code {}".format(sa, proc.returncode), file=sys.stderr)
201                                print(err.decode("utf-8"))
202                                sys.exit(1)
203                        for s in out.decode("utf-8").splitlines():
204                                match = re.search("^(.*):(.*)$", s)
205                                if match:
206                                        fields[match.group(1).strip()] = float(match.group(2).strip().replace(',',''))
207
208                options.file.write(json.dumps([a[0][2:], sa, fields]))
209                options.file.flush()
210
211        options.file.write("]\n")
212
213        if options.file != sys.stdout:
214                print("Done                                                                                ")
Note: See TracBrowser for help on using the repository browser.