From 9821b058c2f4901a9b4d66667018da214513ab28 Mon Sep 17 00:00:00 2001 From: Tibor Frank Date: Mon, 16 Apr 2018 09:44:50 +0200 Subject: [PATCH] CSIT-1041: Trending dashboard Change-Id: Ic706612218e0ac6b991a15abc4d67e16905e8087 Signed-off-by: Tibor Frank --- docs/cpta/index.rst | 19 +++++ resources/tools/presentation/generator_CPTA.py | 32 ++++----- resources/tools/presentation/generator_tables.py | 76 ++++++++++++++++++-- resources/tools/presentation/pal.py | 82 +++++++++++----------- .../tools/presentation/specification_CPTA.yaml | 23 +++++- .../tools/presentation/specification_parser.py | 7 ++ resources/tools/presentation/utils.py | 4 +- 7 files changed, 176 insertions(+), 67 deletions(-) diff --git a/docs/cpta/index.rst b/docs/cpta/index.rst index 0f5dab6b0a..6ae8a521dc 100644 --- a/docs/cpta/index.rst +++ b/docs/cpta/index.rst @@ -1,6 +1,25 @@ Continuous Performance Trending and Analysis ============================================ +VPP Performance Trending Dashboard +---------------------------------- + +1t1c +```` + +.. include:: ../../_build/_static/vpp/performance-trending-dashboard-1t1c.rst + +2t2c +```` + +.. include:: ../../_build/_static/vpp/performance-trending-dashboard-2t2c.rst + +4t4c +```` + +.. include:: ../../_build/_static/vpp/performance-trending-dashboard-4t4c.rst + + .. toctree:: :maxdepth: 6 :numbered: diff --git a/resources/tools/presentation/generator_CPTA.py b/resources/tools/presentation/generator_CPTA.py index 54679a26f6..3a8ea93e0a 100644 --- a/resources/tools/presentation/generator_CPTA.py +++ b/resources/tools/presentation/generator_CPTA.py @@ -232,14 +232,14 @@ def _generate_trending_traces(in_data, build_info, period, moving_win_size=10, in_data = _select_data(in_data, period, fill_missing=fill_missing, use_first=use_first) - try: - data_x = ["{0}/{1}".format(key, build_info[str(key)][1].split("~")[-1]) - for key in in_data.keys()] - except KeyError: - data_x = [key for key in in_data.keys()] - # hover_text = ["vpp-build: {0}".format(x[1].split("~")[-1]) - # for x in build_info.values()] - # data_x = [key for key in in_data.keys()] + # try: + # data_x = ["{0}/{1}".format(key, build_info[str(key)][1].split("~")[-1]) + # for key in in_data.keys()] + # except KeyError: + # data_x = [key for key in in_data.keys()] + hover_text = ["vpp-build: {0}".format(x[1].split("~")[-1]) + for x in build_info.values()] + data_x = [key for key in in_data.keys()] data_y = [val for val in in_data.values()] data_pd = pd.Series(data_y, index=data_x) @@ -251,12 +251,12 @@ def _generate_trending_traces(in_data, build_info, period, moving_win_size=10, anomalies = pd.Series() anomalies_res = list() for idx, item in enumerate(in_data.items()): - item_pd = pd.Series([item[1], ], - index=["{0}/{1}". - format(item[0], - build_info[str(item[0])][1].split("~")[-1]), - ]) - #item_pd = pd.Series([item[1], ], index=[item[0], ]) + # item_pd = pd.Series([item[1], ], + # index=["{0}/{1}". + # format(item[0], + # build_info[str(item[0])][1].split("~")[-1]), + # ]) + item_pd = pd.Series([item[1], ], index=[item[0], ]) if item[0] in outliers.keys(): anomalies = anomalies.append(item_pd) anomalies_res.append(0.0) @@ -288,8 +288,8 @@ def _generate_trending_traces(in_data, build_info, period, moving_win_size=10, "color": color, "symbol": "circle", }, - # text=hover_text, - # hoverinfo="x+y+text+name" + text=hover_text, + hoverinfo="x+y+text+name" ) traces = [trace_samples, ] diff --git a/resources/tools/presentation/generator_tables.py b/resources/tools/presentation/generator_tables.py index a5a8824dc9..13c8efffdb 100644 --- a/resources/tools/presentation/generator_tables.py +++ b/resources/tools/presentation/generator_tables.py @@ -22,6 +22,7 @@ import pandas as pd from string import replace from math import isnan +from xml.etree import ElementTree as ET from errors import PresentationError from utils import mean, stdev, relative_change, remove_outliers, find_outliers @@ -597,20 +598,15 @@ def table_performance_trending_dashboard(table, input_data): classification = "normal" if not isnan(last) and not isnan(trend) and trend != 0: - # Change: - change = round(float(last - trend) / 1000000, 2) # Relative change: rel_change = int(relative_change(float(trend), float(last))) tbl_lst.append([name, round(float(trend) / 1000000, 2), - last, + round(float(last) / 1000000, 2), rel_change, classification]) - # Sort the table according to the relative change - # tbl_lst.sort(key=lambda rel: rel[-2], reverse=True) - # Sort the table according to the classification tbl_sorted = list() for classification in ("regression", "outlier", "progression", "normal"): @@ -618,7 +614,7 @@ def table_performance_trending_dashboard(table, input_data): tbl_tmp.sort(key=lambda rel: rel[0]) tbl_sorted.extend(tbl_tmp) - file_name = "{0}.{1}".format(table["output-file"], table["output-file-ext"]) + file_name = "{0}{1}".format(table["output-file"], table["output-file-ext"]) logging.info(" Writing file: '{0}'".format(file_name)) with open(file_name, "w") as file_handler: @@ -639,3 +635,69 @@ def table_performance_trending_dashboard(table, input_data): txt_table.align["Test case"] = "l" with open(txt_file_name, "w") as txt_file: txt_file.write(str(txt_table)) + + +def table_performance_trending_dashboard_html(table, input_data): + """Generate the table(s) with algorithm: + table_performance_trending_dashboard_html specified in the specification + file. + + :param table: Table to generate. + :param input_data: Data to process. + :type table: pandas.Series + :type input_data: InputData + """ + + logging.info(" Generating the table {0} ...". + format(table.get("title", ""))) + + try: + with open(table["input-file"], 'rb') as csv_file: + csv_content = csv.reader(csv_file, delimiter=',', quotechar='"') + csv_lst = [item for item in csv_content] + except KeyError: + logging.warning("The input file is not defined.") + return + except csv.Error as err: + logging.warning("Not possible to process the file '{0}'.\n{1}". + format(table["input-file"], err)) + return + + # Table: + dashboard = ET.Element("table", attrib=dict(width="100%", border='0')) + + # Table header: + tr = ET.SubElement(dashboard, "tr", attrib=dict(bgcolor="#6699ff")) + for idx, item in enumerate(csv_lst[0]): + alignment = "left" if idx == 0 else "right" + th = ET.SubElement(tr, "th", attrib=dict(align=alignment)) + th.text = item + + # Rows: + for r_idx, row in enumerate(csv_lst[1:]): + background = "#D4E4F7" if r_idx % 2 else "white" + tr = ET.SubElement(dashboard, "tr", attrib=dict(bgcolor=background)) + + # Columns: + for c_idx, item in enumerate(row): + alignment = "left" if c_idx == 0 else "center" + td = ET.SubElement(tr, "td", attrib=dict(align=alignment)) + if c_idx == 4: + if item == "regression": + td.set("bgcolor", "#FF0000") + elif item == "outlier": + td.set("bgcolor", "#818181") + elif item == "progression": + td.set("bgcolor", "#008000") + td.text = item + + try: + with open(table["output-file"], 'w') as html_file: + logging.info(" Writing file: '{0}'". + format(table["output-file"])) + html_file.write(".. raw:: html\n\n\t") + html_file.write(ET.tostring(dashboard)) + html_file.write("\n\t



\n") + except KeyError: + logging.warning("The output file is not defined.") + return diff --git a/resources/tools/presentation/pal.py b/resources/tools/presentation/pal.py index aaeacaac15..98642c898c 100644 --- a/resources/tools/presentation/pal.py +++ b/resources/tools/presentation/pal.py @@ -87,48 +87,48 @@ def main(): return 1 ret_code = 0 - # try: - env = Environment(spec.environment, args.force) - env.set_environment() - - if spec.is_debug: - if spec.debug["input-format"] == "zip": - unzip_files(spec) - else: - download_data_files(spec) - - prepare_static_content(spec) - - data = InputData(spec) - data.read_data() - - generate_tables(spec, data) - generate_plots(spec, data) - generate_files(spec, data) - - if spec.output["output"] == "report": - generate_report(args.release, spec) - logging.info("Successfully finished.") - elif spec.output["output"] == "CPTA": - sys.stdout.write(generate_cpta(spec, data)) - logging.info("Successfully finished.") - else: - logging.critical("The output '{0}' is not supported.". - format(spec.output["output"])) + try: + env = Environment(spec.environment, args.force) + env.set_environment() + + if spec.is_debug: + if spec.debug["input-format"] == "zip": + unzip_files(spec) + else: + download_data_files(spec) + + prepare_static_content(spec) + + data = InputData(spec) + data.read_data() + + generate_tables(spec, data) + generate_plots(spec, data) + generate_files(spec, data) + + if spec.output["output"] == "report": + generate_report(args.release, spec) + logging.info("Successfully finished.") + elif spec.output["output"] == "CPTA": + sys.stdout.write(generate_cpta(spec, data)) + logging.info("Successfully finished.") + else: + logging.critical("The output '{0}' is not supported.". + format(spec.output["output"])) + ret_code = 1 + + except (KeyError, ValueError, PresentationError) as err: + logging.info("Finished with an error.") + logging.critical(str(err)) ret_code = 1 - - # except (KeyError, ValueError, PresentationError) as err: - # logging.info("Finished with an error.") - # logging.critical(str(err)) - # ret_code = 1 - # except Exception as err: - # logging.info("Finished with an unexpected error.") - # logging.critical(str(err)) - # ret_code = 1 - # finally: - # if spec is not None and not spec.is_debug: - # clean_environment(spec.environment) - # return ret_code + except Exception as err: + logging.info("Finished with an unexpected error.") + logging.critical(str(err)) + ret_code = 1 + finally: + if spec is not None and not spec.is_debug: + clean_environment(spec.environment) + return ret_code if __name__ == '__main__': diff --git a/resources/tools/presentation/specification_CPTA.yaml b/resources/tools/presentation/specification_CPTA.yaml index 7aa047c4e1..0544acd040 100644 --- a/resources/tools/presentation/specification_CPTA.yaml +++ b/resources/tools/presentation/specification_CPTA.yaml @@ -117,7 +117,7 @@ autotick: True margin: r: 20 - b: 150 + b: 50 t: 5 l: 70 legend: @@ -264,6 +264,27 @@ outlier-const: 1.5 window: 10 +- + type: "table" + title: "HTML performance trending dashboard 1t1c" + algorithm: "table_performance_trending_dashboard_html" + input-file: "{DIR[STATIC,VPP]}/performance-trending-dashboard-1t1c.csv" + output-file: "{DIR[STATIC,VPP]}/performance-trending-dashboard-1t1c.rst" + +- + type: "table" + title: "HTML performance trending dashboard 2t2c" + algorithm: "table_performance_trending_dashboard_html" + input-file: "{DIR[STATIC,VPP]}/performance-trending-dashboard-2t2c.csv" + output-file: "{DIR[STATIC,VPP]}/performance-trending-dashboard-2t2c.rst" + +- + type: "table" + title: "HTML performance trending dashboard 4t4c" + algorithm: "table_performance_trending_dashboard_html" + input-file: "{DIR[STATIC,VPP]}/performance-trending-dashboard-4t4c.csv" + output-file: "{DIR[STATIC,VPP]}/performance-trending-dashboard-4t4c.rst" + ################################################################################ ### C P T A ### diff --git a/resources/tools/presentation/specification_parser.py b/resources/tools/presentation/specification_parser.py index 207507e3b6..af4d707613 100644 --- a/resources/tools/presentation/specification_parser.py +++ b/resources/tools/presentation/specification_parser.py @@ -561,6 +561,13 @@ class Specification(object): except KeyError: pass + try: + element["input-file"] = self._replace_tags( + element["input-file"], + self._specification["environment"]["paths"]) + except KeyError: + pass + # add data sets to the elements: if isinstance(element.get("data", None), str): data_set = element["data"] diff --git a/resources/tools/presentation/utils.py b/resources/tools/presentation/utils.py index 0bf78f09bf..8365bfad5c 100644 --- a/resources/tools/presentation/utils.py +++ b/resources/tools/presentation/utils.py @@ -187,8 +187,8 @@ def execute_command(cmd): stdout, stderr = proc.communicate() - logging.debug(stdout) - logging.debug(stderr) + logging.info(stdout) + logging.info(stderr) if proc.returncode != 0: logging.error(" Command execution failed.") -- 2.16.6