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

source_changes at macosforge.org source_changes at macosforge.org
Wed Jul 11 10:07:28 PDT 2012


Revision: 9429
          http://trac.macosforge.org/projects/calendarserver/changeset/9429
Author:   cdaboo at apple.com
Date:     2012-07-11 10:07:27 -0700 (Wed, 11 Jul 2012)
Log Message:
-----------
Add the ability for the sim tool to generate recurring events with various RRULE patterns based on a distribution.

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

Modified: CalendarServer/trunk/contrib/performance/loadtest/config.dist.plist
===================================================================
--- CalendarServer/trunk/contrib/performance/loadtest/config.dist.plist	2012-07-11 01:17:35 UTC (rev 9428)
+++ CalendarServer/trunk/contrib/performance/loadtest/config.dist.plist	2012-07-11 17:07:27 UTC (rev 9429)
@@ -210,6 +210,52 @@
 									<string>America/Los_Angeles</string>
 								</dict>
 							</dict>
+
+							<!-- Define how recurrences are created. -->
+							<key>recurrenceDistribution</key>
+							<dict>
+
+								<!-- This distribution is pretty specialized.  We have a fixed set of
+								     RRULEs defined for this distribution and pick each based on a
+								     weight. -->
+								<key>type</key>
+								<string>contrib.performance.stats.RecurrenceDistribution</string>
+
+								<key>params</key>
+								<dict>
+									<!-- False to disable RRULEs -->
+									<key>allowRecurrence</key>
+									<true/>
+
+									<!-- These are the weights for the specific set of RRULEs. -->
+									<key>weights</key>
+									<dict>
+										<!-- Half of all events will be non-recurring -->
+										<key>none</key>
+										<integer>50</integer>
+										
+										<!-- Daily and weekly are pretty common -->
+										<key>daily</key>
+										<integer>10</integer>
+										<key>weekly</key>
+										<integer>20</integer>
+										
+										<!-- Monthly, yearly, daily & weekly limit not so common -->
+										<key>monthly</key>
+										<integer>2</integer>
+										<key>yearly</key>
+										<integer>1</integer>
+										<key>dailylimit</key>
+										<integer>2</integer>
+										<key>weeklylimit</key>
+										<integer>5</integer>
+										
+										<!-- Work days pretty common -->
+										<key>workdays</key>
+										<integer>10</integer>
+									</dict>
+								</dict>
+							</dict>
 						</dict>
 					</dict>
 
@@ -336,8 +382,8 @@
 									<!-- maximum -->
 									<key>maximum</key>
 									<real>100</real>
-						</dict>
-					</dict>
+								</dict>
+							</dict>
 
 							<!-- Define how start times (DTSTART) for the randomly generated events 
 								will be selected. This is an example of a "Distribution" parameter. The value 
@@ -378,6 +424,52 @@
 									<string>America/Los_Angeles</string>
 								</dict>
 							</dict>
+
+							<!-- Define how recurrences are created. -->
+							<key>recurrenceDistribution</key>
+							<dict>
+
+								<!-- This distribution is pretty specialized.  We have a fixed set of
+								     RRULEs defined for this distribution and pick each based on a
+								     weight. -->
+								<key>type</key>
+								<string>contrib.performance.stats.RecurrenceDistribution</string>
+
+								<key>params</key>
+								<dict>
+									<!-- False to disable RRULEs -->
+									<key>allowRecurrence</key>
+									<true/>
+
+									<!-- These are the weights for the specific set of RRULEs. -->
+									<key>weights</key>
+									<dict>
+										<!-- Half of all events will be non-recurring -->
+										<key>none</key>
+										<integer>50</integer>
+										
+										<!-- Daily and weekly are pretty common -->
+										<key>daily</key>
+										<integer>10</integer>
+										<key>weekly</key>
+										<integer>20</integer>
+										
+										<!-- Monthly, yearly, daily & weekly limit not so common -->
+										<key>monthly</key>
+										<integer>2</integer>
+										<key>yearly</key>
+										<integer>1</integer>
+										<key>dailylimit</key>
+										<integer>2</integer>
+										<key>weeklylimit</key>
+										<integer>5</integer>
+										
+										<!-- Work days pretty common -->
+										<key>workdays</key>
+										<integer>10</integer>
+									</dict>
+								</dict>
+							</dict>
 						</dict>
 					</dict>
 

