diff options
Diffstat (limited to 'resources/tools/report_gen/run_plot.py')
-rw-r--r-- | resources/tools/report_gen/run_plot.py | 261 |
1 files changed, 261 insertions, 0 deletions
diff --git a/resources/tools/report_gen/run_plot.py b/resources/tools/report_gen/run_plot.py new file mode 100644 index 0000000000..4218ecb93a --- /dev/null +++ b/resources/tools/report_gen/run_plot.py @@ -0,0 +1,261 @@ +#!/usr/bin/python + +# Copyright (c) 2016 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: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Plot the performance data""" + +import argparse +import operator +import os +import sys +import math + +import plotly.offline as ploff +import plotly.graph_objs as plgo +from lxml import etree + + +def select_files_in_subfolders(directory, ext='xml'): + """Get all files in folder and its subfolders. + + :param dir: Input folder. + :param ext: File extension. + :type dir: str + :type ext: str + :return: List of filex matching the parameters. + :rtype list + """ + for _, _, files in os.walk(directory): + for file in files: + if file.endswith('.%s' % ext): + yield os.path.join(directory, file) + + +def select_files_in_folder(directory, ext='xml'): + """Get all files in folder. + + :param dir: Input folder. + :param ext: File extension. + :type dir: str + :type ext: str + :return: List of filex matching the parameters. + :rtype list + """ + for file in os.listdir(directory): + if file.endswith('.%s' % ext): + yield os.path.join(directory, file) + + +def combine_dicts(first, second, oper=operator.add): + """Combine two dictionaries. + + :param first: First dict. + :param second: Second dict. + :param oper: Operator. + :type first: dict + :type second: dict + :type oper: operator + :return: Combined dictionary. + :rtype dict + """ + + return dict(first.items() + second.items() +\ + [(k, oper(first[k], second[k])) for k in set(second) & set(first)]) + + +def parse_data_pps(args): + """Get PPS data out of XML file into array. + + :param args: Command line parameters. + :type suite: ArgumentParser + :return: X-data and Y-data dictionaries. + :rtype tuple of dict + """ + xdata = [] + ydata_pps = {} + + for i, file in enumerate(sorted(select_files_in_folder(args.input))): + xml_tree = etree.parse(file) + sel = xml_tree.xpath(args.xpath) + if sel: + ydata_pps = combine_dicts(ydata_pps, dict((elem.attrib['name'],\ + (i, float(elem.text))) for elem in sel)) + xdata.append(xml_tree.getroot().attrib['vdevice']) + return xdata, ydata_pps + + +def parse_data_lat(args): + """Get latency data out of XML file into array. + + :param args: Command line parameters. + :type suite: ArgumentParser + :return: X-data and Y-data dictionaries. + :rtype tuple of dict + """ + xdata = [] + ydata_lat = {} + + for i, file in enumerate(sorted(select_files_in_folder(args.input))): + xml_tree = etree.parse(file) + sel = xml_tree.xpath(args.xpath) + if sel: + try: + ydata_lat = combine_dicts(ydata_lat, dict((elem.attrib['name'],\ + (i, elem.attrib[args.latency])) for elem in sel)) + except KeyError: + raise RuntimeError('Retrieving latency data error (PDR?)') + xdata.append(xml_tree.getroot().attrib['vdevice']) + return xdata, ydata_lat + + +def parse_args(): + """Parse arguments from cmd line. + + :return: Parsed arguments. + :rtype ArgumentParser + """ + + parser = argparse.ArgumentParser() + parser.add_argument("-x", "--xpath", required=True, + help="Xpath filter") + parser.add_argument("-t", "--title", required=True, + help="Plot title") + parser.add_argument("-l", "--lower", + default=False, + help="Lower boudary of Y-axis") + parser.add_argument("-u", "--upper", + default=False, + help="Upper boudary of Y-axis") + parser.add_argument("-e", "--errorbar", + default=False, + help="Errorbar for Y-axis") + parser.add_argument("-d", "--latency", + choices=['lat_10', 'lat_50', 'lat_100'], + help="Latency to draw") + parser.add_argument("-i", "--input", + help="Input folder") + parser.add_argument("-o", "--output", required=True, + help="Output image file name") + return parser.parse_args() + + +def main(): + """Main function.""" + + args = parse_args() + if args.latency: + xdata, ydata = parse_data_lat(args) + else: + xdata, ydata = parse_data_pps(args) + + # Print data into console for debug + row_format = "{:>60}" * (len(xdata) + 1) + print row_format.format(args.title, *xdata) + for data in ydata: + try: + print row_format.format(data, *ydata[data][1::2]) + except IndexError: + print "{:>60}".format(data), ydata[data] + + if xdata and ydata: + traces = [] + # Add plot traces + for i, suite in enumerate(ydata): + if args.latency: + y_extract = [] + _ = [y_extract.extend([l, l]) for l in ydata[suite][1::2][0].split('/')] + traces.append(plgo.Box( + x=['TGint1-to-SUT1-to-SUT2-to-TGint2', + 'TGint1-to-SUT1-to-SUT2-to-TGint2', + 'TGint1-to-SUT1-to-SUT2-to-TGint2', + 'TGint1-to-SUT1-to-SUT2-to-TGint2', + 'TGint1-to-SUT1-to-SUT2-to-TGint2', + 'TGint1-to-SUT1-to-SUT2-to-TGint2', + 'TGint2-to-SUT2-to-SUT1-to-TGint1', + 'TGint2-to-SUT2-to-SUT1-to-TGint1', + 'TGint2-to-SUT2-to-SUT1-to-TGint1', + 'TGint2-to-SUT2-to-SUT1-to-TGint1', + 'TGint2-to-SUT2-to-SUT1-to-TGint1', + 'TGint2-to-SUT2-to-SUT1-to-TGint1'], + y=y_extract, + name=str(i+1)+'. '+suite.lower().replace('-ndrdisc',''), + boxmean=False, + )) + else: + traces.append(plgo.Scatter( + x=ydata[suite][0::2], + y=ydata[suite][1::2], + mode='lines+markers', + name=str(i+1)+'. '+suite.lower().replace('-ndrdisc',''), + )) + + # Add plot layout + layout = plgo.Layout( + title='{0}'.format(args.title), + xaxis=dict( + autorange=True, + autotick=False, + fixedrange=False, + gridcolor='rgb(238, 238, 238)', + linecolor='rgb(238, 238, 238)', + linewidth=1, + showgrid=True, + showline=True, + showticklabels=True, + tickcolor='rgb(238, 238, 238)', + tickmode='linear', + zeroline=False, + ), + yaxis=dict( + gridcolor='rgb(238, 238, 238)', + hoverformat='' if args.latency else '.4s', + linecolor='rgb(238, 238, 238)', + linewidth=1, + range=[args.lower, args.upper], + showgrid=True, + showline=True, + showticklabels=True, + tickcolor='rgb(238, 238, 238)', + title='Latency min/avg/max [uSec]' if args.latency\ + else 'Packets Per Second [pps]', + zeroline=False, + ), + boxmode='group', + boxgroupgap=0.5, + autosize=False, + margin=dict( + autoexpand=False, + b=200, + l=50, + r=50, + ), + showlegend=True, + legend=dict( + orientation='h', + ), + width=700, + height=700, + ) + # Create plot + plpl = plgo.Figure(data=traces, layout=layout) + # Export Plot + ploff.plot(plpl, + show_link=False, auto_open=False, + filename='{0}.html'.format(args.output)) + else: + sys.stderr.write('No data found!\n') + + +if __name__ == "__main__": + sys.exit(main()) |