[CalendarServer-changes] [6722] CalendarServer/trunk/contrib/performance/loadtest

source_changes at macosforge.org source_changes at macosforge.org
Mon Jan 10 11:46:13 PST 2011


Revision: 6722
          http://trac.macosforge.org/projects/calendarserver/changeset/6722
Author:   exarkun at twistedmatrix.com
Date:     2011-01-10 11:46:05 -0800 (Mon, 10 Jan 2011)
Log Message:
-----------
Collect success/failure results and start to summarize collected statistics like the existing ccs report does

Modified Paths:
--------------
    CalendarServer/trunk/contrib/performance/loadtest/ical.py
    CalendarServer/trunk/contrib/performance/loadtest/population.py

Modified: CalendarServer/trunk/contrib/performance/loadtest/ical.py
===================================================================
--- CalendarServer/trunk/contrib/performance/loadtest/ical.py	2011-01-10 18:30:40 UTC (rev 6721)
+++ CalendarServer/trunk/contrib/performance/loadtest/ical.py	2011-01-10 19:46:05 UTC (rev 6722)
@@ -26,6 +26,7 @@
 from twisted.internet.defer import Deferred, inlineCallbacks, returnValue
 from twisted.internet.task import LoopingCall
 from twisted.web.http_headers import Headers
+from twisted.web.http import OK, MULTI_STATUS
 from twisted.web.client import Agent
 
 from protocol.webdav.propfindparser import PropFindParser
@@ -94,18 +95,20 @@
         self._events = {}
 
 
-    def _request(self, method, url, headers, body):
-        # XXX Do return code checking here.
+    def _request(self, expectedResponseCode, method, url, headers, body):
         headers.setRawHeaders('User-Agent', [self.USER_AGENT])
         d = self.agent.request(method, url, headers, body)
         before = self.reactor.seconds()
-        def report(passthrough):
+        def report(response):
+            success = response.code == expectedResponseCode
             after = self.reactor.seconds()
             # XXX This is time to receive response headers, not time
             # to receive full response.  Should measure the latter, if
             # not both.
-            msg(type="request", duration=(after - before), url=url)
-            return passthrough
+            msg(
+                type="request", success=success, method=method,
+                duration=(after - before), url=url)
+            return response
         d.addCallback(report)
         return d
 
@@ -162,6 +165,7 @@
         """
         principalURL = '/principals/__uids__/' + user + '/'
         d = self._request(
+            MULTI_STATUS,
             'PROPFIND',
             self.root + principalURL[1:],
             Headers({
@@ -178,6 +182,7 @@
         if principalCollectionSet.startswith('/'):
             principalCollectionSet = principalCollectionSet[1:]
         d = self._request(
+            OK,
             'REPORT',
             self.root + principalCollectionSet,
             Headers({
@@ -194,6 +199,7 @@
         if not calendarHomeSet.endswith('/'):
             calendarHomeSet = calendarHomeSet + '/'
         d = self._request(
+            MULTI_STATUS,
             'PROPFIND',
             self.root + calendarHomeSet,
             Headers({
@@ -214,6 +220,7 @@
         # First do a PROPFIND on the calendar to learn about events it
         # might have.
         response = yield self._request(
+            MULTI_STATUS,
             'PROPFIND',
             self.root + url,
             Headers({'content-type': ['text/xml'], 'depth': ['1']}),
@@ -244,6 +251,7 @@
         # Next do a REPORT on each event that might have information
         # we don't know about.
         return self._request(
+            MULTI_STATUS,
             'REPORT',
             self.root + calendar,
             Headers({'content-type': ['text/xml']}),
@@ -265,6 +273,7 @@
         if notificationURL.startswith('/'):
             notificationURL = notificationURL[1:]
         d = self._request(
+            MULTI_STATUS,
             'PROPFIND',
             self.root + notificationURL,
             Headers({
@@ -280,6 +289,7 @@
         if principalURL.startswith('/'):
             principalURL = principalURL[1:]
         d = self._request(
+            OK,
             'REPORT',
             self.root + principalURL,
             Headers({

Modified: CalendarServer/trunk/contrib/performance/loadtest/population.py
===================================================================
--- CalendarServer/trunk/contrib/performance/loadtest/population.py	2011-01-10 18:30:40 UTC (rev 6721)
+++ CalendarServer/trunk/contrib/performance/loadtest/population.py	2011-01-10 19:46:05 UTC (rev 6722)
@@ -105,20 +105,82 @@
 
 
 
-class Statistics(object):
+class StatisticsBase(object):
+    def observe(self, event):
+        if event.get('type') == 'request':
+            self.eventReceived(event)
+
+
+
+class SimpleStatistics(StatisticsBase):
     def __init__(self):
         self._times = []
 
-    def observe(self, event):
-        if event.get('type') == 'request':
-            self._times.append(event['duration'])
-            if len(self._times) == 200:
-                print 'mean:', mean(self._times)
-                print 'median:', median(self._times)
-                print 'stddev:', stddev(self._times)
-                print 'mad:', mad(self._times)
-                del self._times[:100]
 
+    def eventReceived(self, event):
+        self._times.append(event['duration'])
+        if len(self._times) == 200:
+            print 'mean:', mean(self._times)
+            print 'median:', median(self._times)
+            print 'stddev:', stddev(self._times)
+            print 'mad:', mad(self._times)
+            del self._times[:100]
+
+
+
+class ReportStatistics(StatisticsBase):
+    _fields = [
+        ('operation', 10, '%10s'),
+        ('count', 8, '%8s'),
+        ('failed', 8, '%8s'),
+        ('>3sec', 8, '%8s'),
+        ('mean', 8, '%8.4f'),
+        ('median', 8, '%8.4f'),
+        ]
+
+    def __init__(self):
+        self._perMethodTimes = {}
+
+
+    def eventReceived(self, event):
+        dataset = self._perMethodTimes.setdefault(event['method'], [])
+        dataset.append((event['success'], event['duration']))
+
+
+    def _printHeader(self):
+        format = []
+        labels = []
+        for (label, width, fmt) in self._fields:
+            format.append('%%%ds' % (width,))
+            labels.append(label)
+        print ''.join(format) % tuple(labels)
+
+
+    def _summarizeData(self, method, data):
+        failed = 0
+        threesec = 0
+        durations = []
+        for (success, duration) in data:
+            if not success:
+                failed += 1
+            if duration > 3:
+                threesec += 1
+            durations.append(duration)
+
+        return method, len(data), failed, threesec, mean(durations), median(durations)
+
+
+    def _printData(self, *values):
+        format = ''.join(fmt for (label, width, fmt) in self._fields)
+        print format % values
+
+
+    def summarize(self):
+        print
+        self._printHeader()
+        for method, data in self._perMethodTimes.iteritems():
+            self._printData(*self._summarizeData(method, data))
+
     
 def main():
     import random
@@ -127,7 +189,9 @@
     from twisted.internet.task import LoopingCall
     from twisted.python.log import addObserver
 
-    addObserver(Statistics().observe)
+    report = ReportStatistics()
+    addObserver(SimpleStatistics().observe)
+    addObserver(report.observe)
 
     r = random.Random()
     r.seed(100)
@@ -142,6 +206,7 @@
     reactor.callLater(3 * 90, call.stop)
 
     reactor.run()
+    report.summarize()
 
 if __name__ == '__main__':
     main()
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20110110/d1e63c3d/attachment-0001.html>


More information about the calendarserver-changes mailing list