Modified: CalendarServer/trunk/contrib/performance/loadtest/config.plist
===================================================================
--- CalendarServer/trunk/contrib/performance/loadtest/config.plist	2012-07-11 01:17:35 UTC (rev 9428)
+++ CalendarServer/trunk/contrib/performance/loadtest/config.plist	2012-07-11 17:07:27 UTC (rev 9429)
@@ -204,6 +204,52 @@
 									<string>America/Los_Angeles</string>
 								</dict>
 							</dict>
+
+							<!-- Define how recurrences are created. -->
+							<key>recurrenceDistribution</key>
+							<dict>
+
+								<!-- This distribution is pretty specialized.  We have a fixed set of
+								     RRULEs defined for this distribution and pick each based on a
+								     weight. -->
+								<key>type</key>
+								<string>contrib.performance.stats.RecurrenceDistribution</string>
+
+								<key>params</key>
+								<dict>
+									<!-- False to disable RRULEs -->
+									<key>allowRecurrence</key>
+									<true/>
+
+									<!-- These are the weights for the specific set of RRULEs. -->
+									<key>weights</key>
+									<dict>
+										<!-- Half of all events will be non-recurring -->
+										<key>none</key>
+										<integer>50</integer>
+										
+										<!-- Daily and weekly are pretty common -->
+										<key>daily</key>
+										<integer>10</integer>
+										<key>weekly</key>
+										<integer>20</integer>
+										
+										<!-- Monthly, yearly, daily & weekly limit not so common -->
+										<key>monthly</key>
+										<integer>2</integer>
+										<key>yearly</key>
+										<integer>1</integer>
+										<key>dailylimit</key>
+										<integer>2</integer>
+										<key>weeklylimit</key>
+										<integer>5</integer>
+										
+										<!-- Work days pretty common -->
+										<key>workdays</key>
+										<integer>10</integer>
+									</dict>
+								</dict>
+							</dict>
 						</dict>
 					</dict>
 
@@ -372,6 +418,52 @@
 									<string>America/Los_Angeles</string>
 								</dict>
 							</dict>
+
+							<!-- Define how recurrences are created. -->
+							<key>recurrenceDistribution</key>
+							<dict>
+
+								<!-- This distribution is pretty specialized.  We have a fixed set of
+								     RRULEs defined for this distribution and pick each based on a
+								     weight. -->
+								<key>type</key>
+								<string>contrib.performance.stats.RecurrenceDistribution</string>
+
+								<key>params</key>
+								<dict>
+									<!-- False to disable RRULEs -->
+									<key>allowRecurrence</key>
+									<true/>
+
+									<!-- These are the weights for the specific set of RRULEs. -->
+									<key>weights</key>
+									<dict>
+										<!-- Half of all events will be non-recurring -->
+										<key>none</key>
+										<integer>50</integer>
+										
+										<!-- Daily and weekly are pretty common -->
+										<key>daily</key>
+										<integer>10</integer>
+										<key>weekly</key>
+										<integer>20</integer>
+										
+										<!-- Monthly, yearly, daily & weekly limit not so common -->
+										<key>monthly</key>
+										<integer>2</integer>
+										<key>yearly</key>
+										<integer>1</integer>
+										<key>dailylimit</key>
+										<integer>2</integer>
+										<key>weeklylimit</key>
+										<integer>5</integer>
+										
+										<!-- Work days pretty common -->
+										<key>workdays</key>
+										<integer>10</integer>
+									</dict>
+								</dict>
+							</dict>
 						</dict>
 					</dict>
 

Modified: CalendarServer/trunk/contrib/performance/loadtest/ical.py
===================================================================
--- CalendarServer/trunk/contrib/performance/loadtest/ical.py	2012-07-11 01:17:35 UTC (rev 9428)
+++ CalendarServer/trunk/contrib/performance/loadtest/ical.py	2012-07-11 17:07:27 UTC (rev 9429)
@@ -342,7 +342,7 @@
         calendarHomePollInterval=None,
         supportPush=True,
         supportAmpPush=True,
-        ampPushHost="localhost",
+        ampPushHost=None,
         ampPushPort=62311,
     ):
         
@@ -366,6 +366,8 @@
         self.supportPush = supportPush
 
         self.supportAmpPush = supportAmpPush
