[StreamingAlgorithms] result() returns None if data is missing

Make StreamingAlgorithm.result() returning None instead of
raising RallyException in case if no (or not enough) data
has been processed.

This change was discussed at Dec' 21st on Rally weekly meeting.

Change-Id: I5c1eec47a0e190ec6ccd351b0c3bd866f4544b35
This commit is contained in:
Alexander Maretskiy 2015-12-21 19:00:24 +02:00
parent d188a5ba3b
commit 339adba2a9
4 changed files with 21 additions and 36 deletions

View File

@ -18,8 +18,6 @@ import math
import six import six
from rally.common.i18n import _
from rally import exceptions
from rally.task.processing import utils from rally.task.processing import utils
@ -62,11 +60,9 @@ class MeanComputation(StreamingAlgorithm):
self.total += other.total self.total += other.total
def result(self): def result(self):
if self.count == 0: if self.count:
message = _("Unable to calculate the mean: " return self.total / self.count
"no values processed so far.") return None
raise exceptions.RallyException(message)
return self.total / self.count
class StdDevComputation(StreamingAlgorithm): class StdDevComputation(StreamingAlgorithm):
@ -90,6 +86,8 @@ class StdDevComputation(StreamingAlgorithm):
self.dev_sum = self.dev_sum + (value - mean_prev) * (value - self.mean) self.dev_sum = self.dev_sum + (value - mean_prev) * (value - self.mean)
def merge(self, other): def merge(self, other):
if not other.mean_computation.count:
return
dev_sum1 = self.dev_sum dev_sum1 = self.dev_sum
count1 = self.count count1 = self.count
mean1 = self.mean mean1 = self.mean
@ -107,10 +105,9 @@ class StdDevComputation(StreamingAlgorithm):
self.count * self.mean ** 2) self.count * self.mean ** 2)
def result(self): def result(self):
# NOTE(amaretskiy): Need at least two values to be processed
if self.count < 2: if self.count < 2:
message = _("Unable to calculate the standard deviation: " return None
"need at least two values to be processed.")
raise exceptions.RallyException(message)
return math.sqrt(self.dev_sum / (self.count - 1)) return math.sqrt(self.dev_sum / (self.count - 1))
@ -131,9 +128,6 @@ class MinComputation(StreamingAlgorithm):
self.add(other._value) self.add(other._value)
def result(self): def result(self):
if self._value is None:
raise exceptions.RallyException(
_("No values have been processed"))
return self._value return self._value
@ -154,9 +148,6 @@ class MaxComputation(StreamingAlgorithm):
self.add(other._value) self.add(other._value)
def result(self): def result(self):
if self._value is None:
raise exceptions.RallyException(
_("No values have been processed"))
return self._value return self._value
@ -185,10 +176,9 @@ class PercentileComputation(StreamingAlgorithm):
def result(self): def result(self):
results = list( results = list(
map(lambda x: x[1], self._graph_zipper.get_zipped_graph())) map(lambda x: x[1], self._graph_zipper.get_zipped_graph()))
if not results: if results:
raise exceptions.RallyException( return utils.percentile(results, self._percent)
_("No values have been processed")) return None
return utils.percentile(results, self._percent)
class IncrementComputation(StreamingAlgorithm): class IncrementComputation(StreamingAlgorithm):

View File

@ -44,7 +44,7 @@ class MaxAverageDuration(sla.SLA):
def merge(self, other): def merge(self, other):
self.avg_comp.merge(other.avg_comp) self.avg_comp.merge(other.avg_comp)
self.avg = self.avg_comp.result() self.avg = self.avg_comp.result() or 0.0
self.success = self.avg <= self.criterion_value self.success = self.avg <= self.criterion_value
return self.success return self.success

View File

@ -21,7 +21,6 @@ import six
from rally.common import costilius from rally.common import costilius
from rally.common import streaming_algorithms as streaming from rally.common import streaming_algorithms as streaming
from rally import exceptions
from rally.task.processing import utils from rally.task.processing import utils
@ -324,10 +323,7 @@ class MainStatsTable(Chart):
for i in range(len(self.table)): for i in range(len(self.table)):
row = [self.table[i][0][1]] row = [self.table[i][0][1]]
# no results if all iterations failed # no results if all iterations failed
try: no_result = not self.table[i][-2][1].result()
no_result = self.table[i][-2][1].result() == 0.0
except exceptions.RallyException:
no_result = True
row.extend(x[2](x[1], no_result) for x in self.table[i][1:]) row.extend(x[2](x[1], no_result) for x in self.table[i][1:])
rows.append(row) rows.append(row)

