vmtp/scale/kb_gen_chart.py
Yichen Wang af1e5ca210 Fix the quota caclulation bugs, add force_cleanup
Change-Id: I99cc22325d69d271d6cc98479bda9b155d6ee158
2015-07-08 14:43:49 -07:00

218 lines
7.6 KiB
Python

# Copyright 2014 Cisco Systems, Inc. All rights reserved.
#
# 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.
#
# A tool that can represent KloudBuster json results in
# a nicer form using HTML5, bootstrap.js and the Google Charts Javascript library
#
import argparse
import json
import os
import os.path
import sys
import webbrowser
from jinja2 import Environment
from jinja2 import FileSystemLoader
__version__ = '0.0.1'
kb_html_tpl = "./kb_tpl.jinja"
def get_formatted_num(value):
return '{:,}'.format(value)
# table column names
col_names = ['<i class="glyphicon glyphicon-file"></i> File',
'<i class="glyphicon glyphicon-random"></i> Connections',
'<i class="glyphicon glyphicon-book"></i> Server VMs',
'<i class="glyphicon glyphicon-transfer"></i> Requests',
'<i class="glyphicon glyphicon-fire"></i> Socket errors',
'<i class="glyphicon glyphicon-time"></i> RPS measured',
'<i class="glyphicon glyphicon-pencil"></i> RPS requested',
'<i class="glyphicon glyphicon-cloud-download"></i> RX throughput (Gbps)']
def get_new_latency_tuples():
'''Returns a list of lists initializedas follows
The latency tuples must be formatted like this:
['Percentile', 'fileA', 'fileB'],
[2.0, 1, 3],
[4.0, 27, 38],
etc, with the first column being calculated from the percentile
using the formula (1/(1-percentile))
50% -> 1/0.5 = 2
75% -> 4
etc...
This horizontal scaling is used to stretch the chart at the top end
(towards 100%)
'''
return [
['Percentile'], # add run file name
[2], # add run 50% latency
[4], # add run 75% latency
[10],
[100],
[1000],
[10000],
[100000] # add run 99.999% latency
]
class KbReport(object):
def __init__(self, data_list, line_rate):
self.data_list = data_list
self.latency_tuples = get_new_latency_tuples()
self.common_stats = []
self.table = None
template_loader = FileSystemLoader(searchpath=".")
template_env = Environment(loader=template_loader)
self.tpl = template_env.get_template(kb_html_tpl)
self.line_rate = line_rate
def add_latency_stats(self, run_results):
# init a column list
column = [run_results['filename']]
for latency_pair in run_results['latency_stats']:
# convert from usec to msec
latency_ms = latency_pair[1] / 1000
column.append(latency_ms)
# and append that column to the latency list
for pct_list, colval in zip(self.latency_tuples, column):
pct_list.append(colval)
def prepare_table(self):
table = {}
table['col_names'] = col_names
# add values for each row
rows = []
for run_res in self.data_list:
rps_max = run_res['http_rate_limit'] * run_res['total_client_vms']
rx_tp = float(run_res['http_throughput_kbytes'])
rx_tp = round(rx_tp * 8 / (1024 * 1024), 1)
cells = [run_res['filename'],
get_formatted_num(run_res['total_connections']),
get_formatted_num(run_res['total_server_vms']),
get_formatted_num(run_res['http_total_req']),
get_formatted_num(run_res['http_sock_err'] + run_res['http_sock_timeout']),
get_formatted_num(run_res['http_rps']),
get_formatted_num(rps_max)]
row = {'cells': cells,
'rx': {'value': rx_tp,
'max': self.line_rate,
'percent': (rx_tp * 100) / self.line_rate}}
rows.append(row)
table['rows'] = rows
self.table = table
def plot(self, dest_file):
for run_results in self.data_list:
self.add_latency_stats(run_results)
self.prepare_table()
kbstats = {
'table': self.table,
'latency_tuples': self.latency_tuples,
'search_page': 'true' if len(self.data_list) > 10 else 'false'
}
with open(dest_file, 'w') as dest:
print('Generating chart drawing code to ' + dest_file + '...')
output = self.tpl.render(kbstats=kbstats)
dest.write(output)
def get_display_file_name(filename):
res = os.path.basename(filename)
# remove extension
res, _ = os.path.splitext(res)
return res
def guess_line_rate(data_list):
max_tp_kb = 0
for data_list in data_list:
max_tp_kb = max(max_tp_kb, data_list['http_throughput_kbytes'])
max_tp_gb = (max_tp_kb * 8) / (1000 * 1000)
# typical GE line rates are 10, 40 and 100
if max_tp_gb < 10:
return 10
if max_tp_gb < 40:
return 40
return 100
def gen_chart(file_list, chart_dest, browser, line_rate):
data_list = []
for res_file in file_list:
print 'processing: ' + res_file
if not os.path.isfile(res_file):
print('Error: No such file %s: ' + res_file)
sys.exit(1)
with open(res_file) as data_file:
results = json.load(data_file)
results['filename'] = get_display_file_name(res_file)
data_list.append(results)
if not line_rate:
line_rate = guess_line_rate(data_list)
print line_rate
chart = KbReport(data_list, line_rate)
print('Generating report to ' + chart_dest + '...')
chart.plot(chart_dest)
if browser:
url = 'file://' + os.path.abspath(chart_dest)
webbrowser.open(url, new=2)
def get_absolute_path_for_file(file_name):
'''
Return the filename in absolute path for any file
passed as relateive path.
'''
abs_file = os.path.dirname(os.path.abspath(__file__))
return abs_file + '/' + file_name
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='KloudBuster Chart Generator V' + __version__)
parser.add_argument('-c', '--chart', dest='chart',
action='store',
help='create and save chart in html file',
metavar='<file>')
parser.add_argument('-b', '--browser', dest='browser',
action='store_true',
default=False,
help='display (-c) chart in the browser')
parser.add_argument('-v', '--version', dest='version',
default=False,
action='store_true',
help='print version of this script and exit')
parser.add_argument('-l', '--line-rate', dest='line_rate',
action='store',
default=0,
type=int,
help='line rate in Gbps (default=10)',
metavar='<rate-Gbps>')
parser.add_argument(dest='files',
help='KloudBuster json result file', nargs="+",
metavar='<file>')
opts = parser.parse_args()
if opts.version:
print('Version ' + __version__)
sys.exit(0)
gen_chart(opts.files, opts.chart, opts.browser, opts.line_rate)