diff options
Diffstat (limited to 'wsched.py')
-rwxr-xr-x | wsched.py | 185 |
1 files changed, 185 insertions, 0 deletions
diff --git a/wsched.py b/wsched.py new file mode 100755 index 0000000..8214bf0 --- /dev/null +++ b/wsched.py | |||
@@ -0,0 +1,185 @@ | |||
1 | #!/usr/bin/env python | ||
2 | |||
3 | import defapp | ||
4 | from optparse import make_option as o | ||
5 | from os.path import splitext, basename | ||
6 | |||
7 | import sys | ||
8 | |||
9 | from util import load_csv_file | ||
10 | |||
11 | def split_rows(rows, key_col): | ||
12 | by_key_col = {} | ||
13 | key_order = [] | ||
14 | |||
15 | # hash each row according by its key | ||
16 | for r in rows: | ||
17 | key = r[key_col] | ||
18 | if not key in by_key_col: | ||
19 | key_order.append(key) | ||
20 | by_key_col[key] = [] | ||
21 | by_key_col[key].append(r) | ||
22 | |||
23 | return (by_key_col, key_order) | ||
24 | |||
25 | |||
26 | def group(rows, key_col): | ||
27 | (by, order) = split_rows(rows, key_col) | ||
28 | for k in order: | ||
29 | yield (k, by[k]) | ||
30 | |||
31 | def aggregate_column(rows, key_col, aggregate_fun): | ||
32 | by_key, order = split_rows(rows, key_col) | ||
33 | for key in order: | ||
34 | yield aggregate_fun(by_key[key]) | ||
35 | |||
36 | |||
37 | def weighted_schedulability(data, key_col, ucap_col): | ||
38 | def wsched(rows): | ||
39 | # Every column except for the key_col and the ucap_col | ||
40 | # is presumed to be schedulability values. | ||
41 | key = rows[0][key_col] | ||
42 | cols = len(rows[0]) | ||
43 | accum = [0.0 for _ in xrange(cols)] | ||
44 | norm = 0.0 | ||
45 | umax = 0.0 | ||
46 | for r in rows: | ||
47 | ucap = r[ucap_col] | ||
48 | umax = max(ucap, umax) | ||
49 | norm += ucap | ||
50 | for i, val in enumerate(r): | ||
51 | if i != key_col and i != ucap_col: | ||
52 | accum[i] += ucap * val | ||
53 | return [(accum[i] / norm) if i != key_col and i != ucap_col | ||
54 | else (key if i == key_col else umax) for i in xrange(cols)] | ||
55 | |||
56 | return aggregate_column(data, key_col, wsched) | ||
57 | |||
58 | |||
59 | def print_row(row, out, fmt): | ||
60 | out.write(", ".join(fmt % d for d in row)) | ||
61 | out.write("\n") | ||
62 | |||
63 | def filter_wsched(fname, key, ucap, out=sys.stdout, fmt="%10.3f"): | ||
64 | data = load_csv_file(fname, dtype=float) | ||
65 | for row in weighted_schedulability(data, key, ucap): | ||
66 | print_row(row, out, fmt) | ||
67 | out.flush() | ||
68 | |||
69 | def filter_comments(fname, is_comment=lambda line: line and line[0] == '#', | ||
70 | out=sys.stdout): | ||
71 | f = open(fname, 'r') | ||
72 | for line in f: | ||
73 | if is_comment(line): | ||
74 | out.write(line) | ||
75 | out.flush() | ||
76 | f.close() | ||
77 | |||
78 | options = [ | ||
79 | # output options | ||
80 | o('-o', '--output-prefix', action='store', dest='prefix'), | ||
81 | o('-k', '--key-column', action='store', type='int', dest='keycol'), | ||
82 | o('-u', '--ucap-column', action='store', type='int', dest='ucol'), | ||
83 | o(None, '--no-comments', action='store_true', dest='no_comments'), | ||
84 | o('-w', '--col-width', action='store', type='int', dest='colwidth'), | ||
85 | o(None, '--split', action='store_true', dest='want_split'), | ||
86 | ] | ||
87 | |||
88 | defaults = { | ||
89 | 'prefix' : None, | ||
90 | 'keycol' : 0, | ||
91 | 'ucol' : 1, | ||
92 | 'no_comments' : False, | ||
93 | 'colwidth' : 10, | ||
94 | 'precision' : 3, | ||
95 | 'indent' : 2, | ||
96 | 'key_fmt' : "_key=%d", | ||
97 | 'want_split' : False, | ||
98 | } | ||
99 | |||
100 | |||
101 | class WschedFilter(defapp.App): | ||
102 | def __init__(self): | ||
103 | defapp.App.__init__(self, options, defaults, no_std_opts=True) | ||
104 | self.out = sys.stdout | ||
105 | |||
106 | |||
107 | def filter_wsched(self, fname, out=sys.stdout): | ||
108 | data = load_csv_file(fname, dtype=float) | ||
109 | for row in weighted_schedulability( | ||
110 | data, self.options.keycol, self.options.ucol): | ||
111 | out.write(" " * self.options.indent) | ||
112 | out.write(", ".join(self.fmt % d for d in row)) | ||
113 | out.write("\n") | ||
114 | out.flush() | ||
115 | |||
116 | def target_name(self, fname, extra=None): | ||
117 | bname = basename(fname) | ||
118 | if extra: | ||
119 | bname, ext = splitext(bname) | ||
120 | bname = "%s%s%s" % (bname, extra, ext) | ||
121 | return self.options.prefix + bname | ||
122 | |||
123 | def filter_file(self, fin, fout=None): | ||
124 | out = open(fout, 'w') if fout else sys.stdout | ||
125 | if not self.options.no_comments: | ||
126 | filter_comments(fin, out=out) | ||
127 | self.filter_wsched(fin, out=out) | ||
128 | if fout: | ||
129 | out.close() | ||
130 | |||
131 | def write_split(self, fin, fout, rows): | ||
132 | out = open(fout, 'w') | ||
133 | if not self.options.no_comments: | ||
134 | filter_comments(fin, out=out) | ||
135 | for r in rows: | ||
136 | print_row(r, out, self.fmt) | ||
137 | out.close() | ||
138 | |||
139 | def split_file(self, fname): | ||
140 | data = load_csv_file(fname, dtype=float) | ||
141 | for (key, rows) in group(data, self.options.keycol): | ||
142 | fout = self.target_name(fname, self.options.key_fmt % key) | ||
143 | print '\t->', fout | ||
144 | self.write_split(fname, fout, rows) | ||
145 | |||
146 | def wsched(self, _): | ||
147 | if self.options.prefix: | ||
148 | for i, datafile in enumerate(self.args): | ||
149 | fout = self.target_name(datafile) | ||
150 | print "[%d/%d] %s -> %s" % \ | ||
151 | (i + 1, len(self.args), datafile, fout) | ||
152 | try: | ||
153 | self.filter_file(datafile, fout) | ||
154 | except IOError as ioe: | ||
155 | sys.stderr.write("[!!] ") | ||
156 | sys.stderr.write(str(ioe)) | ||
157 | sys.stderr.write("\n") | ||
158 | else: | ||
159 | for fname in self.args: | ||
160 | self.filter_file(fname) | ||
161 | |||
162 | def split(self, _): | ||
163 | if self.options.prefix: | ||
164 | for i, datafile in enumerate(self.args): | ||
165 | print "[%d/%d] Splitting %s..." % \ | ||
166 | (i + 1, len(self.args), datafile) | ||
167 | try: | ||
168 | self.split_file(datafile) | ||
169 | except IOError as ioe: | ||
170 | sys.stderr.write("[!!] ") | ||
171 | sys.stderr.write(str(ioe)) | ||
172 | sys.stderr.write("\n") | ||
173 | else: | ||
174 | print "split: requires output prefix (-o)." | ||
175 | |||
176 | def default(self, _): | ||
177 | self.fmt = "%%%d.%df" % (self.options.colwidth, self.options.precision) | ||
178 | if self.options.want_split: | ||
179 | self.split(_) | ||
180 | else: | ||
181 | self.wsched(_) | ||
182 | |||
183 | if __name__ == '__main__': | ||
184 | WschedFilter().launch() | ||
185 | |||