[CalendarServer-changes] [7553] CalendarServer/trunk/contrib/performance

source_changes at macosforge.org source_changes at macosforge.org
Fri Jun 3 12:57:35 PDT 2011


Revision: 7553
          http://trac.macosforge.org/projects/calendarserver/changeset/7553
Author:   exarkun at twistedmatrix.com
Date:     2011-06-03 12:57:35 -0700 (Fri, 03 Jun 2011)
Log Message:
-----------
Accept distribution objects in the other profiles as well.

Modified Paths:
--------------
    CalendarServer/trunk/contrib/performance/loadtest/config.plist
    CalendarServer/trunk/contrib/performance/loadtest/profiles.py
    CalendarServer/trunk/contrib/performance/loadtest/test_profiles.py
    CalendarServer/trunk/contrib/performance/stats.py
    CalendarServer/trunk/contrib/performance/test_stats.py

Modified: CalendarServer/trunk/contrib/performance/loadtest/config.plist
===================================================================
--- CalendarServer/trunk/contrib/performance/loadtest/config.plist	2011-06-03 00:31:41 UTC (rev 7552)
+++ CalendarServer/trunk/contrib/performance/loadtest/config.plist	2011-06-03 19:57:35 UTC (rev 7553)
@@ -73,6 +73,7 @@
 	    <dict>
 	      <key>interval</key>
 	      <integer>60</integer>
+
 	      <key>eventStartDistribution</key>
 	      <dict>
 		<key>type</key>
@@ -97,17 +98,39 @@
 	  </dict>
 
 	  <dict>
+
 	    <key>class</key>
 	    <string>loadtest.profiles.Inviter</string>
-
+	    
 	    <key>params</key>
 	    <dict>
-	      <key>interval</key>
-	      <integer>20</integer>
+	      <key>sendInvitationDistribution</key>
+	      <dict>
+		<key>type</key>
+		<string>stats.NormalDistribution</string>
+		<key>params</key>
+		<dict>
+		  <key>mu</key>
+		  <integer>60</integer>
+		  <key>sigma</key>
+		  <integer>5</integer>
+		</dict>
+	      </dict>
 
-	      <key>spread</key>
-	      <integer>3</integer>
+	      <key>inviteeDistanceDistribution</key>
+	      <dict>
+		<key>type</key>
+		<string>stats.UniformIntegerDistribution</string>
+		<key>params</key>
+		<dict>
+		  <key>min</key>
+		  <integer>-100</integer>
+		  <key>max</key>
+		  <integer>101</integer>
+		</dict>
+	      </dict>
 	    </dict>
+
 	  </dict>
 
 	  <dict>
@@ -116,14 +139,21 @@
 
 	    <key>params</key>
 	    <dict>
-	      <key>delay</key>
-	      <integer>10</integer>
-
-	      <key>spread</key>
-	      <integer>2</integer>
+	      <key>acceptDelayDistribution</key>
+	      <dict>
+		<key>type</key>
+		<string>stats.NormalDistribution</string>
+		<key>params</key>
+		<dict>
+		  <key>mu</key>
+		  <integer>360</integer>
+		  <key>sigma</key>
+		  <integer>60</integer>
+		</dict>
+	      </dict>
 	    </dict>
+	  
 	  </dict>
-
 	</array>
 
 	<key>weight</key>

Modified: CalendarServer/trunk/contrib/performance/loadtest/profiles.py
===================================================================
--- CalendarServer/trunk/contrib/performance/loadtest/profiles.py	2011-06-03 00:31:41 UTC (rev 7552)
+++ CalendarServer/trunk/contrib/performance/loadtest/profiles.py	2011-06-03 19:57:35 UTC (rev 7553)
@@ -31,13 +31,13 @@
 from protocol.caldav.definitions import caldavxml
 
 from twisted.python import context
-from twisted.python.log import msg
+from twisted.python.log import msg, err
 from twisted.python.failure import Failure
 from twisted.internet.defer import Deferred, succeed, fail
 from twisted.internet.task import LoopingCall
 from twisted.web.http import PRECONDITION_FAILED
 
-from stats import NearFutureDistribution, UniformDiscreteDistribution, mean, median
+from stats import NearFutureDistribution, NormalDistribution, UniformDiscreteDistribution, mean, median
 from loadtest.logger import SummarizingMixin
 from loadtest.ical import IncorrectResponseCode
 
