aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJonathan Herman <hermanjl@cs.unc.edu>2013-04-08 15:42:16 -0400
committerJonathan Herman <hermanjl@cs.unc.edu>2013-04-08 15:42:16 -0400
commitd169debf732270c9571be6ea6e7d920345bffc33 (patch)
treed86c1ff5d0e4a116fcc916717abb29a026862c74
parent8864a4018c9b9088f330c3ef24ed7b5313ec36a2 (diff)
Added parameter file options for tracers and pre/post experiment commands.
-rw-r--r--common.py2
-rw-r--r--config/config.py5
-rw-r--r--run/experiment.py56
-rw-r--r--run/tracer.py52
-rwxr-xr-xrun_exps.py242
5 files changed, 230 insertions, 127 deletions
diff --git a/common.py b/common.py
index a26ac94..66df7bb 100644
--- a/common.py
+++ b/common.py
@@ -7,7 +7,7 @@ import sys
7from collections import defaultdict 7from collections import defaultdict
8from textwrap import dedent 8from textwrap import dedent
9 9
10def get_executable(prog, hint, optional=False): 10def get_executable(prog, hint='unknown', optional=False):
11 '''Search for @prog in system PATH. Print @hint if no binary is found.''' 11 '''Search for @prog in system PATH. Print @hint if no binary is found.'''
12 12
13 def is_exe(fpath): 13 def is_exe(fpath):
diff --git a/config/config.py b/config/config.py
index 49fd234..3486a40 100644
--- a/config/config.py
+++ b/config/config.py
@@ -28,7 +28,10 @@ PARAMS = {'sched' : 'scheduler', # Scheduler used by run_exps
28 'copts' : 'config-options', # Required kernel configuration options 28 'copts' : 'config-options', # Required kernel configuration options
29 'cycles' : 'clock-frequency', # Frequency run_exps was run with 29 'cycles' : 'clock-frequency', # Frequency run_exps was run with
30 'tasks' : 'tasks', # Number of tasks 30 'tasks' : 'tasks', # Number of tasks
31 'trial' : 'trial' # For multiple exps with same config 31 'trial' : 'trial', # For multiple exps with same config
32 'pre' : 'pre-experiment', # Run before each experiment
33 'post' : 'post-experiment', # Run after each experiment
34 'trace' : 'tracers' # Tracers to run with an experiment
32 } 35 }
33 36
34'''Default values for program options.''' 37'''Default values for program options.'''
diff --git a/run/experiment.py b/run/experiment.py
index 03d6ab6..3dd4866 100644
--- a/run/experiment.py
+++ b/run/experiment.py
@@ -3,7 +3,6 @@ import time
3import run.litmus_util as lu 3import run.litmus_util as lu
4import shutil as sh 4import shutil as sh
5from operator import methodcaller 5from operator import methodcaller
6from run.tracer import SchedTracer, LogTracer, PerfTracer, LinuxTracer, OverheadTracer
7 6
8class ExperimentException(Exception): 7class ExperimentException(Exception):
9 '''Used to indicate when there are problems with an experiment.''' 8 '''Used to indicate when there are problems with an experiment.'''
@@ -32,7 +31,8 @@ class Experiment(object):
32 '''Execute one task-set and save the results. Experiments have unique IDs.''' 31 '''Execute one task-set and save the results. Experiments have unique IDs.'''
33 INTERRUPTED_DIR = ".interrupted" 32 INTERRUPTED_DIR = ".interrupted"
34 33
35 def __init__(self, name, scheduler, working_dir, finished_dir, proc_entries, executables): 34 def __init__(self, name, scheduler, working_dir, finished_dir,
35 proc_entries, executables, tracer_types):
36 '''Run an experiment, optionally wrapped in tracing.''' 36 '''Run an experiment, optionally wrapped in tracing.'''
37 37
38 self.name = name 38 self.name = name
@@ -46,27 +46,17 @@ class Experiment(object):
46 46
47 self.__make_dirs() 47 self.__make_dirs()
48 self.__assign_executable_cwds() 48 self.__assign_executable_cwds()
49 self.__setup_tracers(tracer_types)
49 50
50 self.tracers = [] 51
51 if SchedTracer.enabled(): 52 def __setup_tracers(self, tracer_types):
52 self.log("Enabling sched_trace") 53 tracers = [ t(self.working_dir) for t in tracer_types ]
53 self.tracers.append( SchedTracer(working_dir) ) 54
54 if LinuxTracer.enabled(): 55 self.regular_tracers = [t for t in tracers if not t.is_exact()]
55 self.log("Enabling trace-cmd") 56 self.exact_tracers = [t for t in tracers if t.is_exact()]
56 self.tracers.append( LinuxTracer(working_dir) ) 57
57 if LogTracer.enabled(): 58 for t in tracers:
58 self.log("Enabling logging") 59 self.log("Enabling %s" % t.get_name())
59 self.tracers.append( LogTracer(working_dir) )
60 if PerfTracer.enabled():
61 self.log("Tracking CPU performance counters")
62 self.tracers.append( PerfTracer(working_dir) )
63
64 # Overhead trace must be handled seperately, see __run_tasks
65 if OverheadTracer.enabled():
66 self.log("Enabling overhead tracing")
67 self.overhead_trace = OverheadTracer(working_dir)
68 else:
69 self.overhead_trace = None
70 60
71 def __make_dirs(self): 61 def __make_dirs(self):
72 interrupted = None 62 interrupted = None
@@ -111,11 +101,10 @@ class Experiment(object):
111 raise Exception("Too much time has passed waiting for tasks!") 101 raise Exception("Too much time has passed waiting for tasks!")
112 time.sleep(1) 102 time.sleep(1)
113 103
114 # Overhead tracer must be started right after release or overhead 104 # Exact tracers (like overheads) must be started right after release or
115 # measurements will be full of irrelevant records 105 # measurements will be full of irrelevant records
116 if self.overhead_trace: 106 self.log("Starting %d released tracers" % len(self.exact_tracers))
117 self.log("Starting overhead trace") 107 map(methodcaller('start_tracing'), self.exact_tracers)
118 self.overhead_trace.start_tracing()
119 108
120 self.log("Releasing %d tasks" % len(self.executables)) 109 self.log("Releasing %d tasks" % len(self.executables))
121 released = lu.release_tasks() 110 released = lu.release_tasks()
@@ -145,10 +134,9 @@ class Experiment(object):
145 if not e.wait(): 134 if not e.wait():
146 ret = False 135 ret = False
147 136
148 # And it must be stopped here for the same reason 137 # And these must be stopped here for the same reason
149 if self.overhead_trace: 138 self.log("Stopping exact tracers")
150 self.log("Stopping overhead trace") 139 map(methodcaller('stop_tracing'), self.exact_tracers)
151 self.overhead_trace.stop_tracing()
152 140
153 if not ret: 141 if not ret:
154 raise ExperimentFailed(self.name) 142 raise ExperimentFailed(self.name)
@@ -186,8 +174,8 @@ class Experiment(object):
186 self.log("Switching to %s" % self.scheduler) 174 self.log("Switching to %s" % self.scheduler)
187 lu.switch_scheduler(self.scheduler) 175 lu.switch_scheduler(self.scheduler)
188 176
189 self.log("Starting %d tracers" % len(self.tracers)) 177 self.log("Starting %d regular tracers" % len(self.regular_tracers))
190 map(methodcaller('start_tracing'), self.tracers) 178 map(methodcaller('start_tracing'), self.regular_tracers)
191 179
192 self.exec_out = open('%s/exec-out.txt' % self.working_dir, 'w') 180 self.exec_out = open('%s/exec-out.txt' % self.working_dir, 'w')
193 self.exec_err = open('%s/exec-err.txt' % self.working_dir, 'w') 181 self.exec_err = open('%s/exec-err.txt' % self.working_dir, 'w')
@@ -200,6 +188,6 @@ class Experiment(object):
200 self.exec_out and self.exec_out.close() 188 self.exec_out and self.exec_out.close()
201 self.exec_err and self.exec_err.close() 189 self.exec_err and self.exec_err.close()
202 190
203 self.log("Stopping tracers") 191 self.log("Stopping regular tracers")
204 map(methodcaller('stop_tracing'), self.tracers) 192 map(methodcaller('stop_tracing'), self.regular_tracers)
205 193
diff --git a/run/tracer.py b/run/tracer.py
index 065797c..6e1d05c 100644
--- a/run/tracer.py
+++ b/run/tracer.py
@@ -6,10 +6,17 @@ from operator import methodcaller
6from run.executable.ftcat import FTcat,Executable 6from run.executable.ftcat import FTcat,Executable
7 7
8class Tracer(object): 8class Tracer(object):
9 def __init__(self, name, output_dir): 9 def __init__(self, name, output_dir, exact=False):
10 self.name = name 10 self.name = name
11 self.output_dir = output_dir 11 self.output_dir = output_dir
12 self.bins = [] 12 self.bins = []
13 self.exact=exact
14
15 def get_name(self):
16 return self.name
17
18 def is_exact(self):
19 return self.exact
13 20
14 def start_tracing(self): 21 def start_tracing(self):
15 map(methodcaller("execute"), self.bins) 22 map(methodcaller("execute"), self.bins)
@@ -23,7 +30,7 @@ class LinuxTracer(Tracer):
23 LITMUS_EVENTS = "%s/events/litmus" % EVENT_ROOT 30 LITMUS_EVENTS = "%s/events/litmus" % EVENT_ROOT
24 31
25 def __init__(self, output_dir): 32 def __init__(self, output_dir):
26 super(LinuxTracer, self).__init__("trace-cmd", output_dir) 33 super(LinuxTracer, self).__init__("Trace-cmd / Kernelshark", output_dir)
27 34
28 extra_args = ["record", # "-e", "sched:sched_switch", 35 extra_args = ["record", # "-e", "sched:sched_switch",
29 "-e", "litmus:*", 36 "-e", "litmus:*",
@@ -89,7 +96,7 @@ class OverheadTracer(Tracer):
89 DEVICE_STR = '/dev/litmus/ft_trace0' 96 DEVICE_STR = '/dev/litmus/ft_trace0'
90 97
91 def __init__(self, output_dir): 98 def __init__(self, output_dir):
92 super(OverheadTracer, self).__init__("Overhead Trace", output_dir) 99 super(OverheadTracer, self).__init__("Overhead Trace", output_dir, True)
93 100
94 stdout_f = open('{0}/{1}'.format(self.output_dir, conf.FILES['ft_data']), 'w') 101 stdout_f = open('{0}/{1}'.format(self.output_dir, conf.FILES['ft_data']), 'w')
95 stderr_f = open('{0}/{1}.stderr.txt'.format(self.output_dir, conf.FILES['ft_data']), 'w') 102 stderr_f = open('{0}/{1}.stderr.txt'.format(self.output_dir, conf.FILES['ft_data']), 'w')
@@ -109,3 +116,42 @@ class PerfTracer(Tracer):
109 @staticmethod 116 @staticmethod
110 def enabled(): 117 def enabled():
111 return False 118 return False
119
120
121tracers = {}
122
123def register_tracer(tracer, name):
124 tracers[name] = tracer
125
126def get_tracer_types(names):
127 error = True # Error if name is not present
128 errors = []
129
130 if not names:
131 # Just return all enabled tracers if none specified
132 names = tracers.keys()
133 error = False
134
135 ret = []
136
137 for name in names:
138 if name not in tracers:
139 raise ValueError("Invalid tracer '%s', valid names are: %s" %
140 (name, tracers.keys()))
141
142 if tracers[name].enabled():
143 ret += [ tracers[name] ]
144 elif error:
145 errors += ["Tracer '%s' requested, but not enabled." % name]
146
147 if errors:
148 raise ValueError("Check your kernel compile configuration!\n" +
149 "\n".join(errors))
150
151 return ret
152
153register_tracer(LinuxTracer, "kernelshark")
154register_tracer(LogTracer, "log")
155register_tracer(SchedTracer, "sched")
156register_tracer(OverheadTracer, "overhead")
157
diff --git a/run_exps.py b/run_exps.py
index c51f4c6..6043931 100755
--- a/run_exps.py
+++ b/run_exps.py
@@ -7,6 +7,7 @@ import os
7import re 7import re
8import shutil 8import shutil
9import sys 9import sys
10import run.tracer as trace
10import traceback 11import traceback
11 12
12from collections import namedtuple 13from collections import namedtuple
@@ -15,6 +16,12 @@ from run.executable.executable import Executable
15from run.experiment import Experiment,ExperimentDone 16from run.experiment import Experiment,ExperimentDone
16from run.proc_entry import ProcEntry 17from run.proc_entry import ProcEntry
17 18
19'''Customizable experiment parameters'''
20ExpParams = namedtuple('ExpParams', ['scheduler', 'duration', 'tracers',
21 'kernel', 'config_options'])
22'''Comparison of requested versus actual kernel compile parameter value'''
23ConfigResult = namedtuple('ConfigResult', ['param', 'wanted', 'actual'])
24
18class InvalidKernel(Exception): 25class InvalidKernel(Exception):
19 def __init__(self, kernel): 26 def __init__(self, kernel):
20 self.kernel = kernel 27 self.kernel = kernel
@@ -22,7 +29,7 @@ class InvalidKernel(Exception):
22 def __str__(self): 29 def __str__(self):
23 return "Kernel name does not match '%s'." % self.kernel 30 return "Kernel name does not match '%s'." % self.kernel
24 31
25ConfigResult = namedtuple('ConfigResult', ['param', 'wanted', 'actual']) 32
26class InvalidConfig(Exception): 33class InvalidConfig(Exception):
27 def __init__(self, results): 34 def __init__(self, results):
28 self.results = results 35 self.results = results
@@ -38,6 +45,7 @@ class InvalidConfig(Exception):
38 return "Invalid kernel configuration " +\ 45 return "Invalid kernel configuration " +\
39 "(ignore configuration with -i option).\n" + "\n".join(messages) 46 "(ignore configuration with -i option).\n" + "\n".join(messages)
40 47
48
41def parse_args(): 49def parse_args():
42 parser = OptionParser("usage: %prog [options] [sched_file]... [exp_dir]...") 50 parser = OptionParser("usage: %prog [options] [sched_file]... [exp_dir]...")
43 51
@@ -92,6 +100,7 @@ def convert_data(data):
92 100
93 return {'proc' : procs, 'spin' : spins} 101 return {'proc' : procs, 'spin' : spins}
94 102
103
95def fix_paths(schedule, exp_dir, sched_file): 104def fix_paths(schedule, exp_dir, sched_file):
96 '''Replace relative paths of command line arguments with absolute ones.''' 105 '''Replace relative paths of command line arguments with absolute ones.'''
97 for (idx, (spin, args)) in enumerate(schedule['spin']): 106 for (idx, (spin, args)) in enumerate(schedule['spin']):
@@ -106,97 +115,24 @@ def fix_paths(schedule, exp_dir, sched_file):
106 115
107 schedule['spin'][idx] = (spin, args) 116 schedule['spin'][idx] = (spin, args)
108 117
109def verify_environment(kernel, copts):
110 if kernel and not com.uname_matches(kernel):
111 raise InvalidKernel(kernel)
112
113 if copts:
114 results = []
115 for param, wanted in copts.iteritems():
116 try:
117 actual = com.get_config_option(param)
118 except IOError:
119 actual = None
120 if not str(wanted) == str(actual):
121 results += [ConfigResult(param, wanted, actual)]
122
123 if results:
124 raise InvalidConfig(results)
125
126def load_experiment(sched_file, scheduler, duration,
127 param_file, out_dir, ignore, jabber):
128 if not os.path.isfile(sched_file):
129 raise IOError("Cannot find schedule file: %s" % sched_file)
130
131 dir_name, fname = os.path.split(sched_file)
132 exp_name = os.path.split(dir_name)[1] + "/" + fname
133
134 params = {}
135 kernel = copts = ""
136
137 param_file = param_file or \
138 "%s/%s" % (dir_name, conf.DEFAULTS['params_file'])
139
140 if os.path.isfile(param_file):
141 params = com.load_params(param_file)
142 scheduler = scheduler or params[conf.PARAMS['sched']]
143 duration = duration or params[conf.PARAMS['dur']]
144
145 # Experiments can specify required kernel name
146 if conf.PARAMS['kernel'] in params:
147 kernel = params[conf.PARAMS['kernel']]
148 # Or required config options
149 if conf.PARAMS['copts'] in params:
150 copts = params[conf.PARAMS['copts']]
151
152 duration = duration or conf.DEFAULTS['duration']
153
154 if not scheduler:
155 raise IOError("Parameter scheduler not specified in %s" % (param_file))
156
157 # Parse schedule file's intentions
158 schedule = load_schedule(sched_file)
159 work_dir = "%s/tmp" % dir_name
160
161 fix_paths(schedule, os.path.split(sched_file)[0], sched_file)
162
163 if not ignore:
164 verify_environment(kernel, copts)
165
166 run_exp(exp_name, schedule, scheduler, kernel, duration, work_dir, out_dir)
167
168 if jabber:
169 jabber.send("Completed '%s'" % exp_name)
170
171 # Save parameters used to run experiment in out_dir
172 out_params = dict(params.items() +
173 [(conf.PARAMS['sched'], scheduler),
174 (conf.PARAMS['tasks'], len(schedule['spin'])),
175 (conf.PARAMS['dur'], duration)])
176 118
177 # Feather-trace clock frequency saved for accurate overhead parsing 119def load_schedule(name, fname, duration):
178 ft_freq = com.ft_freq() 120 '''Turn schedule file @fname into ProcEntry's and Executable's which execute
179 if ft_freq: 121 for @duration time.'''
180 out_params[conf.PARAMS['cycles']] = ft_freq
181
182 with open("%s/%s" % (out_dir, conf.DEFAULTS['params_file']), 'w') as f:
183 f.write(str(out_params))
184
185def load_schedule(fname):
186 with open(fname, 'r') as f: 122 with open(fname, 'r') as f:
187 data = f.read().strip() 123 data = f.read().strip()
188 try: 124 try:
189 schedule = eval(data) 125 schedule = eval(data)
190 except: 126 except:
191 schedule = convert_data(data) 127 schedule = convert_data(data)
192 return schedule
193 128
129 # Make paths relative to the file's directory
130 fix_paths(schedule, os.path.split(fname)[0], fname)
194 131
195def run_exp(name, schedule, scheduler, kernel, duration, work_dir, out_dir):
196 proc_entries = [] 132 proc_entries = []
197 executables = [] 133 executables = []
198 134
199 # Parse values for proc entries 135 # Create proc entries
200 for entry_conf in schedule['proc']: 136 for entry_conf in schedule['proc']:
201 path = entry_conf[0] 137 path = entry_conf[0]
202 data = entry_conf[1] 138 data = entry_conf[1]
@@ -206,7 +142,7 @@ def run_exp(name, schedule, scheduler, kernel, duration, work_dir, out_dir):
206 142
207 proc_entries += [ProcEntry(path, data)] 143 proc_entries += [ProcEntry(path, data)]
208 144
209 # Parse spinners 145 # Create executables
210 for spin_conf in schedule['spin']: 146 for spin_conf in schedule['spin']:
211 if isinstance(spin_conf, str): 147 if isinstance(spin_conf, str):
212 # Just a string defaults to default spin 148 # Just a string defaults to default spin
@@ -217,9 +153,6 @@ def run_exp(name, schedule, scheduler, kernel, duration, work_dir, out_dir):
217 raise IOError("Invalid spin conf %s: %s" % (spin_conf, name)) 153 raise IOError("Invalid spin conf %s: %s" % (spin_conf, name))
218 (spin, args) = (spin_conf[0], spin_conf[1]) 154 (spin, args) = (spin_conf[0], spin_conf[1])
219 155
220 # if not conf.BINS[spin]:
221 # raise IndexError("No knowledge of program %s: %s" % (spin, name))
222
223 real_spin = com.get_executable(spin, "") 156 real_spin = com.get_executable(spin, "")
224 real_args = args.split() 157 real_args = args.split()
225 if re.match(".*spin", real_spin): 158 if re.match(".*spin", real_spin):
@@ -230,21 +163,154 @@ def run_exp(name, schedule, scheduler, kernel, duration, work_dir, out_dir):
230 163
231 executables += [Executable(real_spin, real_args)] 164 executables += [Executable(real_spin, real_args)]
232 165
233 exp = Experiment(name, scheduler, work_dir, out_dir, 166 return proc_entries, executables
234 proc_entries, executables) 167
168
169def verify_environment(exp_params):
170 if exp_params.kernel and not com.uname_matches(exp_params.kernel):
171 raise InvalidKernel(exp_params.kernel)
172
173 if exp_params.config_options:
174 results = []
175 for param, wanted in exp_params.config_options.iteritems():
176 try:
177 actual = com.get_config_option(param)
178 except IOError:
179 actual = None
180 if not str(wanted) == str(actual):
181 results += [ConfigResult(param, wanted, actual)]
182
183 if results:
184 raise InvalidConfig(results)
185
186
187def run_parameter(exp_dir, out_dir, params, param_name):
188 '''Run an executable (arguments optional) specified as a configurable
189 @param_name in @params.'''
190 if conf.PARAMS[param_name] not in params:
191 return
192
193 script_params = params[conf.PARAMS[param_name]]
194
195 # Split into arguments and program name
196 if type(script_params) != type([]):
197 script_params = [script_params]
198 script_name = script_params.pop(0)
199
200 cwd_name = "%s/%s" % (exp_dir, script_name)
201 if os.path.isfile(cwd_name):
202 script = cwd_name
203 else:
204 script = com.get_executable(script_name, optional=True)
205
206 if not script:
207 raise Exception("Cannot find executable %s-script: %s" %
208 (param_name, script_name))
209
210 out = open('%s/%s-out.txt' % (out_dir, param_name), 'w')
211 prog = Executable(script, script_params,
212 stderr_file=out, stdout_file=out)
213 prog.cwd = out_dir
214
215 prog.execute()
216 prog.wait()
217
218 out.close()
219
220
221def get_exp_params(cmd_scheduler, cmd_duration, file_params):
222 kernel = copts = ""
223
224 scheduler = cmd_scheduler or file_params[conf.PARAMS['sched']]
225 duration = cmd_duration or file_params[conf.PARAMS['dur']] or\
226 conf.DEFAULTS['duration']
227
228 # Experiments can specify required kernel name
229 if conf.PARAMS['kernel'] in file_params:
230 kernel = file_params[conf.PARAMS['kernel']]
231
232 # Or required config options
233 if conf.PARAMS['copts'] in file_params:
234 copts = file_params[conf.PARAMS['copts']]
235
236 # Or required tracers
237 requested = []
238 if conf.PARAMS['trace'] in file_params:
239 requested = file_params[conf.PARAMS['trace']]
240 tracers = trace.get_tracer_types(requested)
241
242 # But only these two are mandatory
243 if not scheduler:
244 raise IOError("No scheduler found in param file!")
245 if not duration:
246 raise IOError("No duration found in param file!")
247
248 return ExpParams(scheduler=scheduler, kernel=kernel, duration=duration,
249 config_options=copts, tracers=tracers)
250
251
252def load_experiment(sched_file, cmd_scheduler, cmd_duration,
253 param_file, out_dir, ignore, jabber):
254 '''Load and parse data from files and run result.'''
255 if not os.path.isfile(sched_file):
256 raise IOError("Cannot find schedule file: %s" % sched_file)
257
258 dir_name, fname = os.path.split(sched_file)
259 exp_name = os.path.split(dir_name)[1] + "/" + fname
260 work_dir = "%s/tmp" % dir_name
261
262 # Load parameter file
263 param_file = param_file or \
264 "%s/%s" % (dir_name, conf.DEFAULTS['params_file'])
265 if os.path.isfile(param_file):
266 file_params = com.load_params(param_file)
267 else:
268 file_params = {}
269
270 exp_params = get_exp_params(cmd_scheduler, cmd_duration, file_params)
271 procs, execs = load_schedule(exp_name, sched_file, exp_params.duration)
272
273 exp = Experiment(exp_name, exp_params.scheduler, work_dir, out_dir,
274 procs, execs, exp_params.tracers)
275
276 if not ignore:
277 verify_environment(exp_params)
278
279 run_parameter(dir_name, work_dir, file_params, 'pre')
235 280
236 exp.run_exp() 281 exp.run_exp()
237 282
283 run_parameter(dir_name, out_dir, file_params, 'post')
284
285 if jabber:
286 jabber.send("Completed '%s'" % exp_name)
287
288 # Save parameters used to run experiment in out_dir
289 out_params = dict(file_params.items() +
290 [(conf.PARAMS['sched'], exp_params.scheduler),
291 (conf.PARAMS['tasks'], len(execs)),
292 (conf.PARAMS['dur'], exp_params.duration)])
293
294 # Feather-trace clock frequency saved for accurate overhead parsing
295 ft_freq = com.ft_freq()
296 if ft_freq:
297 out_params[conf.PARAMS['cycles']] = ft_freq
298
299 with open("%s/%s" % (out_dir, conf.DEFAULTS['params_file']), 'w') as f:
300 f.write(str(out_params))
301
302
238def setup_jabber(target): 303def setup_jabber(target):
239 try: 304 try:
240 from run.jabber import Jabber 305 from run.jabber import Jabber
241 306
242 return Jabber(target) 307 return Jabber(target)
243 except ImportError: 308 except ImportError:
244 sys.stderr.write("Failed to import jabber. Is python-xmpppy "+\ 309 sys.stderr.write("Failed to import jabber, disabling messages. " +
245 "installed?\nDisabling Jabber messaging.\n") 310 "Is python-xmpp installed?")
246 return None 311 return None
247 312
313
248def main(): 314def main():
249 opts, args = parse_args() 315 opts, args = parse_args()
250 316