1 ##############################################################################
2 # Copyright (c) 2015 Ericsson AB and others.
4 # All rights reserved. This program and the accompanying materials
5 # are made available under the terms of the Apache License, Version 2.0
6 # which accompanies this distribution, and is available at
7 # http://www.apache.org/licenses/LICENSE-2.0
8 ##############################################################################
12 import multiprocessing
16 log = logging.getLogger(__name__)
18 import yardstick.common.utils as utils
19 from yardstick.benchmark.scenarios import base as base_scenario
20 from yardstick.dispatcher.base import Base as DispatcherBase
23 def _output_serializer_main(filename, queue):
24 '''entrypoint for the singleton subprocess writing to outfile
25 Use of this process enables multiple instances of a scenario without
26 messing up the output file.
29 config["type"] = "File"
30 config["file_path"] = filename
31 dispatcher = DispatcherBase.get(config)
34 # blocks until data becomes available
36 if record == '_TERMINATE_':
39 dispatcher.record_result_data(record)
42 def _single_action(seconds, command, queue):
43 '''entrypoint for the single action process'''
44 log.debug("single action, fires after %d seconds (from now)", seconds)
46 log.debug("single action: executing command: '%s'", command)
47 data = subprocess.check_output(command, shell=True)
48 log.debug("\n%s" % data)
51 def _periodic_action(interval, command, queue):
52 '''entrypoint for the periodic action process'''
53 log.debug("periodic action, fires every: %d seconds", interval)
57 time_spent += interval
58 log.debug("periodic action, executing command: '%s'", command)
59 data = subprocess.check_output(command, shell=True)
60 log.debug("\n%s" % data)
69 def get_cls(runner_type):
70 '''return class of specified type'''
71 for runner in utils.itersubclasses(Runner):
72 if runner_type == runner.__execution_type__:
74 raise RuntimeError("No such runner_type %s" % runner_type)
78 '''return a list of known runner type (class) names'''
80 for runner in utils.itersubclasses(Runner):
86 """Returns instance of a scenario runner for execution type.
88 # if there is no runner, start the output serializer subprocess
89 if len(Runner.runners) == 0:
90 log.debug("Starting dump process file '%s'" %
91 config["output_filename"])
92 Runner.queue = multiprocessing.Queue()
93 Runner.dump_process = multiprocessing.Process(
94 target=_output_serializer_main,
96 args=(config["output_filename"], Runner.queue))
97 Runner.dump_process.start()
99 return Runner.get_cls(config["type"])(config, Runner.queue)
103 '''Release the runner'''
104 Runner.runners.remove(runner)
105 # if this was the last runner, stop the output serializer subprocess
106 if len(Runner.runners) == 0:
107 log.debug("Stopping dump process")
108 Runner.queue.put('_TERMINATE_')
109 Runner.dump_process.join()
113 '''Terminate all runners (subprocesses)'''
114 log.debug("Terminating all runners")
115 for runner in Runner.runners:
116 if runner.periodic_action_process:
117 log.debug("Terminating periodic action process")
118 runner.periodic_action_process.terminate()
119 runner.periodic_action_process = None
120 runner.process.terminate()
121 runner.process.join()
122 Runner.release(runner)
124 def __init__(self, config, queue):
127 self.periodic_action_process = None
128 self.result_queue = queue
129 Runner.runners.append(self)
131 def run_pre_start_action(self):
132 '''run a potentially configured pre-start action'''
133 if "pre-start-action" in self.config:
134 command = self.config["pre-start-action"]["command"]
135 log.debug("pre start action: command: '%s'" % command)
136 data = subprocess.check_output(command, shell=True)
137 log.debug("pre-start data: \n%s" % data)
138 output = "{'pre-start-action-data': %s}" % data
139 self.result_queue.put(output)
141 def run_post_stop_action(self):
142 '''run a potentially configured post-stop action'''
143 if "post-stop-action" in self.config:
144 command = self.config["post-stop-action"]["command"]
145 log.debug("post stop action: command: '%s'" % command)
146 data = subprocess.check_output(command, shell=True)
147 log.debug("post-stop data: \n%s" % data)
148 output = "{'post-stop-action-data': %s}" % data
149 self.result_queue.put(output)
151 def run(self, scenario_type, scenario_cfg):
152 class_name = base_scenario.Scenario.get(scenario_type)
153 path_split = class_name.split(".")
154 module_path = ".".join(path_split[:-1])
155 module = importlib.import_module(module_path)
156 cls = getattr(module, path_split[-1])
158 self.config['object'] = class_name
160 self.run_pre_start_action()
162 if "single-shot-action" in self.config:
163 single_action_process = multiprocessing.Process(
164 target=_single_action,
165 name="single-shot-action",
166 args=(self.config["single-shot-action"]["after"],
167 self.config["single-shot-action"]["command"],
169 single_action_process.start()
171 if "periodic-action" in self.config:
172 self.periodic_action_process = multiprocessing.Process(
173 target=_periodic_action,
174 name="periodic-action",
175 args=(self.config["periodic-action"]["interval"],
176 self.config["periodic-action"]["command"],
178 self.periodic_action_process.start()
180 self._run_benchmark(cls, "run", scenario_cfg)
184 if self.periodic_action_process:
185 self.periodic_action_process.terminate()
186 self.periodic_action_process = None
187 self.run_post_stop_action()
188 return self.process.exitcode