aboutsummaryrefslogtreecommitdiffstats
path: root/parse_exps.py
blob: 1f36babb6c66eb371958ab6cb0d05f3f4cb04fa7 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#!/usr/bin/env python
from __future__ import print_function

import config.config as conf
import copy
import os
import parse.ft as ft
import parse.sched as st
import re
import shutil as sh

from collections import namedtuple
from common import load_params
from optparse import OptionParser
from parse.point import ExpPoint
from parse.tuple_table import ColMap,TupleTable

def parse_args():
    parser = OptionParser("usage: %prog [options] [data_dir]...")

    parser.add_option('-o', '--out-dir', dest='out_dir',
                      help='directory for data output', default='parse-data')
    parser.add_option('-c', '--clean', action='store_true', default=False,
                      dest='clean', help='do not output single-point csvs')
    parser.add_option('-s', '--scale-against', dest='scale_against',
                      metavar='PARAM=VALUE', default="",
                      help='calculate task scaling factors against these configs')
    parser.add_option('-f', '--force', action='store_true', default=False,
                      dest='force', help='overwrite existing data')
    parser.add_option('-v', '--verbose', action='store_true', default=False,
                      dest='verbose', help='print out data points')

    return parser.parse_args()

ExpData   = namedtuple('ExpData', ['name', 'params', 'data_files'])
DataFiles = namedtuple('DataFiles', ['ft','st'])

def get_exp_params(data_dir, col_map):
    param_file = "%s/%s" % (data_dir, conf.DEFAULTS['params_file'])
    if not os.path.isfile:
        raise Exception("No param file '%s' exists!" % param_file)

    # Keep only params that uniquely identify the experiment
    params = load_params(param_file)
    for ignored in conf.PARAMS.itervalues():
        if ignored in params:
            params.pop(ignored)

    # Track all changed params
    for key in params.keys():
        col_map.try_add(key)

    return params


def gen_exp_data(exp_dirs, base_conf, col_map, force):
    plain_exps = []
    scaling_bases  = []

    for data_dir in exp_dirs:
        if not os.path.isdir(data_dir):
            raise IOError("Invalid experiment '%s'" % os.path.abspath(data_dir))

        tmp_dir = data_dir + "/tmp"
        if not os.path.exists(tmp_dir):
            os.mkdir(tmp_dir)

        # Read and translate exp output files
        params = get_exp_params(data_dir, col_map)
        st_output = st.get_st_output(data_dir, tmp_dir, force)
        ft_output = ft.get_ft_output(data_dir, tmp_dir, force)

        # Create experiment named after the data dir
        exp_data = ExpData(data_dir, params, DataFiles(ft_output, st_output))

        if base_conf and base_conf.viewitems() & params.viewitems():
            if not st_output:
                raise Exception("Scaling base '%s' useless without sched data!"
                                % data_dir)
            params.pop(base_conf.keys()[0])
            scaling_bases += [exp_data]
        else:
            plain_exps += [exp_data]

    return (plain_exps, scaling_bases)

def main():
    opts, args = parse_args()

    args = args or [os.getcwd()]

    # Configuration key for task systems used to calculate task
    # execution scaling factors
    base_conf = dict(re.findall("(.*)=(.*)", opts.scale_against))

    col_map = ColMap()

    (plain_exps, scaling_bases) = gen_exp_data(args, base_conf, col_map, opts.force)

    if base_conf and base_conf.keys()[0] not in col_map:
        raise IOError("Base column '%s' not present in any parameters!" %
                      base_conf.keys()[0])

    base_table   = TupleTable(col_map)
    result_table = TupleTable(col_map)

    # Used to find matching scaling_base for each experiment
    for base in scaling_bases:
        base_table.add_exp(base.params, base)

    for exp in plain_exps:
        result = ExpPoint(exp.name)

        if exp.data_files.ft:
            # Write overheads into result
            ft.extract_ft_data(exp.data_files.ft, result, conf.BASE_EVENTS)

        if exp.data_files.st:
            base = None
            if base_conf:
                # Try to find a scaling base
                base_params = copy.deepcopy(exp.params)
                base_params.pop(base_conf.keys()[0])
                base = base_table.get_exps(base_params)[0]
            # Write deadline misses / tardiness into result
            st.extract_sched_data(exp.data_files.st, result,
                                  base.data_files.st if base else None)

        result_table.add_exp(exp.params, result)

        if opts.verbose:
            print(result)

    if opts.force and os.path.exists(opts.out_dir):
        sh.rmtree(opts.out_dir)

    # Remove un-plottable values
    if opts.clean:
        result_table.reduce()

    result_table.write_result(opts.out_dir)

if __name__ == '__main__':
    main()