@@ -110,20 +110,35 @@
     """
 
 
+def loopWithDistribution(reactor, distribution, function):
+    result = Deferred()
 
+    def repeat(ignored):
+        reactor.callLater(distribution.sample(), iterate)
+
+    def iterate():
+        d = function()
+        d.addCallbacks(repeat, result.errback)
+
+    repeat(None)
+    return result
+
+
+
 class Inviter(ProfileBase):
     """
     A Calendar user who invites and de-invites other users to events.
     """
-    def setParameters(self, interval=20, spread=3):
-        self._interval = interval
-        self._spread = spread
+    def setParameters(self,
+                      sendInvitationDistribution=NormalDistribution(600, 60),
+                      inviteeDistanceDistribution=UniformDiscreteDistribution(range(-10, 11))):
+        self._sendInvitationDistribution = sendInvitationDistribution
+        self._inviteeDistanceDistribution = inviteeDistanceDistribution
 
 
     def run(self):
-        self._call = LoopingCall(self._invite)
-        self._call.clock = self._reactor
-        return self._call.start(self._interval)
+        return loopWithDistribution(
+            self._reactor, self._sendInvitationDistribution, self._invite)
 
 
     def _addAttendee(self, event, attendees):
@@ -137,7 +152,8 @@
             invitees.add(att.value)
 
         for i in range(10):
-            invitee = max(1, int(self.random.gauss(self._number, self._spread)))
+            invitee = max(
+                1, self._number + self._inviteeDistanceDistribution.sample())
             record = self._sim.getUserRecord(invitee)
             uuid = u'urn:uuid:%s' % (record.uid,)
             if uuid not in invitees:
@@ -210,16 +226,18 @@
                     lambda reason: reason.trap(CannotAddAttendee))
                 return self._newOperation("invite", d)
 
+            # Oops, no events to play with.
+            return succeed(None)
 
 
+
 class Accepter(ProfileBase):
     """
     A Calendar user who accepts invitations to events.
     """
-    def setParameters(self, delay=10, spread=2):
+    def setParameters(self, acceptDelayDistribution=NormalDistribution(1200, 60)):
         self._accepting = set()
-        self._delay = delay
-        self._spread = spread
+        self._acceptDelayDistribution = acceptDelayDistribution
 
 
     def run(self):
@@ -247,7 +265,7 @@
         for attendee in attendees:
             if self._isSelfAttendee(attendee):
                 if attendee.params[u'PARTSTAT'][0] == 'NEEDS-ACTION':
-                    delay = self.random.gauss(self._delay, self._spread)
+                    delay = self._acceptDelayDistribution.sample()
                     self._accepting.add(href)
                     self._reactor.callLater(
                         delay, self._acceptInvitation, href, attendee)

Modified: CalendarServer/trunk/contrib/performance/loadtest/test_profiles.py
===================================================================
--- CalendarServer/trunk/contrib/performance/loadtest/test_profiles.py	2011-06-03 00:31:41 UTC (rev 7552)
+++ CalendarServer/trunk/contrib/performance/loadtest/test_profiles.py	2011-06-03 19:57:35 UTC (rev 7553)
@@ -165,6 +165,10 @@
 
 
 class Deterministic(object):
+    def __init__(self, value=None):
+        self.value = value
+
+
     def gauss(self, mean, stddev):
         """
         Pretend to return a value from a gaussian distribution with mu
@@ -178,7 +182,11 @@
         return sequence[0]
 
 
+    def sample(self):
+        return self.value
 
+
+
 class StubClient(BaseClient):
     """
     Stand in for an iCalendar client.
@@ -232,6 +240,16 @@
 
 
 
+class SequentialDistribution(object):
+    def __init__(self, values):
+        self.values = values
+
+
+    def sample(self):
+        return self.values.pop(0)
+
+
+
 class InviterTests(TestCase):
     """
     Tests for loadtest.profiles.Inviter.
@@ -306,7 +324,7 @@
         vevent, event, calendar, client = self._simpleAccount(
             userNumber, SIMPLE_EVENT)
         inviter = Inviter(Clock(), self.sim, client, userNumber)
-        inviter.random = Deterministic()
+        inviter.setParameters(inviteeDistanceDistribution=Deterministic(1))
         inviter._invite()
         attendees = vevent.contents[u'vevent'][0].contents[u'attendee']
         self.assertEquals(len(attendees), 1)
@@ -330,11 +348,10 @@
             selfNumber, SIMPLE_EVENT)
 
         otherNumber = 20
-        values = [selfNumber, otherNumber]
+        values = [selfNumber - selfNumber, otherNumber - selfNumber]
 
         inviter = Inviter(Clock(), self.sim, client, selfNumber)
-        inviter.random = Deterministic()
-        inviter.random.gauss = lambda mu, sigma: values.pop(0)
+        inviter.setParameters(inviteeDistanceDistribution=SequentialDistribution(values))
         inviter._invite()
         attendees = vevent.contents[u'vevent'][0].contents[u'attendee']
         self.assertEquals(len(attendees), 1)
@@ -360,11 +377,10 @@
         invitee = vevent.contents[u'vevent'][0].contents[u'attendee'][0]
         inviteeNumber = int(invitee.params[u'CN'][0].split()[1])
         anotherNumber = inviteeNumber + 5
