From e8b0f3d3cb40a00ef69362641a4f77a0f08d5a74 Mon Sep 17 00:00:00 2001
From: Brian Warner <warner@allmydata.com>
Date: Mon, 21 Apr 2008 16:16:55 -0700
Subject: [PATCH] mutable status: use google-chart-API to draw server response
 times for servermap update

---
 src/allmydata/mutable/servermap.py        |  2 +-
 src/allmydata/web/map-update-status.xhtml |  4 +-
 src/allmydata/web/status.py               | 70 ++++++++++++++++++++++-
 3 files changed, 71 insertions(+), 5 deletions(-)

diff --git a/src/allmydata/mutable/servermap.py b/src/allmydata/mutable/servermap.py
index 25aa29f4..79a25dd8 100644
--- a/src/allmydata/mutable/servermap.py
+++ b/src/allmydata/mutable/servermap.py
@@ -425,7 +425,7 @@ class ServermapUpdater:
         # enough responses)
 
         self._send_initial_requests(initial_peers_to_query)
-        self._status.timings["setup"] = time.time() - self._started
+        self._status.timings["initial_queries"] = time.time() - self._started
         return self._done_deferred
 
     def _build_initial_querylist(self):
diff --git a/src/allmydata/web/map-update-status.xhtml b/src/allmydata/web/map-update-status.xhtml
index 69e39117..9a354487 100644
--- a/src/allmydata/web/map-update-status.xhtml
+++ b/src/allmydata/web/map-update-status.xhtml
@@ -22,11 +22,11 @@
 <h2>Update Results</h2>
 <ul>
   <li n:render="problems" />
-  <li>Timings:</li>
+  <li>Timings: <span n:render="timing_chart" /></li>
   <ul>
     <li>Total: <span n:render="time" n:data="time_total" /></li>
     <ul>
-      <li>Setup: <span n:render="time" n:data="time_setup" /></li>
+      <li>Initial Queries: <span n:render="time" n:data="time_initial_queries" /></li>
       <li n:render="privkey_from" />
       <li>Cumulative Verify: <span n:render="time" n:data="time_cumulative_verify" /></li>
     </ul>
diff --git a/src/allmydata/web/status.py b/src/allmydata/web/status.py
index b9b40c15..83e3773a 100644
--- a/src/allmydata/web/status.py
+++ b/src/allmydata/web/status.py
@@ -675,8 +675,8 @@ class MapupdateStatusPage(rend.Page, RateAndTimeMixin):
     def data_time_total(self, ctx, data):
         return self.update_status.timings.get("total")
 
-    def data_time_setup(self, ctx, data):
-        return self.update_status.timings.get("setup")
+    def data_time_initial_queries(self, ctx, data):
+        return self.update_status.timings.get("initial_queries")
 
     def data_time_cumulative_verify(self, ctx, data):
         return self.update_status.timings.get("cumulative_verify")
@@ -690,6 +690,10 @@ class MapupdateStatusPage(rend.Page, RateAndTimeMixin):
             peerid_s = idlib.shortnodeid_b2a(peerid)
             times = []
             for op,started,t in per_server[peerid]:
+                #times.append("%s/%.4fs/%s/%s" % (op,
+                #                              started,
+                #                              self.render_time(None, started - self.update_status.get_started()),
+                #                              self.render_time(None,t)))
                 if op == "query":
                     times.append( self.render_time(None, t) )
                 elif op == "late":
@@ -700,6 +704,68 @@ class MapupdateStatusPage(rend.Page, RateAndTimeMixin):
             l[T.li["[%s]: %s" % (peerid_s, times_s)]]
         return T.li["Per-Server Response Times: ", l]
 
+    def render_timing_chart(self, ctx, data):
+        imageurl = self._timing_chart()
+        return ctx.tag[imageurl]
+
+    def _timing_chart(self):
+        started = self.update_status.get_started()
+        total = self.update_status.timings["total"]
+        per_server = self.update_status.timings.get("per_server")
+        base = "http://chart.apis.google.com/chart?"
+        pieces = ["cht=bhs", "chs=400x300"]
+        pieces.append("chco=ffffff,4d89f9,c6d9fd") # colors
+        data0 = []
+        data1 = []
+        data2 = []
+        peerids_s = []
+        top_abs = started
+        # we sort the queries by the time at which we sent the first request
+        sorttable = [ (times[0][1], peerid)
+                      for peerid, times in per_server.items() ]
+        sorttable.sort()
+        peerids = [t[1] for t in sorttable]
+            
+        for peerid in peerids:
+            times = per_server[peerid]
+            peerid_s = idlib.shortnodeid_b2a(peerid)
+            peerids_s.append(peerid_s)
+            # for servermap updates, there are either one or two queries per
+            # peer. The second (if present) is to get the privkey.
+            op,q_started,q_elapsed = times[0]
+            data0.append("%.3f" % (q_started-started))
+            data1.append("%.3f" % q_elapsed)
+            top_abs = max(top_abs, q_started+q_elapsed)
+            if len(times) > 1:
+                op,p_started,p_elapsed = times[0]
+                data2.append("%.3f" % p_elapsed)
+                top_abs = max(top_abs, p_started+p_elapsed)
+            else:
+                data2.append("0.0")
+        finished = self.update_status.get_finished()
+        if finished:
+            top_abs = max(top_abs, finished)
+        top_rel = top_abs - started
+        chd = "chd=t:" + "|".join([",".join(data0),
+                                   ",".join(data1),
+                                   ",".join(data2)])
+        pieces.append(chd)
+        chds = "chds=0,%0.3f" % top_rel
+        pieces.append(chds)
+        pieces.append("chxt=x,y")
+        pieces.append("chxr=0,0.0,%0.3f" % top_rel)
+        pieces.append("chxl=1:|" + "|".join(reversed(peerids_s)))
+        # use up to 10 grid lines, at decimal multiples.
+        # mathutil.next_power_of_k doesn't handle numbers smaller than one,
+        # unfortunately.
+        #pieces.append("chg="
+        # this chm=r thing is being interpreted as 1.0=fullscale
+        finished_f = 1.0 * total / top_rel
+        pieces.append("chm=r,FF0000,0,%0.3f,%0.3f" % (finished_f,
+                                                      finished_f+0.01))
+        url = base + "&".join(pieces)
+        return T.img(src=url, align="right", float="right")
+
 
 class Status(rend.Page):
     docFactory = getxmlfile("status.xhtml")
-- 
2.45.2