+        if ampPushHost is None:
+            ampPushHost = urlparse(self.root)[1].split(":")[0]
         self.ampPushHost = ampPushHost
         self.ampPushPort = ampPushPort
 
@@ -886,7 +888,11 @@
     
             multistatus = yield self._eventReport(calendar.url, batchedHrefs)
             for responseHref in batchedHrefs:
-                res = multistatus[responseHref]
+                try:
+                    res = multistatus[responseHref]
+                except KeyError:
+                    # Resource might have been deleted
+                    continue
                 if res.getStatus() == 200:
                     text = res.getTextProperties()
                     etag = text[davxml.getetag]

Modified: CalendarServer/trunk/contrib/performance/loadtest/profiles.py
===================================================================
--- CalendarServer/trunk/contrib/performance/loadtest/profiles.py	2012-07-11 01:17:35 UTC (rev 9428)
+++ CalendarServer/trunk/contrib/performance/loadtest/profiles.py	2012-07-11 17:07:27 UTC (rev 9429)
@@ -37,7 +37,7 @@
 from twistedcaldav.ical import Property, Component
 
 from contrib.performance.stats import NearFutureDistribution, NormalDistribution, UniformDiscreteDistribution, mean, median
-from contrib.performance.stats import LogNormalDistribution
+from contrib.performance.stats import LogNormalDistribution, RecurrenceDistribution
 from contrib.performance.loadtest.logger import SummarizingMixin
 from contrib.performance.loadtest.ical import IncorrectResponseCode
 
@@ -298,7 +298,8 @@
             15 * 60, 30 * 60,
             45 * 60, 60 * 60,
             120 * 60
-        ])
+        ]),
+        recurrenceDistribution=RecurrenceDistribution(False),
     ):
         self.enabled = enabled
         self._sendInvitationDistribution = sendInvitationDistribution
@@ -306,6 +307,7 @@
         self._inviteeCountDistribution = inviteeCountDistribution
         self._eventStartDistribution = eventStartDistribution
         self._eventDurationDistribution = eventDurationDistribution
+        self._recurrenceDistribution = recurrenceDistribution
 
 
     def run(self):
@@ -386,6 +388,10 @@
             vevent.replaceProperty(Property("DTSTART", dtstart))
             vevent.replaceProperty(Property("DTEND", dtend))
             vevent.replaceProperty(Property("UID", uid))
+            
+            rrule = self._recurrenceDistribution.sample()
+            if rrule is not None:
+                vevent.addProperty(Property(None, None, None, pycalendar=rrule))
 
             vevent.addProperty(self._client._makeSelfOrganizer())
             vevent.addProperty(self._client._makeSelfAttendee())
@@ -582,12 +588,14 @@
             15 * 60, 30 * 60,
             45 * 60, 60 * 60,
             120 * 60
-        ])
+        ]),
+        recurrenceDistribution=RecurrenceDistribution(False),
     ):
         self.enabled = enabled
         self._interval = interval
         self._eventStartDistribution = eventStartDistribution
         self._eventDurationDistribution = eventDurationDistribution
+        self._recurrenceDistribution = recurrenceDistribution
 
 
     def run(self):
@@ -618,6 +626,10 @@
             vevent.replaceProperty(Property("DTSTART", dtstart))
             vevent.replaceProperty(Property("DTEND", dtend))
             vevent.replaceProperty(Property("UID", uid))
+            
+            rrule = self._recurrenceDistribution.sample()
+            if rrule is not None:
+                vevent.addProperty(Property(None, None, None, pycalendar=rrule))
 
             href = '%s%s.ics' % (calendar.url, uid)
             d = self._client.addEvent(href, vcalendar)

Modified: CalendarServer/trunk/contrib/performance/stats.py
===================================================================
--- CalendarServer/trunk/contrib/performance/stats.py	2012-07-11 01:17:35 UTC (rev 9428)
+++ CalendarServer/trunk/contrib/performance/stats.py	2012-07-11 17:07:27 UTC (rev 9429)
@@ -24,6 +24,7 @@
 from pycalendar.datetime import PyCalendarDateTime
 from pycalendar.duration import PyCalendarDuration
 from pycalendar.timezone import PyCalendarTimezone
+from pycalendar.property import PyCalendarProperty
 
 NANO = 1000000000.0
 
