source: benchmark/rmit.py @ 836c992

arm-ehjacob/cs343-translationnew-ast-unique-expr
Last change on this file since 836c992 was 836c992, checked in by Thierry Delisle <tdelisle@…>, 12 months ago

Minor fixes to rmit in case keys differ

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