diff options
| -rw-r--r-- | parse/dir_map.py | 5 | ||||
| -rw-r--r-- | parse/ft.py | 1 | ||||
| -rw-r--r-- | parse/point.py | 4 | ||||
| -rw-r--r-- | parse/sched.py | 6 | ||||
| -rw-r--r-- | parse/tuple_table.py | 5 | ||||
| -rwxr-xr-x | parse_exps.py | 8 | ||||
| -rw-r--r-- | plot/style.py | 20 | ||||
| -rwxr-xr-x | plot_exps.py | 11 |
8 files changed, 41 insertions, 19 deletions
diff --git a/parse/dir_map.py b/parse/dir_map.py index a8d2a83..231d21a 100644 --- a/parse/dir_map.py +++ b/parse/dir_map.py | |||
| @@ -96,7 +96,10 @@ class DirMap(object): | |||
| 96 | return | 96 | return |
| 97 | 97 | ||
| 98 | with open(path, 'rb') as f: | 98 | with open(path, 'rb') as f: |
| 99 | data = np.loadtxt(f, delimiter=",") | 99 | try: |
| 100 | data = np.loadtxt(f, delimiter=",") | ||
| 101 | except Exception as e: | ||
| 102 | raise IOError("Cannot load '%s': %s" % (path, e.message)) | ||
| 100 | 103 | ||
| 101 | # Convert to tuples of ints if possible, else floats | 104 | # Convert to tuples of ints if possible, else floats |
| 102 | values = [map(lambda a:a if a%1 else int(a), t) for t in data] | 105 | values = [map(lambda a:a if a%1 else int(a), t) for t in data] |
diff --git a/parse/ft.py b/parse/ft.py index 98405f4..1f05323 100644 --- a/parse/ft.py +++ b/parse/ft.py | |||
| @@ -71,7 +71,6 @@ def extract_ft_data(result, data_dir, work_dir, cycles): | |||
| 71 | 71 | ||
| 72 | bin_file = "{}/{}".format(data_dir, bins[0]) | 72 | bin_file = "{}/{}".format(data_dir, bins[0]) |
| 73 | if not os.path.getsize(bin_file): | 73 | if not os.path.getsize(bin_file): |
| 74 | sys.stderr.write("Empty feather trace file %s!" % bin_file) | ||
| 75 | return False | 74 | return False |
| 76 | 75 | ||
| 77 | with open("%s/%s" % (work_dir, FT_ERR_NAME), 'w') as err_file: | 76 | with open("%s/%s" % (work_dir, FT_ERR_NAME), 'w') as err_file: |
diff --git a/parse/point.py b/parse/point.py index f2b266a..ac47c70 100644 --- a/parse/point.py +++ b/parse/point.py | |||
| @@ -8,8 +8,8 @@ from enum import Enum | |||
| 8 | from collections import defaultdict | 8 | from collections import defaultdict |
| 9 | 9 | ||
| 10 | Type = Enum(['Min','Max','Avg','Var']) | 10 | Type = Enum(['Min','Max','Avg','Var']) |
| 11 | default_typemap = {Type.Max : {Type.Max : 1, Type.Min : 1, Type.Avg : 1, Type.Var : 1}, | 11 | default_typemap = {Type.Max : {Type.Max : 1, Type.Min : 0, Type.Avg : 0, Type.Var : 0}, |
| 12 | Type.Min : {Type.Max : 1, Type.Min : 1, Type.Avg : 1, Type.Var : 1}, | 12 | Type.Min : {Type.Max : 0, Type.Min : 1, Type.Avg : 0, Type.Var : 0}, |
| 13 | Type.Avg : {Type.Max : 1, Type.Min : 1, Type.Avg : 1, Type.Var : 1}} | 13 | Type.Avg : {Type.Max : 1, Type.Min : 1, Type.Avg : 1, Type.Var : 1}} |
| 14 | 14 | ||
| 15 | def make_typemap(): | 15 | def make_typemap(): |
diff --git a/parse/sched.py b/parse/sched.py index 147a2e5..1213f0d 100644 --- a/parse/sched.py +++ b/parse/sched.py | |||
| @@ -68,7 +68,7 @@ def make_iterator(fname): | |||
| 68 | '''Iterate over (parsed record, processing method) in a | 68 | '''Iterate over (parsed record, processing method) in a |
| 69 | sched-trace file.''' | 69 | sched-trace file.''' |
| 70 | if not os.path.getsize(fname): | 70 | if not os.path.getsize(fname): |
| 71 | sys.stderr.write("Empty sched_trace file %s!" % fname) | 71 | # Likely a release master CPU |
| 72 | return | 72 | return |
| 73 | 73 | ||
| 74 | f = open(fname, 'rb') | 74 | f = open(fname, 'rb') |
| @@ -176,6 +176,10 @@ def extract_sched_data(result, data_dir, work_dir): | |||
| 176 | 176 | ||
| 177 | # Group per-task values | 177 | # Group per-task values |
| 178 | for tdata in task_dict.itervalues(): | 178 | for tdata in task_dict.itervalues(): |
| 179 | if not tdata.params: | ||
| 180 | # Currently unknown where these invalid tasks come from... | ||
| 181 | continue | ||
| 182 | |||
| 179 | miss_ratio = float(tdata.misses.num) / tdata.jobs | 183 | miss_ratio = float(tdata.misses.num) / tdata.jobs |
| 180 | # Scale average down to account for jobs with 0 tardiness | 184 | # Scale average down to account for jobs with 0 tardiness |
| 181 | avg_tard = tdata.misses.avg * miss_ratio | 185 | avg_tard = tdata.misses.avg * miss_ratio |
diff --git a/parse/tuple_table.py b/parse/tuple_table.py index 491ea7b..47fb6b6 100644 --- a/parse/tuple_table.py +++ b/parse/tuple_table.py | |||
| @@ -78,7 +78,7 @@ class ReducedTupleTable(TupleTable): | |||
| 78 | val = kv[col] | 78 | val = kv[col] |
| 79 | 79 | ||
| 80 | try: | 80 | try: |
| 81 | float(val) | 81 | float(str(val)) |
| 82 | except: | 82 | except: |
| 83 | # Only vary numbers. Otherwise, just have seperate files | 83 | # Only vary numbers. Otherwise, just have seperate files |
| 84 | continue | 84 | continue |
| @@ -93,9 +93,6 @@ class ReducedTupleTable(TupleTable): | |||
| 93 | Leaf = namedtuple('Leaf', ['stat', 'variable', 'base', | 93 | Leaf = namedtuple('Leaf', ['stat', 'variable', 'base', |
| 94 | 'summary', 'config', 'values']) | 94 | 'summary', 'config', 'values']) |
| 95 | 95 | ||
| 96 | def next_type(path): | ||
| 97 | return path.pop() if path[-1] in Type else Type.Avg | ||
| 98 | |||
| 99 | def leafs(): | 96 | def leafs(): |
| 100 | for path, node in dir_map.leafs(): | 97 | for path, node in dir_map.leafs(): |
| 101 | # The path will be of at least size 1: the filename | 98 | # The path will be of at least size 1: the filename |
diff --git a/parse_exps.py b/parse_exps.py index 8aa9b43..c254536 100755 --- a/parse_exps.py +++ b/parse_exps.py | |||
| @@ -32,6 +32,9 @@ def parse_args(): | |||
| 32 | parser.add_option('-m', '--write-map', action='store_true', default=False, | 32 | parser.add_option('-m', '--write-map', action='store_true', default=False, |
| 33 | dest='write_map', | 33 | dest='write_map', |
| 34 | help='Output map of values instead of csv tree') | 34 | help='Output map of values instead of csv tree') |
| 35 | parser.add_option('-p', '--processors', default=max(cpu_count() - 1, 1), | ||
| 36 | type='int', dest='processors', | ||
| 37 | help='number of threads for processing') | ||
| 35 | 38 | ||
| 36 | return parser.parse_args() | 39 | return parser.parse_args() |
| 37 | 40 | ||
| @@ -134,7 +137,7 @@ def main(): | |||
| 134 | 137 | ||
| 135 | sys.stderr.write("Parsing data...\n") | 138 | sys.stderr.write("Parsing data...\n") |
| 136 | 139 | ||
| 137 | procs = min(len(exps), max(cpu_count()/2, 1)) | 140 | procs = min(len(exps), opts.processors) |
| 138 | pool = Pool(processes=procs) | 141 | pool = Pool(processes=procs) |
| 139 | pool_args = zip(exps, [opts.force]*len(exps)) | 142 | pool_args = zip(exps, [opts.force]*len(exps)) |
| 140 | enum = pool.imap_unordered(parse_exp, pool_args, 1) | 143 | enum = pool.imap_unordered(parse_exp, pool_args, 1) |
| @@ -161,8 +164,8 @@ def main(): | |||
| 161 | 164 | ||
| 162 | reduced_table = result_table.reduce() | 165 | reduced_table = result_table.reduce() |
| 163 | 166 | ||
| 164 | sys.stderr.write("Writing result...\n") | ||
| 165 | if opts.write_map: | 167 | if opts.write_map: |
| 168 | sys.stderr.write("Writing python map into %s...\n" % opts.out) | ||
| 166 | # Write summarized results into map | 169 | # Write summarized results into map |
| 167 | reduced_table.write_map(opts.out) | 170 | reduced_table.write_map(opts.out) |
| 168 | else: | 171 | else: |
| @@ -177,6 +180,7 @@ def main(): | |||
| 177 | for e in exp: | 180 | for e in exp: |
| 178 | print(e) | 181 | print(e) |
| 179 | else: | 182 | else: |
| 183 | sys.stderr.write("Writing csvs into %s...\n" % opts.out) | ||
| 180 | dir_map.write(opts.out) | 184 | dir_map.write(opts.out) |
| 181 | 185 | ||
| 182 | if __name__ == '__main__': | 186 | if __name__ == '__main__': |
diff --git a/plot/style.py b/plot/style.py index 21c4e7e..4e2057f 100644 --- a/plot/style.py +++ b/plot/style.py | |||
| @@ -7,7 +7,8 @@ class Style(namedtuple('SS', ['marker', 'line', 'color'])): | |||
| 7 | 7 | ||
| 8 | class StyleMap(object): | 8 | class StyleMap(object): |
| 9 | '''Maps configs (dicts) to specific line styles.''' | 9 | '''Maps configs (dicts) to specific line styles.''' |
| 10 | DEFAULT = Style('', '-', 'k') | 10 | DEFAULT = Style(marker='', line= '-', color='k') |
| 11 | ORDER = [ str, bool, float, int ] | ||
| 11 | 12 | ||
| 12 | def __init__(self, col_list, col_values): | 13 | def __init__(self, col_list, col_values): |
| 13 | '''Assign (some) columns in @col_list to fields in @Style to vary, and | 14 | '''Assign (some) columns in @col_list to fields in @Style to vary, and |
| @@ -15,6 +16,17 @@ class StyleMap(object): | |||
| 15 | self.value_map = {} | 16 | self.value_map = {} |
| 16 | self.field_map = {} | 17 | self.field_map = {} |
| 17 | 18 | ||
| 19 | # Prioritize non-numbers | ||
| 20 | def type_priority(column): | ||
| 21 | value = col_values[column].pop() | ||
| 22 | col_values[column].add(value) | ||
| 23 | try: | ||
| 24 | t = float if float(value) % 1.0 else int | ||
| 25 | except: | ||
| 26 | t = bool if value in ['True','False'] else str | ||
| 27 | return StyleMap.ORDER.index(t) | ||
| 28 | col_list = sorted(col_list, key=type_priority) | ||
| 29 | |||
| 18 | # TODO: undo this, switch to popping mechanism | 30 | # TODO: undo this, switch to popping mechanism |
| 19 | for field, values in reversed([x for x in self.__get_all()._asdict().iteritems()]): | 31 | for field, values in reversed([x for x in self.__get_all()._asdict().iteritems()]): |
| 20 | if not col_list: | 32 | if not col_list: |
| @@ -31,9 +43,9 @@ class StyleMap(object): | |||
| 31 | 43 | ||
| 32 | def __get_all(self): | 44 | def __get_all(self): |
| 33 | '''A Style holding all possible values for each property.''' | 45 | '''A Style holding all possible values for each property.''' |
| 34 | return Style(list('.,ov^<>1234sp*hH+xDd|_'), # markers | 46 | return Style(marker=list('.,ov^<>1234sp*hH+xDd|_'), |
| 35 | ['-', ':', '--'], # lines | 47 | line=['-', ':', '--'], |
| 36 | list('bgrcmyk')) # colors | 48 | color=list('bgrcmyk')) |
| 37 | 49 | ||
| 38 | def get_style(self, kv): | 50 | def get_style(self, kv): |
| 39 | '''Translate column values to unique line style.''' | 51 | '''Translate column values to unique line style.''' |
diff --git a/plot_exps.py b/plot_exps.py index 3b5636b..76e7396 100755 --- a/plot_exps.py +++ b/plot_exps.py | |||
| @@ -7,11 +7,11 @@ import shutil as sh | |||
| 7 | import sys | 7 | import sys |
| 8 | import traceback | 8 | import traceback |
| 9 | from collections import namedtuple | 9 | from collections import namedtuple |
| 10 | from multiprocessing import Pool, cpu_count | ||
| 10 | from optparse import OptionParser | 11 | from optparse import OptionParser |
| 11 | from parse.col_map import ColMap,ColMapBuilder | 12 | from parse.col_map import ColMap,ColMapBuilder |
| 12 | from parse.dir_map import DirMap | 13 | from parse.dir_map import DirMap |
| 13 | from plot.style import StyleMap | 14 | from plot.style import StyleMap |
| 14 | from multiprocessing import Pool, cpu_count | ||
| 15 | 15 | ||
| 16 | def parse_args(): | 16 | def parse_args(): |
| 17 | parser = OptionParser("usage: %prog [options] [csv_dir]...") | 17 | parser = OptionParser("usage: %prog [options] [csv_dir]...") |
| @@ -20,6 +20,9 @@ def parse_args(): | |||
| 20 | help='directory for plot output', default='plot-data') | 20 | help='directory for plot output', default='plot-data') |
| 21 | parser.add_option('-f', '--force', action='store_true', default=False, | 21 | parser.add_option('-f', '--force', action='store_true', default=False, |
| 22 | dest='force', help='overwrite existing data') | 22 | dest='force', help='overwrite existing data') |
| 23 | parser.add_option('-p', '--processors', default=max(cpu_count() - 1, 1), | ||
| 24 | type='int', dest='processors', | ||
| 25 | help='number of threads for processing') | ||
| 23 | 26 | ||
| 24 | return parser.parse_args() | 27 | return parser.parse_args() |
| 25 | 28 | ||
| @@ -97,7 +100,7 @@ def plot_wrapper(details): | |||
| 97 | except: | 100 | except: |
| 98 | traceback.print_exc() | 101 | traceback.print_exc() |
| 99 | 102 | ||
| 100 | def plot_dir(data_dir, out_dir, force): | 103 | def plot_dir(data_dir, out_dir, max_procs, force): |
| 101 | sys.stderr.write("Reading data...\n") | 104 | sys.stderr.write("Reading data...\n") |
| 102 | dir_map = DirMap.read(data_dir) | 105 | dir_map = DirMap.read(data_dir) |
| 103 | 106 | ||
| @@ -119,7 +122,7 @@ def plot_dir(data_dir, out_dir, force): | |||
| 119 | if not plot_details: | 122 | if not plot_details: |
| 120 | return | 123 | return |
| 121 | 124 | ||
| 122 | procs = min(len(plot_details), max(cpu_count()/2, 1)) | 125 | procs = min(len(plot_details), max_procs) |
| 123 | pool = Pool(processes=procs) | 126 | pool = Pool(processes=procs) |
| 124 | enum = pool.imap_unordered(plot_wrapper, plot_details) | 127 | enum = pool.imap_unordered(plot_wrapper, plot_details) |
| 125 | 128 | ||
| @@ -150,7 +153,7 @@ def main(): | |||
| 150 | out_dir = "%s/%s" % (opts.out_dir, os.path.split(dir)[1]) | 153 | out_dir = "%s/%s" % (opts.out_dir, os.path.split(dir)[1]) |
| 151 | else: | 154 | else: |
| 152 | out_dir = opts.out_dir | 155 | out_dir = opts.out_dir |
| 153 | plot_dir(dir, out_dir, opts.force) | 156 | plot_dir(dir, out_dir, opts.processors, opts.force) |
| 154 | 157 | ||
| 155 | if __name__ == '__main__': | 158 | if __name__ == '__main__': |
| 156 | main() | 159 | main() |
