Как сгенерировать гистограмму для данного распределения вероятностей (для функционального тестирования сервера)? - PullRequest
4 голосов
/ 10 сентября 2008

Я пытаюсь автоматизировать функциональное тестирование сервера, используя реалистичное распределение частот запросов. (вид нагрузочного тестирования, вид моделирования)

Я выбрал распределение Weibull , поскольку оно "вроде" соответствует распределению, которое я наблюдал (быстро нарастает, быстро падает, но не мгновенно)

Я использую этот дистрибутив для генерации количества запросов, которые должны отправляться каждый день между заданной датой начала и окончания

Я взломал алгоритм в Python, который вроде работает, но он кажется глупым:

how_many_days = (end_date - start_date).days
freqs = defaultdict(int)
for x in xrange(how_many_responses):
    freqs[int(how_many_days * weibullvariate(0.5, 2))] += 1
timeline = []
day = start_date
for i,freq in sorted(freqs.iteritems()):
    timeline.append((day, freq))
    day += timedelta(days=1)
return timeline

Какие есть лучшие способы сделать это?

Ответы [ 6 ]

1 голос
/ 11 сентября 2008

Это быстро и, возможно, не так точно, но если вы рассчитываете PDF самостоятельно, то, по крайней мере, вы упростите наложение нескольких меньших / больших по одной временной шкале. dev - это стандартное отклонение гуассианского шума, которое контролирует шероховатость. Обратите внимание, что это не 'правильный' способ создать то, что вы хотите, но это просто.

import math
from datetime import datetime, timedelta, date
from random import gauss

how_many_responses = 1000
start_date = date(2008, 5, 1)
end_date = date(2008, 6, 1)
num_days = (end_date - start_date).days + 1
timeline = [start_date + timedelta(i) for i in xrange(num_days)]

def weibull(x, k, l):
    return (k / l) * (x / l)**(k-1) * math.e**(-(x/l)**k)

dev = 0.1
samples = [i * 1.25/(num_days-1) for i in range(num_days)]
probs = [weibull(i, 2, 0.5) for i in samples]
noise = [gauss(0, dev) for i in samples]
simdata = [max(0., e + n) for (e, n) in zip(probs, noise)]
events = [int(p * (how_many_responses / sum(probs))) for p in simdata]

histogram = zip(timeline, events)

print '\n'.join((d.strftime('%Y-%m-%d ') + "*" * c) for d,c in histogram)
1 голос
/ 11 сентября 2008

Немного длиннее, но, вероятно, более читаемая переделка ваших последних четырех строк:

samples = [0 for i in xrange(how_many_days + 1)]
for s in xrange(how_many_responses):
    samples[min(int(how_many_days * weibullvariate(0.5, 2)), how_many_days)] += 1
histogram = zip(timeline, samples)
print '\n'.join((d.strftime('%Y-%m-%d ') + "*" * c) for d,c in histogram)

Это всегда отбрасывает сэмплы в пределах диапазона дат, но вы получаете соответствующее увеличение в конце временной шкалы от всех сэмплов, которые находятся выше диапазона [0, 1].

1 голос
/ 10 сентября 2008

Почему бы вам не попробовать Grinder 3 для нагрузочного тестирования вашего сервера, он поставляется со всем этим и более готовым, и поддерживает Python как язык сценариев

0 голосов
/ 18 сентября 2008

Другое решение заключается в использовании Rpy , который позволяет легко использовать всю мощь R (включая множество инструментов для дистрибутивов) в Python.

0 голосов
/ 11 сентября 2008

Я переписал приведенный выше код, чтобы он был короче (но, может быть, теперь он слишком запутан?)

timeline = (start_date + timedelta(days=days) for days in count(0))
how_many_days = (end_date - start_date).days
pick_a_day = lambda _:int(how_many_days * weibullvariate(0.5, 2))
days = sorted(imap(pick_a_day, xrange(how_many_responses)))
histogram = zip(timeline, (len(list(responses)) for day, responses in groupby(days)))
print '\n'.join((d.strftime('%Y-%m-%d ') + "*" * c) for d,c in histogram)
0 голосов
/ 11 сентября 2008

Вместо того, чтобы указывать количество запросов в качестве фиксированного значения, почему бы не использовать вместо этого коэффициент масштабирования? В настоящий момент вы рассматриваете запросы как ограниченное количество и рандомизируете дни, в которые эти запросы выпадают. Казалось бы, более разумно рассматривать ваши запросы в день как независимые.

from datetime import *
from random import *

timeline = []
scaling = 10
start_date = date(2008, 5, 1)
end_date = date(2008, 6, 1)

num_days = (end_date - start_date).days + 1
days = [start_date + timedelta(i) for i in range(num_days)]
requests = [int(scaling * weibullvariate(0.5, 2)) for i in range(num_days)]
timeline = zip(days, requests)
timeline
...