[tor-commits] [arm/master] Rewriting prepopulate_from_state()

atagar at torproject.org atagar at torproject.org
Sun Nov 16 01:38:34 UTC 2014


commit a3beb2e196980af0e69a5b4aec9e9909b4c63283
Author: Damian Johnson <atagar at torproject.org>
Date:   Sat Nov 15 17:04:28 2014 -0800

    Rewriting prepopulate_from_state()
    
    Moving the function into the BandwidthStats class, and rewriting it to be both
    more succinct and less wrong. Few obvious issues...
---
 arm/graph_panel.py                |   85 +++++++++++++++++--------------------
 arm/util/__init__.py              |    6 +--
 test/util/bandwidth_from_state.py |    4 +-
 3 files changed, 45 insertions(+), 50 deletions(-)

diff --git a/arm/graph_panel.py b/arm/graph_panel.py
index 612cbf2..af6751e 100644
--- a/arm/graph_panel.py
+++ b/arm/graph_panel.py
@@ -160,8 +160,6 @@ class GraphCategory(object):
       self.primary_header_stats = []
       self.secondary_header_stats = []
 
-      tor_controller().add_event_listener(self.bandwidth_event, EventType.BW)
-
   def y_axis_label(self, value, is_primary):
     """
     Provides the label we should display on our y-axis.
@@ -262,6 +260,39 @@ class BandwidthStats(GraphCategory):
 
     self.title_stats = stats
 
+  def prepopulate_from_state(self):
+    """
+    Attempts to use tor's state file to prepopulate values for the 15 minute
+    interval via the BWHistoryReadValues/BWHistoryWriteValues values.
+
+    :returns: **float** for the number of seconds of data missing
+
+    :raises: **ValueError** if unable to get the bandwidth information from our
+      state file
+    """
+
+    def update_values(stat, entries, latest_time):
+      # fill missing entries with the last value
+
+      missing_entries = int((time.time() - latest_time) / 900)
+      entries = entries + [entries[-1]] * missing_entries
+
+      # pad if too short and truncate if too long
+
+      entry_count = CONFIG['features.graph.max_width']
+      entries = [0] * (entry_count - len(entries)) + entries[-entry_count:]
+
+      stat.values[Interval.FIFTEEN_MINUTE] = entries
+      stat.max_value[Interval.FIFTEEN_MINUTE] = max(entries)
+      stat.latest_value = entries[-1] * 900
+
+    stats = bandwidth_from_state()
+
+    update_values(self.primary, stats.read_entries, stats.last_read_time)
+    update_values(self.secondary, stats.write_entries, stats.last_write_time)
+
+    return time.time() - min(stats.last_read_time, stats.last_write_time)
+
   def _size_label(self, byte_count, decimal = 1):
     """
     Alias for str_tools.size_label() that accounts for if the user prefers bits
@@ -348,23 +379,26 @@ class GraphPanel(panel.Panel):
 
     controller = tor_controller()
 
-    if CONFIG['features.graph.bw.prepopulate'] and controller.is_alive():
+    if controller.is_alive() and CONFIG['features.graph.bw.prepopulate']:
       try:
-        missing_seconds = prepopulate_from_state(self.stats[GraphStat.BANDWIDTH])
+        missing_seconds = self.stats[GraphStat.BANDWIDTH].prepopulate_from_state()
 
         if missing_seconds:
           log.notice(msg('panel.graphing.prepopulation_successful', duration = str_tools.time_label(missing_seconds, 0, True)))
         else:
           log.notice(msg('panel.graphing.prepopulation_all_successful'))
 
-        self.update_interval = '15 minute'
+        self.update_interval = Interval.FIFTEEN_MINUTE
       except ValueError as exc:
-        log.info(msg('panel.graphing.prepopulation_failure', error = str(exc)))
+        log.info(msg('panel.graphing.prepopulation_failure', error = exc))
 
     controller.add_event_listener(self.bandwidth_event, EventType.BW)
     controller.add_status_listener(self.reset_listener)
 
   def bandwidth_event(self, event):
+    for stat in self.stats.values():
+      stat.bandwidth_event(event)
+
     if not CONFIG['features.graph.bw.accounting.show']:
       self._accounting_stats = None
     elif not self._accounting_stats or time.time() - self._accounting_stats.retrieved >= ACCOUNTING_RATE:
@@ -723,42 +757,3 @@ class GraphPanel(panel.Panel):
       return dict([(key, type(self.stats[key])(self.stats[key])) for key in self.stats])
     else:
       return panel.Panel.copy_attr(self, attr)
-
-
-def prepopulate_from_state(stat):
-  """
-  Attempts to use tor's state file to prepopulate values for the 15 minute
-  interval via the BWHistoryReadValues/BWHistoryWriteValues values. This
-  returns True if successful and False otherwise.
-  """
-
-  stats = bandwidth_from_state()
-
-  missing_read_entries = int((time.time() - stats.last_read_time) / 900)
-  missing_write_entries = int((time.time() - stats.last_write_time) / 900)
-
-  # fills missing entries with the last value
-
-  bw_read_entries = stats.read_entries + [stats.read_entries[-1]] * missing_read_entries
-  bw_write_entries = stats.write_entries + [stats.write_entries[-1]] * missing_write_entries
-
-  # crops starting entries so they're the same size
-
-  entry_count = min(len(bw_read_entries), len(bw_write_entries), CONFIG['features.graph.max_width'])
-  bw_read_entries = bw_read_entries[len(bw_read_entries) - entry_count:]
-  bw_write_entries = bw_write_entries[len(bw_write_entries) - entry_count:]
-
-  # fills the graphing parameters with state information
-
-  for i in range(entry_count):
-    read_value, write_value = bw_read_entries[i] * 1024, bw_write_entries[i] * 1024  # KB => B
-
-    stat.primary.latest_value, stat.secondary.latest_value = read_value / 900, write_value / 900
-
-    stat.primary.values['15 minute'] = [read_value] + stat.primary.values['15 minute'][:-1]
-    stat.secondary.values['15 minute'] = [write_value] + stat.secondary.values['15 minute'][:-1]
-
-  stat.primary.max_value['15 minute'] = max(stat.primary.values)
-  stat.secondary.max_value['15 minute'] = max(stat.secondary.values)
-
-  return time.time() - min(stats.last_read_time, stats.last_write_time)
diff --git a/arm/util/__init__.py b/arm/util/__init__.py
index c410284..9546642 100644
--- a/arm/util/__init__.py
+++ b/arm/util/__init__.py
@@ -92,7 +92,7 @@ def bandwidth_from_state(config):
 
     * read_entries and write_entries
 
-      List of the average kilobytes read or written during each fifteen minute
+      List of the average bytes read or written during each fifteen minute
       period, oldest to newest.
 
     * last_read_time and last_write_time
@@ -151,9 +151,9 @@ def bandwidth_from_state(config):
     line = line.strip()
 
     if line.startswith('BWHistoryReadValues '):
-      attr['read_entries'] = [int(entry) / 1024.0 / 900 for entry in line[20:].split(',')[:-1]]
+      attr['read_entries'] = [int(entry) / 900 for entry in line[20:].split(',')[:-1]]
     elif line.startswith('BWHistoryWriteValues '):
-      attr['write_entries'] = [int(entry) / 1024.0 / 900 for entry in line[21:].split(',')[:-1]]
+      attr['write_entries'] = [int(entry) / 900 for entry in line[21:].split(',')[:-1]]
     elif line.startswith('BWHistoryReadEnds '):
       attr['last_read_time'] = calendar.timegm(time.strptime(line[18:], '%Y-%m-%d %H:%M:%S')) - 900
     elif line.startswith('BWHistoryWriteEnds '):
diff --git a/test/util/bandwidth_from_state.py b/test/util/bandwidth_from_state.py
index b84c251..6877371 100644
--- a/test/util/bandwidth_from_state.py
+++ b/test/util/bandwidth_from_state.py
@@ -105,7 +105,7 @@ class TestBandwidthFromState(unittest.TestCase):
     open_mock.return_value = io.BytesIO(STATE_FILE_WITH_ENTRIES % (timestamp, timestamp))
 
     stats = bandwidth_from_state()
-    self.assertEqual([1, 2, 3, 4], stats.read_entries)
-    self.assertEqual([50, 50, 100, 100], stats.write_entries)
+    self.assertEqual([1024, 2048, 3072, 4096], stats.read_entries)
+    self.assertEqual([51200, 51200, 102400, 102400], stats.write_entries)
     self.assertEqual(now, stats.last_read_time)
     self.assertEqual(now, stats.last_write_time)





More information about the tor-commits mailing list