Bar graph for Soak tests results
[csit.git] / resources / tools / presentation / generator_plots.py
index 0f66099..21dd1a0 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (c) 2018 Cisco and/or its affiliates.
+# Copyright (c) 2019 Cisco and/or its affiliates.
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
 # You may obtain a copy of the License at:
@@ -144,11 +144,22 @@ def plot_performance_box(plot, input_data):
     df.head()
     y_max = list()
     for i, col in enumerate(df.columns):
-        name = "{0}. {1} ({2} run{3})".\
-            format(i + 1,
-                   col.lower().replace('-ndrpdr', ''),
-                   nr_of_samples[i],
-                   's' if nr_of_samples[i] > 1 else '')
+        name = "{nr}. ({samples:02d} run{plural}) {name}".\
+            format(nr=(i + 1),
+                   samples=nr_of_samples[i],
+                   plural='s' if nr_of_samples[i] > 1 else '',
+                   name=col.lower().replace('-ndrpdr', ''))
+        if len(name) > 50:
+            name_lst = name.split('-')
+            name = ""
+            split_name = True
+            for segment in name_lst:
+                if (len(name) + len(segment) + 1) > 50 and split_name:
+                    name += "<br>    "
+                    split_name = False
+                name += segment + '-'
+            name = name[:-1]
+
         logging.debug(name)
         traces.append(plgo.Box(x=[str(i + 1) + '.'] * len(df[col]),
                                y=[y / 1000000 if y else None for y in df[col]],
@@ -184,6 +195,248 @@ def plot_performance_box(plot, input_data):
         return
 
 
+def plot_soak_bars(plot, input_data):
+    """Generate the plot(s) with algorithm: plot_soak_bars
+    specified in the specification file.
+
+    :param plot: Plot to generate.
+    :param input_data: Data to process.
+    :type plot: pandas.Series
+    :type input_data: InputData
+    """
+
+    # Transform the data
+    plot_title = plot.get("title", "")
+    logging.info("    Creating the data set for the {0} '{1}'.".
+                 format(plot.get("type", ""), plot_title))
+    data = input_data.filter_data(plot)
+    if data is None:
+        logging.error("No data.")
+        return
+
+    # Prepare the data for the plot
+    y_vals = dict()
+    y_tags = dict()
+    for job in data:
+        for build in job:
+            for test in build:
+                if y_vals.get(test["parent"], None) is None:
+                    y_tags[test["parent"]] = test.get("tags", None)
+                try:
+                    if test["type"] in ("SOAK", ):
+                        y_vals[test["parent"]] = test["throughput"]
+                    else:
+                        continue
+                except (KeyError, TypeError):
+                    y_vals[test["parent"]] = dict()
+
+    # Sort the tests
+    order = plot.get("sort", None)
+    if order and y_tags:
+        y_sorted = OrderedDict()
+        y_tags_l = {s: [t.lower() for t in ts] for s, ts in y_tags.items()}
+        for tag in order:
+            logging.debug(tag)
+            for suite, tags in y_tags_l.items():
+                if "not " in tag:
+                    tag = tag.split(" ")[-1]
+                    if tag.lower() in tags:
+                        continue
+                else:
+                    if tag.lower() not in tags:
+                        continue
+                try:
+                    y_sorted[suite] = y_vals.pop(suite)
+                    y_tags_l.pop(suite)
+                    logging.debug(suite)
+                except KeyError as err:
+                    logging.error("Not found: {0}".format(repr(err)))
+                finally:
+                    break
+    else:
+        y_sorted = y_vals
+
+    idx = 0
+    y_max = 0
+    traces = list()
+    for test_name, test_data in y_sorted.items():
+        idx += 1
+        name = "{nr}. {name}".\
+            format(nr=idx, name=test_name.lower().replace('-soak', ''))
+        if len(name) > 50:
+            name_lst = name.split('-')
+            name = ""
+            split_name = True
+            for segment in name_lst:
+                if (len(name) + len(segment) + 1) > 50 and split_name:
+                    name += "<br>    "
+                    split_name = False
+                name += segment + '-'
+            name = name[:-1]
+
+        y_val = test_data.get("LOWER", None)
+        if y_val:
+            y_val /= 1000000
+            if y_val > y_max:
+                y_max = y_val
+
+        time = "No Information"
+        result = "No Information"
+        hovertext = ("{name}<br>"
+                     "Packet Throughput: {val:.2f}Mpps<br>"
+                     "Final Duration: {time}<br>"
+                     "Result: {result}".format(name=name,
+                                               val=y_val,
+                                               time=time,
+                                               result=result))
+        traces.append(plgo.Bar(x=[str(idx) + '.', ],
+                               y=[y_val, ],
+                               name=name,
+                               text=hovertext,
+                               hoverinfo="text"))
+    try:
+        # Create plot
+        layout = deepcopy(plot["layout"])
+        if layout.get("title", None):
+            layout["title"] = "<b>Packet Throughput:</b> {0}". \
+                format(layout["title"])
+        if y_max:
+            layout["yaxis"]["range"] = [0, y_max + 1]
+        plpl = plgo.Figure(data=traces, layout=layout)
+        # Export Plot
+        logging.info("    Writing file '{0}{1}'.".
+                     format(plot["output-file"], plot["output-file-type"]))
+        ploff.plot(plpl, show_link=False, auto_open=False,
+                   filename='{0}{1}'.format(plot["output-file"],
+                                            plot["output-file-type"]))
+    except PlotlyError as err:
+        logging.error("   Finished with error: {}".
+                      format(repr(err).replace("\n", " ")))
+        return
+
+
+def plot_soak_boxes(plot, input_data):
+    """Generate the plot(s) with algorithm: plot_soak_boxes
+    specified in the specification file.
+
+    :param plot: Plot to generate.
+    :param input_data: Data to process.
+    :type plot: pandas.Series
+    :type input_data: InputData
+    """
+
+    # Transform the data
+    plot_title = plot.get("title", "")
+    logging.info("    Creating the data set for the {0} '{1}'.".
+                 format(plot.get("type", ""), plot_title))
+    data = input_data.filter_data(plot)
+    if data is None:
+        logging.error("No data.")
+        return
+
+    # Prepare the data for the plot
+    y_vals = dict()
+    y_tags = dict()
+    for job in data:
+        for build in job:
+            for test in build:
+                if y_vals.get(test["parent"], None) is None:
+                    y_tags[test["parent"]] = test.get("tags", None)
+                try:
+                    if test["type"] in ("SOAK", ):
+                        y_vals[test["parent"]] = test["throughput"]
+                    else:
+                        continue
+                except (KeyError, TypeError):
+                    y_vals[test["parent"]] = dict()
+
+    # Sort the tests
+    order = plot.get("sort", None)
+    if order and y_tags:
+        y_sorted = OrderedDict()
+        y_tags_l = {s: [t.lower() for t in ts] for s, ts in y_tags.items()}
+        for tag in order:
+            logging.debug(tag)
+            for suite, tags in y_tags_l.items():
+                if "not " in tag:
+                    tag = tag.split(" ")[-1]
+                    if tag.lower() in tags:
+                        continue
+                else:
+                    if tag.lower() not in tags:
+                        continue
+                try:
+                    y_sorted[suite] = y_vals.pop(suite)
+                    y_tags_l.pop(suite)
+                    logging.debug(suite)
+                except KeyError as err:
+                    logging.error("Not found: {0}".format(repr(err)))
+                finally:
+                    break
+    else:
+        y_sorted = y_vals
+
+    idx = 0
+    y_max = 0
+    traces = list()
+    for test_name, test_data in y_sorted.items():
+        idx += 1
+        name = "{nr}. {name}".\
+            format(nr=idx, name=test_name.lower().replace('-soak', ''))
+        if len(name) > 50:
+            name_lst = name.split('-')
+            name = ""
+            split_name = True
+            for segment in name_lst:
+                if (len(name) + len(segment) + 1) > 50 and split_name:
+                    name += "<br>    "
+                    split_name = False
+                name += segment + '-'
+            name = name[:-1]
+
+        y_val = test_data.get("UPPER", None)
+        if y_val:
+            y_val /= 1000000
+            if y_val > y_max:
+                y_max = y_val
+
+        y_base = test_data.get("LOWER", None)
+        if y_base:
+            y_base /= 1000000
+
+        hovertext = ("{name}<br>"
+                     "Upper bound: {upper:.2f}Mpps<br>"
+                     "Lower bound: {lower:.2f}Mpps".format(name=name,
+                                                           upper=y_val,
+                                                           lower=y_base))
+        traces.append(plgo.Bar(x=[str(idx) + '.', ],
+                               # +0.05 to see the value in case lower == upper
+                               y=[y_val - y_base + 0.05, ],
+                               base=y_base,
+                               name=name,
+                               text=hovertext,
+                               hoverinfo="text"))
+    try:
+        # Create plot
+        layout = deepcopy(plot["layout"])
+        if layout.get("title", None):
+            layout["title"] = "<b>Soak Tests:</b> {0}". \
+                format(layout["title"])
+        if y_max:
+            layout["yaxis"]["range"] = [0, y_max + 1]
+        plpl = plgo.Figure(data=traces, layout=layout)
+        # Export Plot
+        logging.info("    Writing file '{0}{1}'.".
+                     format(plot["output-file"], plot["output-file-type"]))
+        ploff.plot(plpl, show_link=False, auto_open=False,
+                   filename='{0}{1}'.format(plot["output-file"],
+                                            plot["output-file-type"]))
+    except PlotlyError as err:
+        logging.error("   Finished with error: {}".
+                      format(repr(err).replace("\n", " ")))
+        return
+
+
 def plot_latency_error_bars(plot, input_data):
     """Generate the plot(s) with algorithm: plot_latency_error_bars
     specified in the specification file.
@@ -287,13 +540,23 @@ def plot_latency_error_bars(plot, input_data):
     y_maxs = list()
     nr_of_samples = list()
     for key, val in y_sorted.items():
-        key = "-".join(key.split("-")[1:-1])
-        x_vals.append(key)  # dir 1
+        name = "-".join(key.split("-")[1:-1])
+        if len(name) > 50:
+            name_lst = name.split('-')
+            name = ""
+            split_name = True
+            for segment in name_lst:
+                if (len(name) + len(segment) + 1) > 50 and split_name:
+                    name += "<br>"
+                    split_name = False
+                name += segment + '-'
+            name = name[:-1]
+        x_vals.append(name)  # dir 1
         y_vals.append(mean(val[1]) if val[1] else None)
         y_mins.append(mean(val[0]) if val[0] else None)
         y_maxs.append(mean(val[2]) if val[2] else None)
         nr_of_samples.append(len(val[1]) if val[1] else 0)
-        x_vals.append(key)  # dir 2
+        x_vals.append(name)  # dir 2
         y_vals.append(mean(val[4]) if val[4] else None)
         y_mins.append(mean(val[3]) if val[3] else None)
         y_maxs.append(mean(val[5]) if val[5] else None)
@@ -309,18 +572,18 @@ def plot_latency_error_bars(plot, input_data):
 
     for idx in range(len(x_vals)):
         if not bool(int(idx % 2)):
-            direction = "West - East"
+            direction = "West-East"
         else:
-            direction = "East - West"
-        hovertext = ("Test: {test}<br>"
-                     "Direction: {dir}<br>"
-                     "No. of Runs: {nr}<br>".format(test=x_vals[idx],
-                                                    dir=direction,
-                                                    nr=nr_of_samples[idx]))
+            direction = "East-West"
+        hovertext = ("No. of Runs: {nr}<br>"
+                     "Test: {test}<br>"
+                     "Direction: {dir}<br>".format(test=x_vals[idx],
+                                                   dir=direction,
+                                                   nr=nr_of_samples[idx]))
         if isinstance(y_maxs[idx], float):
             hovertext += "Max: {max:.2f}uSec<br>".format(max=y_maxs[idx])
         if isinstance(y_vals[idx], float):
-            hovertext += "Avg: {avg:.2f}uSec<br>".format(avg=y_vals[idx])
+            hovertext += "Mean: {avg:.2f}uSec<br>".format(avg=y_vals[idx])
         if isinstance(y_mins[idx], float):
             hovertext += "Min: {min:.2f}uSec".format(min=y_mins[idx])
 
@@ -467,6 +730,16 @@ def plot_throughput_speedup_analysis(plot, input_data):
         try:
             if test_vals["1"][1]:
                 name = "-".join(test_name.split('-')[1:-1])
+                if len(name) > 50:
+                    name_lst = name.split('-')
+                    name = ""
+                    split_name = True
+                    for segment in name_lst:
+                        if (len(name) + len(segment) + 1) > 50 and split_name:
+                            name += "<br>"
+                            split_name = False
+                        name += segment + '-'
+                    name = name[:-1]
 
                 vals[name] = dict()
                 y_val_1 = test_vals["1"][0] / 1000000.0
@@ -515,6 +788,8 @@ def plot_throughput_speedup_analysis(plot, input_data):
             limit = plot["limits"]["nic"]["xxv710"]
         elif "xl710" in test_name:
             limit = plot["limits"]["nic"]["xl710"]
+        elif "x553" in test_name:
+            limit = plot["limits"]["nic"]["x553"]
         else:
             limit = 0
         if limit > nic_limit:
@@ -664,9 +939,9 @@ def plot_throughput_speedup_analysis(plot, input_data):
             for idx in range(len(val["val"])):
                 htext = ""
                 if isinstance(val["val"][idx], float):
-                    htext += "Value: {0:.2f}Mpps<br>" \
-                             "No. of Runs: {1}<br>".format(val["val"][idx],
-                                                        val["count"][idx])
+                    htext += "No. of Runs: {1}<br>" \
+                             "Mean: {0:.2f}Mpps<br>".format(val["val"][idx],
+                                                            val["count"][idx])
                 if isinstance(val["diff"][idx], float):
                     htext += "Diff: {0:.0f}%<br>".format(round(val["diff"][idx]))
                 if isinstance(val["rel"][idx], float):
@@ -697,7 +972,7 @@ def plot_throughput_speedup_analysis(plot, input_data):
                                            color=COLORS[cidx],
                                            width=2,
                                            dash="dash"),
-                                       text=["perfect: {0:.2f}Mpps".format(y)
+                                       text=["Perfect: {0:.2f}Mpps".format(y)
                                              for y in val["ideal"]],
                                        hoverinfo="text"
                                        ))
@@ -774,11 +1049,22 @@ def plot_http_server_performance_box(plot, input_data):
     df = pd.DataFrame(y_vals)
     df.head()
     for i, col in enumerate(df.columns):
-        name = "{0}. {1} ({2} run{3})".\
-            format(i + 1,
-                   col.lower().replace('-cps', '').replace('-rps', ''),
-                   nr_of_samples[i],
-                   's' if nr_of_samples[i] > 1 else '')
+        name = "{nr}. ({samples:02d} run{plural}) {name}".\
+            format(nr=(i + 1),
+                   samples=nr_of_samples[i],
+                   plural='s' if nr_of_samples[i] > 1 else '',
+                   name=col.lower().replace('-ndrpdr', ''))
+        if len(name) > 50:
+            name_lst = name.split('-')
+            name = ""
+            split_name = True
+            for segment in name_lst:
+                if (len(name) + len(segment) + 1) > 50 and split_name:
+                    name += "<br>    "
+                    split_name = False
+                name += segment + '-'
+            name = name[:-1]
+
         traces.append(plgo.Box(x=[str(i + 1) + '.'] * len(df[col]),
                                y=df[col],
                                name=name,