View File

@ -19,7 +19,6 @@ import ddt
import six import six
from rally.common import streaming_algorithms as algo from rally.common import streaming_algorithms as algo
from rally import exceptions
from tests.unit import test from tests.unit import test
@ -27,7 +26,7 @@ class MeanComputationTestCase(test.TestCase):
def test_empty_stream(self): def test_empty_stream(self):
mean_computation = algo.MeanComputation() mean_computation = algo.MeanComputation()
self.assertRaises(exceptions.RallyException, mean_computation.result) self.assertIsNone(mean_computation.result())
def test_one_value(self): def test_one_value(self):
mean_computation = algo.MeanComputation() mean_computation = algo.MeanComputation()
@ -68,12 +67,12 @@ class StdDevComputationTestCase(test.TestCase):
def test_empty_stream(self): def test_empty_stream(self):
std_computation = algo.StdDevComputation() std_computation = algo.StdDevComputation()
self.assertRaises(exceptions.RallyException, std_computation.result) self.assertIsNone(std_computation.result())
def test_one_value(self): def test_one_value(self):
std_computation = algo.StdDevComputation() std_computation = algo.StdDevComputation()
std_computation.add(10.0) std_computation.add(10.0)
self.assertRaises(exceptions.RallyException, std_computation.result) self.assertIsNone(std_computation.result())
def test_two_values(self): def test_two_values(self):
std_computation = algo.StdDevComputation() std_computation = algo.StdDevComputation()
@ -127,10 +126,10 @@ class MinComputationTestCase(test.TestCase):
self.assertRaises(TypeError, comp.add, None) self.assertRaises(TypeError, comp.add, None)
self.assertRaises(TypeError, comp.add, "str") self.assertRaises(TypeError, comp.add, "str")
def test_result_raises(self): def test_result_empty(self):
comp = algo.MinComputation() comp = algo.MinComputation()
self.assertRaises(TypeError, comp.result, 1) self.assertRaises(TypeError, comp.result, 1)
self.assertRaises(exceptions.RallyException, comp.result) self.assertIsNone(comp.result())
def test_merge(self): def test_merge(self):
single_min_algo = algo.MinComputation() single_min_algo = algo.MinComputation()
@ -166,10 +165,10 @@ class MaxComputationTestCase(test.TestCase):
self.assertRaises(TypeError, comp.add, None) self.assertRaises(TypeError, comp.add, None)
self.assertRaises(TypeError, comp.add, "str") self.assertRaises(TypeError, comp.add, "str")
def test_result_raises(self): def test_result_empty(self):
comp = algo.MaxComputation() comp = algo.MaxComputation()
self.assertRaises(TypeError, comp.result, 1) self.assertRaises(TypeError, comp.result, 1)
self.assertRaises(exceptions.RallyException, comp.result) self.assertIsNone(comp.result())
def test_merge(self): def test_merge(self):
single_max_algo = algo.MaxComputation() single_max_algo = algo.MaxComputation()
@ -241,10 +240,10 @@ class PercentileComputationTestCase(test.TestCase):
comp = algo.PercentileComputation(0.50, 100) comp = algo.PercentileComputation(0.50, 100)
self.assertRaises(TypeError, comp.add) self.assertRaises(TypeError, comp.add)
def test_result_raises(self): def test_result_empty(self):
self.assertRaises(TypeError, algo.PercentileComputation) self.assertRaises(TypeError, algo.PercentileComputation)
comp = algo.PercentileComputation(0.50, 100) comp = algo.PercentileComputation(0.50, 100)
self.assertRaises(exceptions.RallyException, comp.result) self.assertIsNone(comp.result())
class IncrementComputationTestCase(test.TestCase): class IncrementComputationTestCase(test.TestCase):