-        values = [inviteeNumber, anotherNumber]
+        values = [inviteeNumber - selfNumber, anotherNumber - selfNumber]
 
         inviter = Inviter(Clock(), self.sim, client, selfNumber)
-        inviter.random = Deterministic()
-        inviter.random.gauss = lambda mu, sigma: values.pop(0)
+        inviter.setParameters(inviteeDistanceDistribution=SequentialDistribution(values))
         inviter._invite()
         attendees = vevent.contents[u'vevent'][0].contents[u'attendee']
         self.assertEquals(len(attendees), 3)
@@ -387,9 +403,8 @@
         vevent, event, calendar, client = self._simpleAccount(
             selfNumber, INVITED_EVENT)
         inviter = Inviter(Clock(), self.sim, client, selfNumber)
-        inviter.random = Deterministic()
         # Always return a user number which has already been invited.
-        inviter.random.gauss = lambda mu, sigma: 2
+        inviter.setParameters(inviteeDistanceDistribution=Deterministic(2 - selfNumber))
         inviter._invite()
         attendees = vevent.contents[u'vevent'][0].contents[u'attendee']
         self.assertEquals(len(attendees), 2)
@@ -527,8 +542,7 @@
         client._setEvent(inboxEvent.url, inboxEvent)
 
         accepter = Accepter(clock, self.sim, client, userNumber)
-        accepter.random = Deterministic()
-        accepter.random.gauss = lambda mu, sigma: randomDelay
+        accepter.setParameters(Deterministic(randomDelay))
         accepter.eventChanged(event.url)
         clock.advance(randomDelay)
 
@@ -564,8 +578,7 @@
         event = Event(calendarURL + u'1234.ics', None, vevent)
         client._events[event.url] = event
         accepter = Accepter(clock, self.sim, client, userNumber)
-        accepter.random = Deterministic()
-        accepter.random.gauss = lambda mu, sigma: randomDelay
+        accepter.setParameters(Deterministic(randomDelay))
         accepter.eventChanged(event.url)
         clock.advance(randomDelay)
 
@@ -608,8 +621,7 @@
         client._setEvent(event.url, event)
 
         accepter = Accepter(clock, self.sim, client, userNumber)
-        accepter.random = Deterministic()
-        accepter.random.gauss = lambda mu, sigma: randomDelay
+        accepter.setParameters(Deterministic(randomDelay))
 
         client.rescheduled.add(event.url)
 

Modified: CalendarServer/trunk/contrib/performance/stats.py
===================================================================
--- CalendarServer/trunk/contrib/performance/stats.py	2011-06-03 00:31:41 UTC (rev 7552)
+++ CalendarServer/trunk/contrib/performance/stats.py	2011-06-03 19:57:35 UTC (rev 7553)
@@ -289,6 +289,19 @@
         return random.normalvariate(self._mu, self._sigma)
 
 
+
+class UniformIntegerDistribution(object, FancyEqMixin):
+    compareAttributes = ['_min', '_max']
+
+    def __init__(self, min, max):
+        self._min = min
+        self._max = max
+
+
+    def sample(self):
+        return int(random.uniform(self._min, self._max))
+
+
 NUM_WEEKDAYS = 7
 
 class WorkDistribution(object, FancyEqMixin):

Modified: CalendarServer/trunk/contrib/performance/test_stats.py
===================================================================
--- CalendarServer/trunk/contrib/performance/test_stats.py	2011-06-03 00:31:41 UTC (rev 7552)
+++ CalendarServer/trunk/contrib/performance/test_stats.py	2011-06-03 19:57:35 UTC (rev 7553)
@@ -18,7 +18,9 @@
 
 from twisted.trial.unittest import TestCase
 
-from stats import SQLDuration, LogNormalDistribution, UniformDiscreteDistribution, WorkDistribution, quantize
+from stats import (
+    SQLDuration, LogNormalDistribution, UniformDiscreteDistribution,
+    UniformIntegerDistribution, WorkDistribution, quantize)
 
 class SQLDurationTests(TestCase):
     def setUp(self):
@@ -76,7 +78,15 @@
             datetime(2011, 6, 4, 15, 30, 0), datetime.fromtimestamp(value)) 
 
 
+    def test_uniform(self):
+        dist = UniformIntegerDistribution(-5, 10)
+        for i in range(100):
+            value = dist.sample()
+            self.assertTrue(-5 <= value < 10)
+            self.assertIsInstance(value, int)
 
+
+
 class QuantizationTests(TestCase):
     """
     Tests for L{quantize} which constructs discrete datasets of
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20110603/d97c3175/attachment-0001.html>


More information about the calendarserver-changes mailing list