@@ -222,7 +223,7 @@
 
 
 class IPopulation(Interface):
-    def sample():
+    def sample(): #@NoSelf
         pass
 
 
@@ -234,14 +235,16 @@
 
     compareAttributes = ['_values']
 
-    def __init__(self, values):
+    def __init__(self, values, randomize=True):
         self._values = values
+        self._randomize = randomize
         self._refill()
 
 
     def _refill(self):
         self._remaining = self._values[:]
-        random.shuffle(self._remaining)
+        if self._randomize:
+            random.shuffle(self._remaining)
 
 
     def sample(self):
@@ -378,6 +381,42 @@
             offset.setDuration(offset.getTotalSeconds() - (end - start).getTotalSeconds())
             beginning = end
 
+class RecurrenceDistribution(object, FancyEqMixin):
+    compareAttributes = ["_allowRecurrence", "_weights"]
+
+    _model_rrules = {
+        "none":        None,
+        "daily":       "RRULE:FREQ=DAILY",
+        "weekly":      "RRULE:FREQ=WEEKLY",
+        "monthly":     "RRULE:FREQ=MONTHLY",
+        "yearly":      "RRULE:FREQ=YEARLY",
+        "dailylimit":  "RRULE:FREQ=DAILY;COUNT=14",
+        "weeklylimit": "RRULE:FREQ=WEEKLY;COUNT=4",
+        "workdays":    "RRULE:FREQ=DAILY;BYDAY=MO,TU,WE,TH,FR"
+    } 
+
+    def __init__(self, allowRecurrence, weights={}):
+        self._allowRecurrence = allowRecurrence
+        self._rrules = []
+        if self._allowRecurrence:
+            for rrule, count in sorted(weights.items(), key=lambda x:x[0]):
+                for _ignore in range(count):
+                    self._rrules.append(self._model_rrules[rrule])
+        self._helperDistribution = UniformIntegerDistribution(0, len(self._rrules)-1)
+
+
+    def sample(self):
+        
+        if self._allowRecurrence:
+            index = self._helperDistribution.sample()
+            rrule = self._rrules[index]
+            if rrule:
+                prop = PyCalendarProperty()
+                prop.parse(rrule)
+                return prop
+        
+        return None
+
 if __name__ == '__main__':
     
     from collections import defaultdict

Modified: CalendarServer/trunk/contrib/performance/test_stats.py
===================================================================
--- CalendarServer/trunk/contrib/performance/test_stats.py	2012-07-11 01:17:35 UTC (rev 9428)
+++ CalendarServer/trunk/contrib/performance/test_stats.py	2012-07-11 17:07:27 UTC (rev 9429)
@@ -1,5 +1,5 @@
 ##
-# Copyright (c) 2010 Apple Inc. All rights reserved.
+# Copyright (c) 2010-2012 Apple Inc. All rights reserved.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -18,7 +18,8 @@
 
 from stats import (
     SQLDuration, LogNormalDistribution, UniformDiscreteDistribution,
-    UniformIntegerDistribution, WorkDistribution, quantize)
+    UniformIntegerDistribution, WorkDistribution, quantize,
+    RecurrenceDistribution)
 from pycalendar.datetime import PyCalendarDateTime
 from pycalendar.timezone import PyCalendarTimezone
 
@@ -91,6 +92,25 @@
     #test_workdistribution.todo = "Somehow timezones mess this up"
 
 
+    def test_recurrencedistribution(self):
+        dist = RecurrenceDistribution(False)
+        for _ignore in range(100):
+            value = dist.sample()
+            self.assertTrue(value is None)
+
+        dist = RecurrenceDistribution(True, {"daily":1, "none":2, "weekly":1})
+        dist._helperDistribution = UniformDiscreteDistribution([0, 3, 2, 1, 0], randomize=False)
+        value = dist.sample()
+        self.assertTrue(value is not None)
+        value = dist.sample()
+        self.assertTrue(value is None)
+        value = dist.sample()
+        self.assertTrue(value is None)
+        value = dist.sample()
+        self.assertTrue(value is not None)
+        value = dist.sample()
+        self.assertTrue(value is not None)
+
     def test_uniform(self):
         dist = UniformIntegerDistribution(-5, 10)
         for _ignore_i in range(100):
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20120711/cc6aa5af/attachment-0001.html>


More information about the calendarserver-changes mailing list