Merge changes from topics 'YARDSTICK-1250', 'YARDSTICK-1249'
[yardstick.git] / yardstick / benchmark / runners / arithmetic.py
index 69ea915..ecb59f9 100755 (executable)
 # yardstick comment: this is a modified copy of
 # rally/rally/benchmark/runners/constant.py
 
-'''A runner that every run arithmetically steps specified input value(s) to
+"""A runner that every run arithmetically steps specified input value(s) to
 the scenario. This just means step value(s) is added to the previous value(s).
 It is possible to combine several named input values and run with those either
 as nested for loops or combine each i:th index of each "input value list"
 until the end of the shortest list is reached (optimally all lists should be
 defined with the same number of values when using such iter_type).
-'''
+"""
 
-import os
-import multiprocessing
+from __future__ import absolute_import
+
+import itertools
 import logging
-import traceback
+import multiprocessing
+import os
 import time
-import itertools
+import traceback
+
+import six
+from six.moves import range
 
 from yardstick.benchmark.runners import base
+from yardstick.common import exceptions as y_exc
 
 LOG = logging.getLogger(__name__)
 
 
 def _worker_process(queue, cls, method_name, scenario_cfg,
-                    context_cfg, aborted):
+                    context_cfg, aborted, output_queue):
 
     sequence = 1
 
@@ -58,10 +64,6 @@ def _worker_process(queue, cls, method_name, scenario_cfg,
     benchmark.setup()
     method = getattr(benchmark, method_name)
 
-    queue.put({'runner_id': runner_cfg['runner_id'],
-               'scenario_cfg': scenario_cfg,
-               'context_cfg': context_cfg})
-
     sla_action = None
     if "sla" in scenario_cfg:
         sla_action = scenario_cfg["sla"].get("action", "assert")
@@ -71,8 +73,8 @@ def _worker_process(queue, cls, method_name, scenario_cfg,
         return -1 if start > stop else 1
 
     param_iters = \
-        [xrange(d['start'], d['stop'] + margin(d['start'], d['stop']),
-                d['step']) for d in runner_cfg['iterators']]
+        [range(d['start'], d['stop'] + margin(d['start'], d['stop']),
+               d['step']) for d in runner_cfg['iterators']]
     param_names = [d['name'] for d in runner_cfg['iterators']]
 
     iter_type = runner_cfg.get("iter_type", "nested_for_loops")
@@ -82,10 +84,10 @@ def _worker_process(queue, cls, method_name, scenario_cfg,
         loop_iter = itertools.product(*param_iters)
     elif iter_type == 'tuple_loops':
         # Combine each i;th index of respective parameter list
-        loop_iter = itertools.izip(*param_iters)
+        loop_iter = six.moves.zip(*param_iters)
     else:
         LOG.warning("iter_type unrecognized: %s", iter_type)
-        raise
+        raise TypeError("iter_type unrecognized: %s" % iter_type)
 
     # Populate options and run the requested method for each value combination
     for comb_values in loop_iter:
@@ -103,17 +105,20 @@ def _worker_process(queue, cls, method_name, scenario_cfg,
         errors = ""
 
         try:
-            method(data)
-        except AssertionError as assertion:
+            result = method(data)
+        except y_exc.SLAValidationError as error:
             # SLA validation failed in scenario, determine what to do now
             if sla_action == "assert":
                 raise
             elif sla_action == "monitor":
-                LOG.warning("SLA validation failed: %s", assertion.args)
-                errors = assertion.args
-        except Exception as e:
+                LOG.warning("SLA validation failed: %s", error.args)
+                errors = error.args
+        except Exception as e:  # pylint: disable=broad-except
             errors = traceback.format_exc()
             LOG.exception(e)
+        else:
+            if result:
+                output_queue.put(result)
 
         time.sleep(interval)
 
@@ -124,25 +129,32 @@ def _worker_process(queue, cls, method_name, scenario_cfg,
             'errors': errors
         }
 
-        record = {'runner_id': runner_cfg['runner_id'],
-                  'benchmark': benchmark_output}
-
-        queue.put(record)
+        queue.put(benchmark_output)
 
         LOG.debug("runner=%(runner)s seq=%(sequence)s END",
                   {"runner": runner_cfg["runner_id"], "sequence": sequence})
 
         sequence += 1
 
-        if (errors and sla_action is None):
+        if errors and sla_action is None:
             break
 
-    benchmark.teardown()
+    try:
+        benchmark.teardown()
+    except Exception:
+        # catch any exception in teardown and convert to simple exception
+        # never pass exceptions back to multiprocessing, because some exceptions can
+        # be unpicklable
+        # https://bugs.python.org/issue9400
+        LOG.exception("")
+        raise SystemExit(1)
     LOG.info("worker END")
+    LOG.debug("queue.qsize() = %s", queue.qsize())
+    LOG.debug("output_queue.qsize() = %s", output_queue.qsize())
 
 
 class ArithmeticRunner(base.Runner):
-    '''Run a scenario arithmetically stepping input value(s)
+    """Run a scenario arithmetically stepping input value(s)
 
   Parameters
     interval - time to wait between each scenario invocation
@@ -175,13 +187,15 @@ class ArithmeticRunner(base.Runner):
           default: none
     -
       name - and so on......
-    '''
+    """
 
     __execution_type__ = 'Arithmetic'
 
     def _run_benchmark(self, cls, method, scenario_cfg, context_cfg):
+        name = "{}-{}-{}".format(self.__execution_type__, scenario_cfg.get("type"), os.getpid())
         self.process = multiprocessing.Process(
+            name=name,
             target=_worker_process,
             args=(self.result_queue, cls, method, scenario_cfg,
-                  context_cfg, self.aborted))
+                  context_cfg, self.aborted, self.output_queue))
         self.process.start()