diff options
| author | Björn B. Brandenburg <bbb@cs.unc.edu> | 2010-10-09 22:01:02 -0400 |
|---|---|---|
| committer | Björn B. Brandenburg <bbb@cs.unc.edu> | 2010-10-09 22:01:02 -0400 |
| commit | 5c0c56cbb9ee7e983275d016d9d95da6e175760b (patch) | |
| tree | 2696a0c40c2f80c21482fb02c8e33369ab942215 | |
| parent | 58a0ab886ec6a9647a8ee4f5639d21ef8e7bbed8 (diff) | |
add utility to aggregate and split weighted schedulability experiments
| -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 | |||
