Improve Yardstick user-guide
[yardstick.git] / yardstick / plot / plotter.py
index f3fb75d..2f1f252 100644 (file)
@@ -9,24 +9,30 @@
 # http://www.apache.org/licenses/LICENSE-2.0
 ##############################################################################
 
-''' yardstick-plot - a command line tool for visualizing results from the
+""" yardstick-plot - a command line tool for visualizing results from the
     output file of yardstick framework.
 
     Example invocation:
     $ yardstick-plot -i /tmp/yardstick.out -o /tmp/plots/
-'''
+"""
+
+from __future__ import absolute_import
+from __future__ import print_function
 
 import argparse
-import json
 import os
 import sys
 import time
-import matplotlib.pyplot as plt
+
 import matplotlib.lines as mlines
+import matplotlib.pyplot as plt
+from oslo_serialization import jsonutils
+from six.moves import range
+from six.moves import zip
 
 
 class Parser(object):
-    ''' Command-line argument and input file parser for yardstick-plot tool'''
+    """ Command-line argument and input file parser for yardstick-plot tool"""
 
     def __init__(self):
         self.data = {
@@ -36,14 +42,15 @@ class Parser(object):
             'fio': []
         }
         self.default_input_loc = "/tmp/yardstick.out"
+        self.scenarios = {}
 
     def _get_parser(self):
-        '''get a command-line parser'''
+        """get a command-line parser"""
         parser = argparse.ArgumentParser(
             prog='yardstick-plot',
             description="A tool for visualizing results from yardstick. "
                         "Currently supports plotting graphs for output files "
-                        "from tests: " + str(self.data.keys())
+                        "from tests: " + str(list(self.data.keys()))
         )
         parser.add_argument(
             '-i', '--input',
@@ -58,39 +65,43 @@ class Parser(object):
         return parser
 
     def _add_record(self, record):
-        '''add record to the relevant scenario'''
-        runner_object = record['sargs']['runner']['object']
-        for test_type in self.data.keys():
+        """add record to the relevant scenario"""
+        if "runner_id" in record and "benchmark" not in record:
+            obj_name = record["scenario_cfg"]["runner"]["object"]
+            self.scenarios[record["runner_id"]] = obj_name
+            return
+        runner_object = self.scenarios[record["runner_id"]]
+        for test_type in self.data:
             if test_type in runner_object:
                 self.data[test_type].append(record)
 
     def parse_args(self):
-        '''parse command-line arguments'''
+        """parse command-line arguments"""
         parser = self._get_parser()
         self.args = parser.parse_args()
         return self.args
 
     def parse_input_file(self):
-        '''parse the input test results file'''
+        """parse the input test results file"""
         if self.args.input:
             input_file = self.args.input
         else:
-            print("No input file specified, reading from %s"
-                  % self.default_input_loc)
+            print(("No input file specified, reading from %s"
+                   % self.default_input_loc))
             input_file = self.default_input_loc
 
         try:
             with open(input_file) as f:
                 for line in f:
-                    record = json.loads(line)
+                    record = jsonutils.loads(line)
                     self._add_record(record)
         except IOError as e:
-            print(os.strerror(e.errno))
+            print((os.strerror(e.errno)))
             sys.exit(1)
 
 
 class Plotter(object):
-    '''Graph plotter for scenario-specific results from yardstick framework'''
+    """Graph plotter for scenario-specific results from yardstick framework"""
 
     def __init__(self, data, output_folder):
         self.data = data
@@ -99,7 +110,7 @@ class Plotter(object):
         self.colors = ['g', 'b', 'c', 'm', 'y']
 
     def plot(self):
-        '''plot the graph(s)'''
+        """plot the graph(s)"""
         for test_type in self.data.keys():
             if self.data[test_type]:
                 plt.figure(self.fig_counter)
@@ -111,7 +122,7 @@ class Plotter(object):
                 self._save_plot(test_type)
 
     def _save_plot(self, test_type):
-        '''save the graph to output folder'''
+        """save the graph to output folder"""
         timestr = time.strftime("%Y%m%d-%H%M%S")
         file_name = test_type + "_" + timestr + ".png"
         if not self.output_folder:
@@ -121,11 +132,11 @@ class Plotter(object):
             os.makedirs(self.output_folder)
         new_file = os.path.join(self.output_folder, file_name)
         plt.savefig(new_file)
-        print("Saved graph to " + new_file)
+        print(("Saved graph to " + new_file))
 
     def _plot_ping(self, records):
-        '''ping test result interpretation and visualization on the graph'''
-        rtts = [r['benchmark']['data'] for r in records]
+        """ping test result interpretation and visualization on the graph"""
+        rtts = [r['benchmark']['data']['rtt'] for r in records]
         seqs = [r['benchmark']['sequence'] for r in records]
 
         for i in range(0, len(rtts)):
@@ -138,7 +149,7 @@ class Plotter(object):
         if len(rtts) == 1:
             plt.bar(1, rtts[0], 0.35, color=self.colors[0])
         else:
-            plt.plot(seqs, rtts, self.colors[0]+'-')
+            plt.plot(seqs, rtts, self.colors[0] + '-')
 
         self._construct_legend(['rtt'])
         plt.xlabel("sequence number")
@@ -146,7 +157,7 @@ class Plotter(object):
         plt.ylabel("round trip time in milliseconds (rtt)")
 
     def _plot_pktgen(self, records):
-        '''pktgen test result interpretation and visualization on the graph'''
+        """pktgen test result interpretation and visualization on the graph"""
         flows = [r['benchmark']['data']['flows'] for r in records]
         sent = [r['benchmark']['data']['packets_sent'] for r in records]
         received = [int(r['benchmark']['data']['packets_received'])
@@ -159,20 +170,20 @@ class Plotter(object):
                 received[i] = 0.0
                 plt.axvline(flows[i], color='r')
 
-        ppm = [1000000.0*(i - j)/i for i, j in zip(sent, received)]
+        ppm = [1000000.0 * (i - j) / i for i, j in zip(sent, received)]
 
         # If there is a single data-point then display a bar-chart
         if len(ppm) == 1:
             plt.bar(1, ppm[0], 0.35, color=self.colors[0])
         else:
-            plt.plot(flows, ppm, self.colors[0]+'-')
+            plt.plot(flows, ppm, self.colors[0] + '-')
 
         self._construct_legend(['ppm'])
         plt.xlabel("number of flows")
         plt.ylabel("lost packets per million packets (ppm)")
 
     def _plot_iperf3(self, records):
-        '''iperf3 test result interpretation and visualization on the graph'''
+        """iperf3 test result interpretation and visualization on the graph"""
         intervals = []
         for r in records:
             #  If did not fail the SLA
@@ -186,7 +197,7 @@ class Plotter(object):
         for i, val in enumerate(intervals):
             if val:
                 for j, _ in enumerate(intervals):
-                    kbps.append(val[j]['sum']['bits_per_second']/1000)
+                    kbps.append(val[j]['sum']['bits_per_second'] / 1000)
                     seconds.append(seconds[-1] + val[j]['sum']['seconds'])
             else:
                 kbps.append(0.0)
@@ -197,12 +208,12 @@ class Plotter(object):
                 plt.axvline(seconds[-1], color='r')
 
         self._construct_legend(['bandwidth'])
-        plt.plot(seconds[1:], kbps[1:], self.colors[0]+'-')
+        plt.plot(seconds[1:], kbps[1:], self.colors[0] + '-')
         plt.xlabel("time in seconds")
         plt.ylabel("bandwidth in Kb/s")
 
     def _plot_fio(self, records):
-        '''fio test result interpretation and visualization on the graph'''
+        """fio test result interpretation and visualization on the graph"""
         rw_types = [r['sargs']['options']['rw'] for r in records]
         seqs = [x for x in range(1, len(records) + 1)]
         data = {}
@@ -213,16 +224,16 @@ class Plotter(object):
             is_rw_type = rw_types[i] == "rw" or rw_types[i] == "randrw"
 
             if is_r_type or is_rw_type:
-                # Remove trailing 'usec' and convert to float
+                # Convert to float
                 data['read_lat'] = \
-                    [r['benchmark']['data']['read_lat'][:-4] for r in records]
+                    [r['benchmark']['data']['read_lat'] for r in records]
                 data['read_lat'] = \
                     [float(i) for i in data['read_lat']]
-                # Remove trailing 'KB/s' and convert to float
+                # Convert to int
                 data['read_bw'] = \
-                    [r['benchmark']['data']['read_bw'][:-4] for r in records]
+                    [r['benchmark']['data']['read_bw'] for r in records]
                 data['read_bw'] =  \
-                    [float(i) for i in data['read_bw']]
+                    [int(i) for i in data['read_bw']]
                 # Convert to int
                 data['read_iops'] = \
                     [r['benchmark']['data']['read_iops'] for r in records]
@@ -231,14 +242,14 @@ class Plotter(object):
 
             if is_w_type or is_rw_type:
                 data['write_lat'] = \
-                    [r['benchmark']['data']['write_lat'][:-4] for r in records]
+                    [r['benchmark']['data']['write_lat'] for r in records]
                 data['write_lat'] = \
                     [float(i) for i in data['write_lat']]
 
                 data['write_bw'] = \
-                    [r['benchmark']['data']['write_bw'][:-4] for r in records]
+                    [r['benchmark']['data']['write_bw'] for r in records]
                 data['write_bw'] = \
-                    [float(i) for i in data['write_bw']]
+                    [int(i) for i in data['write_bw']]
 
                 data['write_iops'] = \
                     [r['benchmark']['data']['write_iops'] for r in records]
@@ -266,8 +277,8 @@ class Plotter(object):
         plt.xticks(seqs, seqs)
 
     def _plot_fio_helper(self, data, seqs, key, bar_color, axl):
-        '''check if measurements exist for a key and then plot the
-           data to a given subplot'''
+        """check if measurements exist for a key and then plot the
+           data to a given subplot"""
         if key in data:
             if len(data[key]) == 1:
                 axl.bar(0.1, data[key], 0.35, color=bar_color)
@@ -276,7 +287,7 @@ class Plotter(object):
                 axl.plot(seqs, data[key], line_style)
 
     def _construct_legend(self, legend_texts, obj=plt):
-        '''construct legend for the plot or subplot'''
+        """construct legend for the plot or subplot"""
         ci = 0
         lines = []
 
@@ -307,5 +318,6 @@ def main():
     print("Plotting graph(s)")
     plotter.plot()
 
+
 if __name__ == '__main__':
     main()