diff options
-rw-r--r-- | common.py | 51 | ||||
-rw-r--r-- | config/config.py | 5 | ||||
-rw-r--r-- | gen/generator.py | 5 | ||||
-rw-r--r-- | parse/dir_map.py | 3 | ||||
-rw-r--r-- | parse/ft.py | 2 | ||||
-rw-r--r-- | parse/point.py | 3 | ||||
-rwxr-xr-x | parse_exps.py | 35 | ||||
-rw-r--r-- | run/executable/executable.py | 2 | ||||
-rw-r--r-- | run/litmus_util.py | 50 | ||||
-rw-r--r-- | run/tracer.py | 10 | ||||
-rwxr-xr-x | run_exps.py | 9 |
11 files changed, 92 insertions, 83 deletions
@@ -1,5 +1,6 @@ | |||
1 | import os | 1 | import os |
2 | import re | 2 | import re |
3 | import stat | ||
3 | import subprocess | 4 | import subprocess |
4 | import sys | 5 | import sys |
5 | 6 | ||
@@ -134,3 +135,53 @@ def load_params(fname): | |||
134 | raise IOError("Invalid param file: %s\n%s" % (fname, e)) | 135 | raise IOError("Invalid param file: %s\n%s" % (fname, e)) |
135 | 136 | ||
136 | return params | 137 | return params |
138 | |||
139 | |||
140 | def num_cpus(): | ||
141 | '''Return the number of CPUs in the system.''' | ||
142 | |||
143 | lnx_re = re.compile(r'^(processor|online)') | ||
144 | cpus = 0 | ||
145 | |||
146 | with open('/proc/cpuinfo', 'r') as f: | ||
147 | for line in f: | ||
148 | if lnx_re.match(line): | ||
149 | cpus += 1 | ||
150 | return cpus | ||
151 | |||
152 | def ft_freq(): | ||
153 | umachine = subprocess.check_output(["uname", "-m"]) | ||
154 | |||
155 | if re.match("armv7", umachine): | ||
156 | # Arm V7s use a millisecond timer | ||
157 | freq = 1000.0 | ||
158 | elif re.match("x86", umachine): | ||
159 | # X86 timer is equal to processor clock | ||
160 | reg = re.compile(r'^cpu MHz\s*:\s*(?P<FREQ>\d+)', re.M) | ||
161 | with open('/proc/cpuinfo', 'r') as f: | ||
162 | data = f.read() | ||
163 | |||
164 | match = re.search(reg, data) | ||
165 | if not match: | ||
166 | raise Exception("Cannot parse CPU frequency from x86 CPU!") | ||
167 | freq = int(match.group('FREQ')) | ||
168 | else: | ||
169 | # You're on your own | ||
170 | freq = 0 | ||
171 | return freq | ||
172 | |||
173 | |||
174 | def uname_matches(reg): | ||
175 | data = subprocess.check_output(["uname", "-r"]) | ||
176 | return bool( re.match(reg, data) ) | ||
177 | |||
178 | def is_executable(fname): | ||
179 | '''Return whether the file passed in is executable''' | ||
180 | mode = os.stat(fname)[stat.ST_MODE] | ||
181 | return mode & stat.S_IXUSR and mode & stat.S_IRUSR | ||
182 | |||
183 | def is_device(dev): | ||
184 | if not os.path.exists(dev): | ||
185 | return False | ||
186 | mode = os.stat(dev)[stat.ST_MODE] | ||
187 | return not (not mode & stat.S_IFCHR) | ||
diff --git a/config/config.py b/config/config.py index 1199278..a6edece 100644 --- a/config/config.py +++ b/config/config.py | |||
@@ -1,6 +1,6 @@ | |||
1 | from __future__ import print_function | 1 | from __future__ import print_function |
2 | import itertools | 2 | import itertools |
3 | from common import get_executable | 3 | from common import get_executable,ft_freq |
4 | 4 | ||
5 | '''Paths to binaries.''' | 5 | '''Paths to binaries.''' |
6 | BINS = {'rtspin' : get_executable('rtspin', 'liblitmus'), | 6 | BINS = {'rtspin' : get_executable('rtspin', 'liblitmus'), |
@@ -16,6 +16,7 @@ BINS = {'rtspin' : get_executable('rtspin', 'liblitmus'), | |||
16 | 16 | ||
17 | '''Names of output files.''' | 17 | '''Names of output files.''' |
18 | FILES = {'ft_data' : 'ft.bin', | 18 | FILES = {'ft_data' : 'ft.bin', |
19 | 'ft_matches' : r'(ft.*\.bin)|(.*\.ft)', | ||
19 | 'linux_data' : 'trace.dat', | 20 | 'linux_data' : 'trace.dat', |
20 | 'sched_data' : 'st-{}.bin', | 21 | 'sched_data' : 'st-{}.bin', |
21 | 'log_data' : 'trace.slog'} | 22 | 'log_data' : 'trace.slog'} |
@@ -34,7 +35,7 @@ DEFAULTS = {'params_file' : 'params.py', | |||
34 | 'sched_file' : 'sched.py', | 35 | 'sched_file' : 'sched.py', |
35 | 'duration' : 10, | 36 | 'duration' : 10, |
36 | 'spin' : 'rtspin', | 37 | 'spin' : 'rtspin', |
37 | 'cycles' : 2000} | 38 | 'cycles' : ft_freq() or 2000} |
38 | 39 | ||
39 | '''Default sched_trace events (this is all of them).''' | 40 | '''Default sched_trace events (this is all of them).''' |
40 | SCHED_EVENTS = range(501, 513) | 41 | SCHED_EVENTS = range(501, 513) |
diff --git a/gen/generator.py b/gen/generator.py index dbf2a7b..8c3048b 100644 --- a/gen/generator.py +++ b/gen/generator.py | |||
@@ -1,11 +1,10 @@ | |||
1 | import gen.rv as rv | 1 | import gen.rv as rv |
2 | import os | 2 | import os |
3 | import run.litmus_util as lu | ||
4 | import shutil as sh | 3 | import shutil as sh |
5 | 4 | ||
6 | from Cheetah.Template import Template | 5 | from Cheetah.Template import Template |
7 | from collections import namedtuple | 6 | from collections import namedtuple |
8 | from common import get_config_option | 7 | from common import get_config_option,num_cpus |
9 | from config.config import DEFAULTS,PARAMS | 8 | from config.config import DEFAULTS,PARAMS |
10 | from gen.dp import DesignPointGenerator | 9 | from gen.dp import DesignPointGenerator |
11 | from parse.col_map import ColMapBuilder | 10 | from parse.col_map import ColMapBuilder |
@@ -69,7 +68,7 @@ class Generator(object): | |||
69 | if 'cpus' in params: | 68 | if 'cpus' in params: |
70 | cpus = min(map(int, params['cpus'])) | 69 | cpus = min(map(int, params['cpus'])) |
71 | else: | 70 | else: |
72 | cpus = lu.num_cpus() | 71 | cpus = num_cpus() |
73 | try: | 72 | try: |
74 | config = get_config_option("RELEASE_MASTER") and True | 73 | config = get_config_option("RELEASE_MASTER") and True |
75 | except: | 74 | except: |
diff --git a/parse/dir_map.py b/parse/dir_map.py index 601dd3b..a8d2a83 100644 --- a/parse/dir_map.py +++ b/parse/dir_map.py | |||
@@ -56,6 +56,9 @@ class DirMap(object): | |||
56 | 56 | ||
57 | remove_childless2(self.root) | 57 | remove_childless2(self.root) |
58 | 58 | ||
59 | def is_empty(self): | ||
60 | return not len(self.root.children) | ||
61 | |||
59 | def write(self, out_dir): | 62 | def write(self, out_dir): |
60 | def write2(path, node): | 63 | def write2(path, node): |
61 | out_path = "/".join(path) | 64 | out_path = "/".join(path) |
diff --git a/parse/ft.py b/parse/ft.py index 19453d1..98405f4 100644 --- a/parse/ft.py +++ b/parse/ft.py | |||
@@ -63,7 +63,7 @@ def extract_ft_data(result, data_dir, work_dir, cycles): | |||
63 | data_dir = os.path.abspath(data_dir) | 63 | data_dir = os.path.abspath(data_dir) |
64 | work_dir = os.path.abspath(work_dir) | 64 | work_dir = os.path.abspath(work_dir) |
65 | 65 | ||
66 | freg = conf.FILES['ft_data'] + "$" | 66 | freg = conf.FILES['ft_matches'] + "$" |
67 | bins = [f for f in os.listdir(data_dir) if re.match(freg, f)] | 67 | bins = [f for f in os.listdir(data_dir) if re.match(freg, f)] |
68 | 68 | ||
69 | if not len(bins): | 69 | if not len(bins): |
diff --git a/parse/point.py b/parse/point.py index d577306..f2b266a 100644 --- a/parse/point.py +++ b/parse/point.py | |||
@@ -128,8 +128,7 @@ class ExpPoint(object): | |||
128 | self.stats[type] = value | 128 | self.stats[type] = value |
129 | 129 | ||
130 | def __str__(self): | 130 | def __str__(self): |
131 | # return "<ExpPoint-%s>\n%s" % (self.id, dict_str(self.stats)) | 131 | return "<ExpPoint-%s>\n%s" % (self.id, dict_str(self.stats)) |
132 | return "<ExpPoint-%s>" % (self.id) | ||
133 | 132 | ||
134 | def get_stats(self): | 133 | def get_stats(self): |
135 | return self.stats.keys() | 134 | return self.stats.keys() |
diff --git a/parse_exps.py b/parse_exps.py index 7dfc9cd..8fcf5c3 100755 --- a/parse_exps.py +++ b/parse_exps.py | |||
@@ -22,8 +22,6 @@ def parse_args(): | |||
22 | # TODO: convert data-dir to proper option, clean 'dest' options | 22 | # TODO: convert data-dir to proper option, clean 'dest' options |
23 | parser = OptionParser("usage: %prog [options] [data_dir]...") | 23 | parser = OptionParser("usage: %prog [options] [data_dir]...") |
24 | 24 | ||
25 | print("default to no params.py") | ||
26 | |||
27 | parser.add_option('-o', '--out', dest='out', | 25 | parser.add_option('-o', '--out', dest='out', |
28 | help='file or directory for data output', default='parse-data') | 26 | help='file or directory for data output', default='parse-data') |
29 | parser.add_option('-c', '--clean', action='store_true', default=False, | 27 | parser.add_option('-c', '--clean', action='store_true', default=False, |
@@ -44,15 +42,15 @@ ExpData = namedtuple('ExpData', ['path', 'params', 'work_dir']) | |||
44 | 42 | ||
45 | def get_exp_params(data_dir, cm_builder): | 43 | def get_exp_params(data_dir, cm_builder): |
46 | param_file = "%s/%s" % (data_dir, conf.DEFAULTS['params_file']) | 44 | param_file = "%s/%s" % (data_dir, conf.DEFAULTS['params_file']) |
47 | if not os.path.isfile: | 45 | if os.path.isfile(param_file): |
48 | raise Exception("No param file '%s' exists!" % param_file) | 46 | params = load_params(param_file) |
49 | |||
50 | params = load_params(param_file) | ||
51 | 47 | ||
52 | # Store parameters in cm_builder, which will track which parameters change | 48 | # Store parameters in cm_builder, which will track which parameters change |
53 | # across experiments | 49 | # across experiments |
54 | for key, value in params.iteritems(): | 50 | for key, value in params.iteritems(): |
55 | cm_builder.try_add(key, value) | 51 | cm_builder.try_add(key, value) |
52 | else: | ||
53 | params = {} | ||
56 | 54 | ||
57 | # Cycles must be present for feather-trace measurement parsing | 55 | # Cycles must be present for feather-trace measurement parsing |
58 | if conf.PARAMS['cycles'] not in params: | 56 | if conf.PARAMS['cycles'] not in params: |
@@ -164,16 +162,25 @@ def main(): | |||
164 | if opts.force and os.path.exists(opts.out): | 162 | if opts.force and os.path.exists(opts.out): |
165 | sh.rmtree(opts.out) | 163 | sh.rmtree(opts.out) |
166 | 164 | ||
167 | result_table = result_table.reduce() | 165 | reduced_table = result_table.reduce() |
168 | 166 | ||
169 | sys.stderr.write("Writing result...\n") | 167 | sys.stderr.write("Writing result...\n") |
170 | if opts.write_map: | 168 | if opts.write_map: |
171 | # Write summarized results into map | 169 | # Write summarized results into map |
172 | result_table.write_map(opts.out) | 170 | reduced_table.write_map(opts.out) |
173 | else: | 171 | else: |
174 | # Write out csv directories for all variable params | 172 | # Write out csv directories for all variable params |
175 | dir_map = result_table.to_dir_map() | 173 | dir_map = reduced_table.to_dir_map() |
176 | dir_map.write(opts.out) | 174 | |
175 | # No csvs to write, assume user meant to print out data | ||
176 | if dir_map.is_empty(): | ||
177 | sys.stderr.write("Too little data to make csv files.\n") | ||
178 | if not opts.verbose: | ||
179 | for key, exp in result_table: | ||
180 | for e in exp: | ||
181 | print(e) | ||
182 | else: | ||
183 | dir_map.write(opts.out) | ||
177 | 184 | ||
178 | if __name__ == '__main__': | 185 | if __name__ == '__main__': |
179 | main() | 186 | main() |
diff --git a/run/executable/executable.py b/run/executable/executable.py index 0a408b7..02e35ae 100644 --- a/run/executable/executable.py +++ b/run/executable/executable.py | |||
@@ -1,7 +1,7 @@ | |||
1 | import sys | 1 | import sys |
2 | import subprocess | 2 | import subprocess |
3 | import signal | 3 | import signal |
4 | from ..litmus_util import is_executable | 4 | from common import is_executable |
5 | 5 | ||
6 | class Executable(object): | 6 | class Executable(object): |
7 | '''Parent object that represents an executable for use in task-sets.''' | 7 | '''Parent object that represents an executable for use in task-sets.''' |
diff --git a/run/litmus_util.py b/run/litmus_util.py index 8a7f87d..b9080c1 100644 --- a/run/litmus_util.py +++ b/run/litmus_util.py | |||
@@ -1,43 +1,8 @@ | |||
1 | import re | 1 | import re |
2 | import time | 2 | import time |
3 | import subprocess | 3 | import subprocess |
4 | import os | ||
5 | import stat | ||
6 | import config.config as conf | 4 | import config.config as conf |
7 | 5 | ||
8 | def num_cpus(): | ||
9 | '''Return the number of CPUs in the system.''' | ||
10 | |||
11 | lnx_re = re.compile(r'^(processor|online)') | ||
12 | cpus = 0 | ||
13 | |||
14 | with open('/proc/cpuinfo', 'r') as f: | ||
15 | for line in f: | ||
16 | if lnx_re.match(line): | ||
17 | cpus += 1 | ||
18 | return cpus | ||
19 | |||
20 | def ft_freq(): | ||
21 | umachine = subprocess.check_output(["uname", "-m"]) | ||
22 | |||
23 | if re.match("armv7", umachine): | ||
24 | # Arm V7s use a millisecond timer | ||
25 | freq = 1000.0 | ||
26 | elif re.match("x86", umachine): | ||
27 | # X86 timer is equal to processor clock | ||
28 | reg = re.compile(r'^cpu MHz\s*:\s*(?P<FREQ>\d+)', re.M) | ||
29 | with open('/proc/cpuinfo', 'r') as f: | ||
30 | data = f.read() | ||
31 | |||
32 | match = re.search(reg, data) | ||
33 | if not match: | ||
34 | raise Exception("Cannot parse CPU frequency from x86 CPU!") | ||
35 | freq = int(match.group('FREQ')) | ||
36 | else: | ||
37 | # You're on your own | ||
38 | freq = 0 | ||
39 | return freq | ||
40 | |||
41 | def switch_scheduler(switch_to_in): | 6 | def switch_scheduler(switch_to_in): |
42 | '''Switch the scheduler to whatever is passed in. | 7 | '''Switch the scheduler to whatever is passed in. |
43 | 8 | ||
@@ -60,21 +25,6 @@ def switch_scheduler(switch_to_in): | |||
60 | if switch_to != cur_plugin: | 25 | if switch_to != cur_plugin: |
61 | raise Exception("Could not switch to plugin: %s" % switch_to) | 26 | raise Exception("Could not switch to plugin: %s" % switch_to) |
62 | 27 | ||
63 | def uname_matches(reg): | ||
64 | data = subprocess.check_output(["uname", "-r"]) | ||
65 | return bool( re.match(reg, data) ) | ||
66 | |||
67 | def is_executable(fname): | ||
68 | '''Return whether the file passed in is executable''' | ||
69 | mode = os.stat(fname)[stat.ST_MODE] | ||
70 | return mode & stat.S_IXUSR and mode & stat.S_IRUSR | ||
71 | |||
72 | def is_device(dev): | ||
73 | if not os.path.exists(dev): | ||
74 | return False | ||
75 | mode = os.stat(dev)[stat.ST_MODE] | ||
76 | return not (not mode & stat.S_IFCHR) | ||
77 | |||
78 | def waiting_tasks(): | 28 | def waiting_tasks(): |
79 | reg = re.compile(r'^ready.*?(?P<READY>\d+)$', re.M) | 29 | reg = re.compile(r'^ready.*?(?P<READY>\d+)$', re.M) |
80 | with open('/proc/litmus/stats', 'r') as f: | 30 | with open('/proc/litmus/stats', 'r') as f: |
diff --git a/run/tracer.py b/run/tracer.py index 303aae0..065797c 100644 --- a/run/tracer.py +++ b/run/tracer.py | |||
@@ -1,7 +1,7 @@ | |||
1 | from . import litmus_util | ||
2 | import os | 1 | import os |
3 | import config.config as conf | 2 | import config.config as conf |
4 | 3 | ||
4 | from common import is_device,num_cpus | ||
5 | from operator import methodcaller | 5 | from operator import methodcaller |
6 | from run.executable.ftcat import FTcat,Executable | 6 | from run.executable.ftcat import FTcat,Executable |
7 | 7 | ||
@@ -58,7 +58,7 @@ class LogTracer(Tracer): | |||
58 | 58 | ||
59 | @staticmethod | 59 | @staticmethod |
60 | def enabled(): | 60 | def enabled(): |
61 | return litmus_util.is_device(LogTracer.DEVICE_STR) | 61 | return is_device(LogTracer.DEVICE_STR) |
62 | 62 | ||
63 | def stop_tracing(self): | 63 | def stop_tracing(self): |
64 | map(methodcaller('interrupt'), self.bins) | 64 | map(methodcaller('interrupt'), self.bins) |
@@ -71,7 +71,7 @@ class SchedTracer(Tracer): | |||
71 | super(SchedTracer, self).__init__("Sched Trace", output_dir) | 71 | super(SchedTracer, self).__init__("Sched Trace", output_dir) |
72 | 72 | ||
73 | if SchedTracer.enabled(): | 73 | if SchedTracer.enabled(): |
74 | for cpu in range(litmus_util.num_cpus()): | 74 | for cpu in range(num_cpus()): |
75 | # Executable will close the stdout/stderr files | 75 | # Executable will close the stdout/stderr files |
76 | stdout_f = open('%s/st-%d.bin' % (self.output_dir, cpu), 'w') | 76 | stdout_f = open('%s/st-%d.bin' % (self.output_dir, cpu), 'w') |
77 | stderr_f = open('%s/st-%d-stderr.txt' % (self.output_dir, cpu), 'w') | 77 | stderr_f = open('%s/st-%d-stderr.txt' % (self.output_dir, cpu), 'w') |
@@ -83,7 +83,7 @@ class SchedTracer(Tracer): | |||
83 | 83 | ||
84 | @staticmethod | 84 | @staticmethod |
85 | def enabled(): | 85 | def enabled(): |
86 | return litmus_util.is_device("%s%d" % (SchedTracer.DEVICE_STR, 0)) | 86 | return is_device("%s%d" % (SchedTracer.DEVICE_STR, 0)) |
87 | 87 | ||
88 | class OverheadTracer(Tracer): | 88 | class OverheadTracer(Tracer): |
89 | DEVICE_STR = '/dev/litmus/ft_trace0' | 89 | DEVICE_STR = '/dev/litmus/ft_trace0' |
@@ -100,7 +100,7 @@ class OverheadTracer(Tracer): | |||
100 | 100 | ||
101 | @staticmethod | 101 | @staticmethod |
102 | def enabled(): | 102 | def enabled(): |
103 | return litmus_util.is_device(OverheadTracer.DEVICE_STR) | 103 | return is_device(OverheadTracer.DEVICE_STR) |
104 | 104 | ||
105 | class PerfTracer(Tracer): | 105 | class PerfTracer(Tracer): |
106 | def __init__(self, output_dir): | 106 | def __init__(self, output_dir): |
diff --git a/run_exps.py b/run_exps.py index 195d3f8..a05ff93 100755 --- a/run_exps.py +++ b/run_exps.py | |||
@@ -2,13 +2,12 @@ | |||
2 | from __future__ import print_function | 2 | from __future__ import print_function |
3 | 3 | ||
4 | import config.config as conf | 4 | import config.config as conf |
5 | import run.litmus_util as lu | ||
6 | import os | 5 | import os |
7 | import re | 6 | import re |
8 | import shutil | 7 | import shutil |
9 | import traceback | 8 | import traceback |
10 | 9 | ||
11 | from common import load_params,get_executable | 10 | from common import load_params,get_executable,uname_matches,ft_freq |
12 | from optparse import OptionParser | 11 | from optparse import OptionParser |
13 | from run.executable.executable import Executable | 12 | from run.executable.executable import Executable |
14 | from run.experiment import Experiment,ExperimentDone | 13 | from run.experiment import Experiment,ExperimentDone |
@@ -125,7 +124,7 @@ def load_experiment(sched_file, scheduler, duration, param_file, out_dir): | |||
125 | (conf.PARAMS['dur'], duration)]) | 124 | (conf.PARAMS['dur'], duration)]) |
126 | 125 | ||
127 | # Feather-trace clock frequency saved for accurate overhead parsing | 126 | # Feather-trace clock frequency saved for accurate overhead parsing |
128 | ft_freq = lu.ft_freq() | 127 | ft_freq = ft_freq() |
129 | if ft_freq: | 128 | if ft_freq: |
130 | out_params[conf.PARAMS['cycles']] = ft_freq | 129 | out_params[conf.PARAMS['cycles']] = ft_freq |
131 | 130 | ||
@@ -146,7 +145,7 @@ def run_exp(name, schedule, scheduler, kernel, duration, work_dir, out_dir): | |||
146 | proc_entries = [] | 145 | proc_entries = [] |
147 | executables = [] | 146 | executables = [] |
148 | 147 | ||
149 | if kernel and not lu.uname_matches(kernel): | 148 | if kernel and not uname_matches(kernel): |
150 | raise InvalidKernel(kernel) | 149 | raise InvalidKernel(kernel) |
151 | 150 | ||
152 | # Parse values for proc entries | 151 | # Parse values for proc entries |
@@ -178,7 +177,7 @@ def run_exp(name, schedule, scheduler, kernel, duration, work_dir, out_dir): | |||
178 | if re.match(".*spin", real_spin): | 177 | if re.match(".*spin", real_spin): |
179 | real_args = ['-w'] + real_args + [duration] | 178 | real_args = ['-w'] + real_args + [duration] |
180 | 179 | ||
181 | if not lu.is_executable(real_spin): | 180 | if not is_executable(real_spin): |
182 | raise OSError("Cannot run spin %s: %s" % (real_spin, name)) | 181 | raise OSError("Cannot run spin %s: %s" % (real_spin, name)) |
183 | 182 | ||
184 | executables += [Executable(real_spin, real_args)] | 183 | executables += [Executable(real_spin, real_args)] |