[tor-commits] [onionperf/develop] Avoid tracebacks when visualizing measurements.

karsten at torproject.org karsten at torproject.org
Sun Dec 13 21:58:58 UTC 2020


commit fe6ff0874dfd9b18bf5eb71c2394431ca44874bc
Author: Karsten Loesing <karsten.loesing at gmx.net>
Date:   Tue Nov 24 12:17:21 2020 +0100

    Avoid tracebacks when visualizing measurements.
    
    Attempting to visualize analysis files containing only unsuccessful
    measurements results in various tracebacks.
    
    With this patch we check more carefully whether a data frame is empty
    before adding a plot.
    
    Another related change is that we always include
    "time_to_{first,last}_byte" and "mbps" columns in the CSV output,
    regardless of whether there are there are any non-null values in the
    data. See also #40004 for a previous related change.
    
    And we check whether a Tor stream identifier exists before retrieving
    a Tor stream.
    
    Finally, we only include TTFB/TTLB if the usecs value is non-zero.
    
    Fixes #44012.
---
 CHANGELOG.md               |  5 +++++
 onionperf/visualization.py | 37 +++++++++++++++++++++++++------------
 2 files changed, 30 insertions(+), 12 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2c1f5ca..2655e01 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,8 @@
+# Changes in version 0.9 - 2020-1?-??
+
+ - Avoid tracebacks when visualizing analysis files containing only
+   unsuccessful measurements. Fixes #44012.
+
 # Changes in version 0.8 - 2020-09-16
 
  - Add a new `onionperf filter` mode that takes an OnionPerf analysis
diff --git a/onionperf/visualization.py b/onionperf/visualization.py
index 2cd3161..75ec2b5 100644
--- a/onionperf/visualization.py
+++ b/onionperf/visualization.py
@@ -66,6 +66,7 @@ class TGenVisualization(Visualization):
                     tgen_streams = analysis.get_tgen_streams(client)
                     tgen_transfers = analysis.get_tgen_transfers(client)
                     while tgen_streams or tgen_transfers:
+                        stream = {"time_to_first_byte": None, "time_to_last_byte": None, "error_code": None, "mbps": None}
                         error_code = None
                         source_port = None
                         unix_ts_end = None
@@ -76,15 +77,15 @@ class TGenVisualization(Visualization):
                         # that value with unit megabits per second.
                         if tgen_streams:
                             stream_id, stream_data = tgen_streams.popitem()
-                            stream = {"id": stream_id, "label": label,
-                                      "filesize_bytes": int(stream_data["stream_info"]["recvsize"]),
-                                      "error_code": None}
+                            stream["id"] = stream_id
+                            stream["label"] = label
+                            stream["filesize_bytes"] = int(stream_data["stream_info"]["recvsize"])
                             stream["server"] = "onion" if ".onion:" in stream_data["transport_info"]["remote"] else "public"
                             if "time_info" in stream_data:
                                 s = stream_data["time_info"]
-                                if "usecs-to-first-byte-recv" in s:
+                                if "usecs-to-first-byte-recv" in s and float(s["usecs-to-first-byte-recv"]) >= 0:
                                     stream["time_to_first_byte"] = float(s["usecs-to-first-byte-recv"])/1000000
-                                if "usecs-to-last-byte-recv" in s:
+                                if "usecs-to-last-byte-recv" in s and float(s["usecs-to-last-byte-recv"]) >= 0:
                                     stream["time_to_last_byte"] = float(s["usecs-to-last-byte-recv"])/1000000
                             if "elapsed_seconds" in stream_data:
                                 s = stream_data["elapsed_seconds"]
@@ -100,9 +101,9 @@ class TGenVisualization(Visualization):
                                 stream["start"] = datetime.datetime.utcfromtimestamp(stream_data["unix_ts_start"])
                         elif tgen_transfers:
                             transfer_id, transfer_data = tgen_transfers.popitem()
-                            stream = {"id": transfer_id, "label": label,
-                                      "filesize_bytes": transfer_data["filesize_bytes"],
-                                      "error_code": None}
+                            stream["id"] = transfer_id
+                            stream["label"] = label
+                            stream["filesize_bytes"] = transfer_data["filesize_bytes"]
                             stream["server"] = "onion" if ".onion:" in transfer_data["endpoint_remote"] else "public"
                             if "elapsed_seconds" in transfer_data:
                                s = transfer_data["elapsed_seconds"]
@@ -125,7 +126,7 @@ class TGenVisualization(Visualization):
                                 stream["start"] = datetime.datetime.utcfromtimestamp(transfer_data["unix_ts_start"])
                         tor_stream = None
                         tor_circuit = None
-                        if source_port and unix_ts_end:
+                        if source_port and source_port in tor_streams_by_source_port and unix_ts_end:
                             for s in tor_streams_by_source_port[source_port]:
                                 if abs(unix_ts_end - s["unix_ts_end"]) < 150.0:
                                     tor_stream = s
@@ -233,6 +234,8 @@ class TGenVisualization(Visualization):
 
     def __draw_ecdf(self, x, hue, hue_name, data, title, xlabel, ylabel):
         data = data.dropna(subset=[x])
+        if data.empty:
+            return
         p0 = data[x].quantile(q=0.0, interpolation="lower")
         p99 = data[x].quantile(q=0.99, interpolation="higher")
         ranks = data.groupby(hue)[x].rank(pct=True)
@@ -255,8 +258,10 @@ class TGenVisualization(Visualization):
         plt.close()
 
     def __draw_timeplot(self, x, y, hue, hue_name, data, title, xlabel, ylabel):
-        plt.figure()
         data = data.dropna(subset=[y])
+        if data.empty:
+            return
+        plt.figure()
         data = data.rename(columns={hue: hue_name})
         xmin = data[x].min()
         xmax = data[x].max()
@@ -271,8 +276,10 @@ class TGenVisualization(Visualization):
         plt.close()
 
     def __draw_boxplot(self, x, y, data, title, xlabel, ylabel):
-        plt.figure()
         data = data.dropna(subset=[y])
+        if data.empty:
+            return
+        plt.figure()
         g = sns.boxplot(data=data, x=x, y=y, sym="")
         g.set(title=title, xlabel=xlabel, ylabel=ylabel, ylim=(0, None))
         sns.despine()
@@ -280,8 +287,10 @@ class TGenVisualization(Visualization):
         plt.close()
 
     def __draw_barplot(self, x, y, data, title, xlabel, ylabel):
-        plt.figure()
         data = data.dropna(subset=[y])
+        if data.empty:
+            return
+        plt.figure()
         g = sns.barplot(data=data, x=x, y=y, ci=None)
         g.set(title=title, xlabel=xlabel, ylabel=ylabel)
         sns.despine()
@@ -289,6 +298,8 @@ class TGenVisualization(Visualization):
         plt.close()
 
     def __draw_countplot(self, x, data, title, xlabel, ylabel, hue=None, hue_name=None):
+        if data.empty:
+            return
         plt.figure()
         if hue is not None:
             data = data.rename(columns={hue: hue_name})
@@ -299,6 +310,8 @@ class TGenVisualization(Visualization):
         plt.close()
 
     def __draw_stripplot(self, x, y, hue, hue_name, data, title, xlabel, ylabel):
+        if data.empty:
+            return
         plt.figure()
         data = data.rename(columns={hue: hue_name})
         xmin = data[x].min()





More information about the tor-commits mailing list