2008-09-10 8 views
3

J'essaie d'automatiser les tests fonctionnels d'un serveur en utilisant une distribution de fréquence réaliste des demandes. (Sorte de test de charge, une sorte de simulation)Comment générer un histogramme pour une distribution de probabilité donnée (pour tester un serveur)?

J'ai choisi la distribution Weibull comme « une sorte de » correspond à la distribution que j'ai observé (rampes rapidement, tombe rapidement, mais pas instantanément)

J'utilise cette distribution pour générer le nombre de demandes qui doivent être envoyés chaque jour entre un début et une date de fin

J'ai piraté ensemble un algorithme en Python ce genre de travaux, mais il se sent kludgy:

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 

Quelles sont les meilleures façons de faire cela?

+0

Cet algorithme renvoie toujours le nombre attendu de réponses, mais il ne correspond généralement pas exactement entre les dates de début et de fin, je ne suis pas sûr que cela soit possible à moins que je ne manipule manuellement les fréquences? –

+0

Ils ne sont pas garantis d'être ajustés entre les dates de début et de fin car vous utilisez une distribution de probabilité avec un support infini. Tant que vous utilisez le nombre aléatoire retourné de la distribution inchangé comme une clé, vous allez avoir ce problème. – Kai

Répondre

1

Ceci est rapide et probablement pas si précis, mais si vous calculez le PDF vous-même, alors au moins vous le rendre plus facile de pondre plusieurs petits/plus grands sur un seul scénario. dev est la déviation std dans le bruit de Guassian, qui contrôle la rugosité. Notez que c'est pas le le «bon» moyen de générer ce que vous voulez, mais c'est facile.

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) 
+0

Superbe la distribution semble bien meilleure que celle générée par simulation. –

1

Pourquoi ne pas essayer The Grinder 3 pour charger tester votre serveur, il est livré avec tout cela et plus préconstruit, et il prend en charge Python comme langage de script

+0

Eh bien, malheureusement, cette fonction va être utilisée dans certains tests fonctionnels ainsi, j'aimerais le garder autant que possible en famille. Peut-être que la simulation est une meilleure description que le test de charge –

0

Au lieu de donner le nombre de demandes en tant que valeur fixe, pourquoi ne pas utiliser un facteur d'échelle à la place? En ce moment, vous traitez les demandes comme une quantité limitée et randomisez les jours où ces demandes tombent. Il semblerait plus raisonnable de traiter vos demandes par jour comme indépendantes.

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 
+0

Cette fonction ne semble pas produire la forme que je recherche.Si vous vérifiez l'article wikipedia, j'ai choisi la courbe rouge qui monte rapidement et qui se poursuit au fil du temps comme semble modéliser les pages vues, d'abord hautes mais ensuite les gens perdent leur intérêt pour le nouveau contenu au fil du temps. –

+0

En fait tout le point (de mon point de vue :-) est que le nombre de demandes dépend du jour. Je n'essaie pas seulement de modéliser des charges aléatoires sur une période donnée. –

+0

D'accord, mais ce que vous faites maintenant ne fait qu'approcher la distribution. Pourquoi ne pas utiliser la distribution elle-même, ou la distribution plus un peu de bruit? En l'état, vous modélisez un processus dépendant de l'historique sans utiliser aucun historique. – Kai

0

Je réécrit le code ci-dessus pour être plus court (mais peut-être qu'il est trop brouillées maintenant?)

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

Ce sont les importations pour la fonction ci-dessus: à partir de itertools importer imap, compter import datetime datetime, timedelta de weibullvariate importation aléatoire , GroupBy how_many_responses = 100 start_date = Date (2008, 5, 1) date_fin = Date (2008, 6, 1) –

1

Un peu plus long, mais réusinage probablement plus lisible de vos quatre dernières lignes:

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) 

Cela supprime toujours les échantillons dans la plage de dates, mais vous obtenez un bump correspondant à la fin de la chronologie à partir de tous les échantillons situés au-dessus de la plage [0, 1].

+0

Nice, j'aime ça. J'essaie toujours de bourrer les choses dans les itérateurs, mais c'est nettement plus facile à lire :-) –

0

Une autre solution consiste à utiliser Rpy, qui met toute la puissance de R (y compris beaucoup d'outils pour les distributions), facilement en Python.

Questions connexes