yandex-tank/Tank/stepper/instance_plan.py

177 lines
4.7 KiB
Python
Raw Normal View History

2013-07-15 12:21:16 +00:00
from itertools import cycle, chain
2013-06-28 13:45:26 +00:00
from util import parse_duration
import re
2013-05-27 13:06:28 +00:00
2013-07-03 13:14:05 +00:00
class InstanceLP(object):
2013-06-28 13:45:26 +00:00
'''Base class for all instance plans'''
2013-05-27 13:06:28 +00:00
def __init__(self, duration=0):
2013-07-15 11:51:50 +00:00
self.duration = float(duration)
2013-05-27 13:06:28 +00:00
def get_duration(self):
'''Return step duration in milliseconds'''
2013-05-27 13:06:28 +00:00
return self.duration
2013-07-03 11:25:00 +00:00
def get_rps_list(self):
return []
2013-06-28 13:45:26 +00:00
2013-07-03 13:14:05 +00:00
class Empty(InstanceLP):
'''Load plan with no timestamp (for instance_schedule)'''
def __iter__(self):
return cycle([0])
2013-07-15 12:21:16 +00:00
class Composite(InstanceLP):
'''Load plan with multiple steps'''
def __init__(self, steps):
self.steps = steps
def __iter__(self):
base = 0
for step in self.steps:
for ts in step:
yield int(ts + base)
base += step.get_duration()
2013-07-15 12:21:16 +00:00
for item in cycle([0]):
yield item
def get_duration(self):
'''Return total duration in milliseconds'''
2013-07-15 12:21:16 +00:00
return sum(step.get_duration() for step in self.steps)
def get_rps_list(self):
return list(chain.from_iterable(step.get_rps_list() for step in self.steps))
2013-07-03 13:14:05 +00:00
class Line(InstanceLP):
2013-06-28 13:45:26 +00:00
2013-07-02 13:37:34 +00:00
'''
Starts some instances linearly
2013-07-15 11:51:50 +00:00
2013-07-15 17:42:11 +00:00
>>> from util import take
>>> take(10, Line(5, 5000))
[1000, 2000, 3000, 4000, 5000]
2013-07-02 13:37:34 +00:00
'''
def __init__(self, instances, duration):
self.instances = instances
self.duration = float(duration)
def __iter__(self):
interval = float(self.duration) / self.instances
return (int(i * interval) for i in xrange(1, self.instances + 1))
2013-07-02 13:37:34 +00:00
2013-07-03 13:14:05 +00:00
class Ramp(InstanceLP):
2013-07-02 13:37:34 +00:00
2013-07-03 13:14:05 +00:00
'''
2013-07-15 11:51:50 +00:00
Starts <instance_count> instances, one each <interval> seconds
2013-07-15 17:42:11 +00:00
>>> from util import take
>>> take(10, Ramp(5, 5000))
2013-07-15 11:51:50 +00:00
[0, 5000, 10000, 15000, 20000]
2013-07-03 13:14:05 +00:00
'''
2013-07-15 11:51:50 +00:00
def __init__(self, instance_count, interval):
self.duration = instance_count * interval
2013-07-15 11:51:50 +00:00
self.instance_count = instance_count
self.interval = interval
2013-07-03 13:14:05 +00:00
def __iter__(self):
2013-07-15 11:51:50 +00:00
return ((int(i * self.interval) for i in xrange(0, self.instance_count)))
2013-06-28 13:45:26 +00:00
class Wait(InstanceLP):
'''
Don't start any instances for the definded duration
'''
def __init__(self, duration):
self.duration = duration
def __iter__(self):
return iter([])
2013-07-03 13:14:05 +00:00
class Stairway(InstanceLP):
2013-06-28 13:45:26 +00:00
def __init__(self, minrps, maxrps, increment, duration):
raise NotImplementedError(
'We have no support for this load type in instances_schedule yet')
class StepFactory(object):
@staticmethod
def line(params):
2013-07-15 16:23:51 +00:00
template = re.compile('(\d+),\s*(\d+),\s*([0-9.]+[dhms]?)+\)')
2013-06-28 13:45:26 +00:00
minrps, maxrps, duration = template.search(params).groups()
2013-07-02 13:37:34 +00:00
# note that we don't use minrps at all and use maxrps
# as the number of instances we gonna start
return Line(int(maxrps) - int(minrps), parse_duration(duration))
@staticmethod
def ramp(params):
2013-07-15 16:23:51 +00:00
template = re.compile('(\d+),\s*([0-9.]+[dhms]?)+\)')
instances, interval = template.search(params).groups()
return Ramp(int(instances), parse_duration(interval))
@staticmethod
def wait(params):
2013-07-15 16:23:51 +00:00
template = re.compile('([0-9.]+[dhms]?)+\)')
duration = template.search(params).groups()[0]
return Wait(parse_duration(duration))
2013-06-28 13:45:26 +00:00
@staticmethod
def stairway(params):
2013-07-15 16:23:51 +00:00
template = re.compile('(\d+),\s*(\d+),\s*(\d+),\s*([0-9.]+[dhms]?)+\)')
2013-06-28 13:45:26 +00:00
minrps, maxrps, increment, duration = template.search(params).groups()
return Stairway(int(minrps), int(maxrps), int(increment), parse_duration(duration))
@staticmethod
def produce(step_config):
_plans = {
'line': StepFactory.line,
'step': StepFactory.stairway,
'ramp': StepFactory.ramp,
'wait': StepFactory.wait,
2013-06-28 13:45:26 +00:00
}
load_type, params = step_config.split('(')
load_type = load_type.strip()
if load_type in _plans:
return _plans[load_type](params)
else:
raise NotImplementedError(
'No such load type implemented for instances_schedule: "%s"' % load_type)
def create(instances_schedule):
'''
2013-07-15 12:21:16 +00:00
Creates load plan timestamps generator
>>> from util import take
>>> take(7, create(['ramp(5, 5s)']))
[0, 5000, 10000, 15000, 20000, 0, 0]
>>> take(12, create(['ramp(5, 5s)', 'wait(5s)', 'ramp(5,5s)']))
2013-07-15 12:21:16 +00:00
[0, 5000, 10000, 15000, 20000, 30000, 35000, 40000, 45000, 50000, 0, 0]
>>> take(7, create(['wait(5s)', 'ramp(5, 0)']))
[5000, 5000, 5000, 5000, 5000, 0, 0]
'''
2013-06-28 13:45:26 +00:00
if len(instances_schedule) > 1:
steps = [StepFactory.produce(step_config)
for step_config in instances_schedule]
else:
steps = [StepFactory.produce(instances_schedule[0])]
2013-07-03 11:25:00 +00:00
return Composite(steps)