From a5a89c7f1fb8f4eecafbd578b16072263037ad65 Mon Sep 17 00:00:00 2001 From: Steven Baltakatei Sandoval Date: Sat, 16 Oct 2021 03:23:52 +0000 Subject: [PATCH] feat(exec):Add sleepRand.py - Note: sleepRand.py pauses activity for random amounts of time using an inverse gaussian distribution. --- exec/unitproc/sleepRand.py | 127 +++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100755 exec/unitproc/sleepRand.py diff --git a/exec/unitproc/sleepRand.py b/exec/unitproc/sleepRand.py new file mode 100755 index 0000000..016e9f3 --- /dev/null +++ b/exec/unitproc/sleepRand.py @@ -0,0 +1,127 @@ +#!/usr/bin/env python3 +# Desc: Pauses a random amount of time. Random distribution is inverse gaussian. +# Version: 0.0.6 +# Depends: python 3.7.3 +# Usage: ./sleepRand.py [-v] [-p P] SECONDS +# Input: SECONDS: float seconds (mean of inverse gaussian distribution) +# P: precision (lambda of inverse gaussian distribution) +# Example: python3 sleepRand.py -vv -p 8.0 60.0 + +import argparse; +import math, time, random, sys; +import logging; + +# Set up argument parser (see https://docs.python.org/3.7/library/argparse.html ) +parser = argparse.ArgumentParser( + description='Delay activity for a random number of seconds. Delays sampled from an inverse gaussian distribution.', + epilog="Author: Steven Baltakatei Sandoval. License: GPLv3+"); +parser.add_argument('-v','--verbose', + action='count', + dest='verbosity', + default=0, + help='Verbose output. (repeat for increased verbosity)'); +parser.add_argument('mean', + action='store', + metavar='SECONDS', + nargs=1, + default=1, + type=float, + help='Mean seconds of delay. Is the mean of the inverse gaussian distribution.'); +parser.add_argument('--precision','-p', + action='store', + metavar='P', + nargs=1, + default=[4.0], + type=float, + help='How concentrated delays are around the mean (default: 4.0). Must be a positive integer or floating point value. Is the lambda factor in the inverse gaussian distribution. High values (e.g. > 10.0) cause random delays to rarely stray far from MEAN. Small values (e.g. < 0.10) result in many small delays plus occasional long delays.'); +parser.add_argument('--upper','-u', + action='store', + metavar='U', + nargs=1, + default=[None], + type=float, + help='Upper bound for possible delays (default: no bound). Without bound, extremely high delays are unlikely but possible.'); +args = parser.parse_args(); + +# Define functions +def setup_logging(verbosity): + '''Sets up logging''' + # Depends: module: argparse + # Ref/Attrib: Haas, Florian; Configure logging with argparse; https://xahteiwi.eu/resources/hints-and-kinks/python-cli-logging-options/ + base_loglevel = 30; + verbosity = min(verbosity, 2); + loglevel = base_loglevel - (verbosity * 10); + logging.basicConfig(level=loglevel, + format='%(message)s'); + +def randInvGau(mu, lam): + """Returns random variate of inverse gaussian distribution""" + # input: mu: mean of inverse gaussian distribution + # lam: shape parameter + # output: float sampled from inv. gaus. with range 0 to infinity, mean mu + # example: sample = float(randInvGau(1.0,4.0)); + # Ref/Attrib: Michael, John R. "Generating Random Variates Using Transformations with Multiple Roots" https://doi.org/10.2307/2683801 + nu = random.gauss(0,1); + y = nu ** 2; + xTerm1 = mu; + xTerm2 = mu ** 2 * y / (2 * lam); + xTerm3 = (- mu / (2 * lam)) * math.sqrt(4 * mu * lam * y + mu ** 2 * y ** 2); + x = xTerm1 + xTerm2 + xTerm3; + z = random.uniform(0.0,1.0); + if z <= (mu / (mu + x)): + return x; + else: + return (mu ** 2 / x); + +# Process input +## Start up logger +setup_logging(args.verbosity); +logging.debug('DEBUG:Debug logging output enabled.'); +logging.debug('DEBUG:args.verbosity:' + str(args.verbosity)); +logging.debug('DEBUG:args:' + str(args)); + +## Receive input arguments +try: + ### Get desired mean + desMean = args.mean[0]; + logging.debug('DEBUG:Desired mean:' + str(desMean)); + + ### Get lambda precision factor + lambdaFactor = args.precision[0]; + logging.debug('DEBUG:Lambda precision factor:' + str(lambdaFactor)); + + ### Get upper bound + if isinstance(args.upper[0], float): + logging.debug('DEBUG:args.upper[0] is float:' + str(args.upper[0])); + upperBound = args.upper[0]; + elif args.upper[0] is None: + logging.debug('DEBUG:args.upper[0] is None:' + str(args.upper[0])); + upperBound = None; + else: + raise TypeError('Upper bound not set correctly.'); + logging.debug('DEBUG:Upper bound:' + str(upperBound)); + + ### Reject negative floats. + if desMean < 0: + logging.error('ERROR:Desired mean is negative:' + str(desMean)); + raise ValueError('Negative number error.'); + if lambdaFactor < 0: + logging.error('ERROR:Lambda precision factor is negative:' + str(lambdaFactor)); + raise ValueError('Negative number error.'); +except ValueError: + sys.exit(1); + +# Calculate delay +rawDelay = randInvGau(desMean, desMean * lambdaFactor); +logging.debug('DEBUG:rawDelay(seconds):' + str(rawDelay)); +if isinstance(upperBound,float): + delay = min(upperBound, rawDelay); +elif upperBound is None: + delay = rawDelay; +logging.debug('DEBUG:delay(seconds) :' + str(delay)); + +# Sleep +time.sleep(float(delay)); + +# Author: Steven Baltakatei Sandoal +# License: GPLv3+ -- 2.30.2