diff options
author | Don Anderson <dda@ddanderson.com> | 2011-11-23 12:36:53 -0500 |
---|---|---|
committer | Don Anderson <dda@ddanderson.com> | 2011-11-23 12:36:53 -0500 |
commit | 0501970a5c529693c209d7629d35f30ed02015f3 (patch) | |
tree | 95281bf35cc8657b3d4f6641a5380472712c4883 /test | |
parent | f3a29f050e8d0e2330a6f9c8723bd9b22dc3c8a5 (diff) | |
download | mongo-0501970a5c529693c209d7629d35f30ed02015f3.tar.gz |
random numbers and multiple scenarios with probabilities: refs #16
- added a random number generator that is fast and good enough,
that is repeatable and each instance is independent, fine for MT tests.
- scenarios that have 'P' in their dict use it as a probability
(otherwise P=1.0). When 'multiplying' scenarios, we multiply their
probabilities. We can prune a list of scenarios, randomly picking a
set based on their probability. This allows us to generate tests based
on a large set of independent scenarios, but not have the size of
the final cross-product be overwhelming. Particular values in
scenarios can be emphasized or even required (with P=1.0).
Diffstat (limited to 'test')
-rw-r--r-- | test/suite/suite_random.py | 65 | ||||
-rw-r--r-- | test/suite/wtscenario.py | 51 |
2 files changed, 116 insertions, 0 deletions
diff --git a/test/suite/suite_random.py b/test/suite/suite_random.py new file mode 100644 index 00000000000..f81ea2cfda3 --- /dev/null +++ b/test/suite/suite_random.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python +# +# See the file LICENSE for redistribution information. +# +# Copyright (c) 2008-2011 WiredTiger, Inc. +# All rights reserved. +# +# suite_random.py +# A quick and predictable pseudo random number generator. +# + + +class suite_random: + """ + Generate random 32 bit integers that are predictable, + and use no global state. We use the Multiply-with-carry + method invented by George Marsaglia, because it is quick + and easy to implement. + """ + def __init__(self, *args): + arglen = len(args) + if arglen == 1: + self.seedw = int(args[0]) & 0xffffffff + self.seedz = int(args[0]) & 0Xffffffff + elif arglen == 2: + self.seedw = int(args[0]) & 0xffffffff + self.seedz = int(args[1]) & 0Xffffffff + else: + self.seedw = 0 + self.seedz = 0 + + # The seeds cannot be 0 + if self.seedw == 0: + self.seedw += 22233 + if self.seedz == 0: + self.seedz += 11133 + + def rand32(self): + """ + returns a random 32 bit integer + """ + w = self.seedw + z = self.seedz + self.seedw = (18000 * (w & 0xffff) + (w >> 16)) & 0xffffffff + self.seedz = (36969 * (z & 0xffff) + (z >> 16)) & 0xffffffff + return ((z << 16) + w) & 0xffffffff + + def rand_range(self, n, m): + """ + returns a random integer in the range [N,M). + """ + if m > 0xffffffff or n < 0: + raise ValueError("rand32_range expects args between 0 , 2^32") + if n >= m: + raise ValueError("rand32_range(n,m) expects n < m") + r = self.rand32() + return (r % (m - n)) + n + + def rand_float(self): + """ + returns a random floating point value between 0 and 1.0 + The number returned does not encompass all possibilities, + only 2^32 values within the range. + """ + return (self.rand32() + 0.0)/0x100000000 diff --git a/test/suite/wtscenario.py b/test/suite/wtscenario.py index 0259828f4c4..727c7dc6c2c 100644 --- a/test/suite/wtscenario.py +++ b/test/suite/wtscenario.py @@ -10,6 +10,7 @@ # import testscenarios +import suite_random def powerrange(start, stop, mult): """ @@ -45,6 +46,9 @@ def log2chr(val): megabyte = 1024 * 1024 def multiply_scenarios(sep, *args): + """ + Create the cross product of two lists of scenarios + """ result = None for scenes in args: if result == None: @@ -53,14 +57,61 @@ def multiply_scenarios(sep, *args): total = [] for scena in scenes: for scenb in result: + # Create a merged scenario with a concatenated name name = scena[0] + sep + scenb[0] tdict = {} tdict.update(scena[1]) tdict.update(scenb[1]) + + # If there is a 'P' value, it represents the + # probability that we want to use this scenario + # If both scenarios list a probability, multiply them. + if 'P' in scena[1] and 'P' in scenb[1]: + P = scena[1]['P'] * scenb[1]['P'] + tdict['P'] = P total.append((name, tdict)) result = total return result +def prune_scenarios(scenes): + """ + Use listed probabilities for pruning the list of scenarios + """ + r = suite_random.suite_random() + result = [] + for scene in scenes: + if 'P' in scene[1]: + p = scene[1]['P'] + if p < r.rand_float(): + continue + result.append(scene) + return result + +def quick_scenarios(fieldname, values, probabilities): + """ + Quickly build common scenarios, like: + [('foo', dict(somefieldname='foo')), + ('bar', dict(somefieldname='bar')), + ('boo', dict(somefieldname='boo'))] + via a call to: + quick_scenario('somefieldname', ['foo', 'bar', 'boo']) + """ + result = [] + if probabilities == None: + plen = 0 + else: + plen = len(probabilities) + ppos = 0 + for value in values: + if ppos >= plen: + d = dict([[fieldname, value]]) + else: + p = probabilities[ppos] + ppos += 1 + d = dict([[fieldname, value],['P', p]]) + result.append((str(value), d)) + return result + class wtscenario: """ A set of generators for different test scenarios |