mirror of
https://github.com/kasmtech/KasmVNC.git
synced 2024-12-01 12:33:20 +01:00
207 lines
6.5 KiB
Python
207 lines
6.5 KiB
Python
|
#!/usr/bin/env python
|
||
|
|
||
|
'''
|
||
|
Use matplotlib to generate performance charts
|
||
|
Copyright (C) 2018 The noVNC Authors
|
||
|
Licensed under MPL-2.0 (see docs/LICENSE.MPL-2.0)
|
||
|
'''
|
||
|
|
||
|
# a bar plot with errorbars
|
||
|
import sys, json
|
||
|
import numpy as np
|
||
|
import matplotlib.pyplot as plt
|
||
|
from matplotlib.font_manager import FontProperties
|
||
|
|
||
|
def usage():
|
||
|
print "%s json_file level1 level2 level3 [legend_height]\n\n" % sys.argv[0]
|
||
|
print "Description:\n"
|
||
|
print "level1, level2, and level3 are one each of the following:\n";
|
||
|
print " select=ITEM - select only ITEM at this level";
|
||
|
print " bar - each item on this level becomes a graph bar";
|
||
|
print " group - items on this level become groups of bars";
|
||
|
print "\n";
|
||
|
print "json_file is a file containing json data in the following format:\n"
|
||
|
print ' {';
|
||
|
print ' "conf": {';
|
||
|
print ' "order_l1": [';
|
||
|
print ' "level1_label1",';
|
||
|
print ' "level1_label2",';
|
||
|
print ' ...';
|
||
|
print ' ],';
|
||
|
print ' "order_l2": [';
|
||
|
print ' "level2_label1",';
|
||
|
print ' "level2_label2",';
|
||
|
print ' ...';
|
||
|
print ' ],';
|
||
|
print ' "order_l3": [';
|
||
|
print ' "level3_label1",';
|
||
|
print ' "level3_label2",';
|
||
|
print ' ...';
|
||
|
print ' ]';
|
||
|
print ' },';
|
||
|
print ' "stats": {';
|
||
|
print ' "level1_label1": {';
|
||
|
print ' "level2_label1": {';
|
||
|
print ' "level3_label1": [val1, val2, val3],';
|
||
|
print ' "level3_label2": [val1, val2, val3],';
|
||
|
print ' ...';
|
||
|
print ' },';
|
||
|
print ' "level2_label2": {';
|
||
|
print ' ...';
|
||
|
print ' },';
|
||
|
print ' },';
|
||
|
print ' "level1_label2": {';
|
||
|
print ' ...';
|
||
|
print ' },';
|
||
|
print ' ...';
|
||
|
print ' },';
|
||
|
print ' }';
|
||
|
sys.exit(2)
|
||
|
|
||
|
def error(msg):
|
||
|
print msg
|
||
|
sys.exit(1)
|
||
|
|
||
|
|
||
|
#colors = ['#ff0000', '#0863e9', '#00f200', '#ffa100',
|
||
|
# '#800000', '#805100', '#013075', '#007900']
|
||
|
colors = ['#ff0000', '#00ff00', '#0000ff',
|
||
|
'#dddd00', '#dd00dd', '#00dddd',
|
||
|
'#dd6622', '#dd2266', '#66dd22',
|
||
|
'#8844dd', '#44dd88', '#4488dd']
|
||
|
|
||
|
if len(sys.argv) < 5:
|
||
|
usage()
|
||
|
|
||
|
filename = sys.argv[1]
|
||
|
L1 = sys.argv[2]
|
||
|
L2 = sys.argv[3]
|
||
|
L3 = sys.argv[4]
|
||
|
if len(sys.argv) > 5:
|
||
|
legendHeight = float(sys.argv[5])
|
||
|
else:
|
||
|
legendHeight = 0.75
|
||
|
|
||
|
# Load the JSON data from the file
|
||
|
data = json.loads(file(filename).read())
|
||
|
conf = data['conf']
|
||
|
stats = data['stats']
|
||
|
|
||
|
# Sanity check data hierarchy
|
||
|
if len(conf['order_l1']) != len(stats.keys()):
|
||
|
error("conf.order_l1 does not match stats level 1")
|
||
|
for l1 in stats.keys():
|
||
|
if len(conf['order_l2']) != len(stats[l1].keys()):
|
||
|
error("conf.order_l2 does not match stats level 2 for %s" % l1)
|
||
|
if conf['order_l1'].count(l1) < 1:
|
||
|
error("%s not found in conf.order_l1" % l1)
|
||
|
for l2 in stats[l1].keys():
|
||
|
if len(conf['order_l3']) != len(stats[l1][l2].keys()):
|
||
|
error("conf.order_l3 does not match stats level 3")
|
||
|
if conf['order_l2'].count(l2) < 1:
|
||
|
error("%s not found in conf.order_l2" % l2)
|
||
|
for l3 in stats[l1][l2].keys():
|
||
|
if conf['order_l3'].count(l3) < 1:
|
||
|
error("%s not found in conf.order_l3" % l3)
|
||
|
|
||
|
#
|
||
|
# Generate the data based on the level specifications
|
||
|
#
|
||
|
bar_labels = None
|
||
|
group_labels = None
|
||
|
bar_vals = []
|
||
|
bar_sdvs = []
|
||
|
if L3.startswith("select="):
|
||
|
select_label = l3 = L3.split("=")[1]
|
||
|
bar_labels = conf['order_l1']
|
||
|
group_labels = conf['order_l2']
|
||
|
bar_vals = [[0]*len(group_labels) for i in bar_labels]
|
||
|
bar_sdvs = [[0]*len(group_labels) for i in bar_labels]
|
||
|
for b in range(len(bar_labels)):
|
||
|
l1 = bar_labels[b]
|
||
|
for g in range(len(group_labels)):
|
||
|
l2 = group_labels[g]
|
||
|
bar_vals[b][g] = np.mean(stats[l1][l2][l3])
|
||
|
bar_sdvs[b][g] = np.std(stats[l1][l2][l3])
|
||
|
elif L2.startswith("select="):
|
||
|
select_label = l2 = L2.split("=")[1]
|
||
|
bar_labels = conf['order_l1']
|
||
|
group_labels = conf['order_l3']
|
||
|
bar_vals = [[0]*len(group_labels) for i in bar_labels]
|
||
|
bar_sdvs = [[0]*len(group_labels) for i in bar_labels]
|
||
|
for b in range(len(bar_labels)):
|
||
|
l1 = bar_labels[b]
|
||
|
for g in range(len(group_labels)):
|
||
|
l3 = group_labels[g]
|
||
|
bar_vals[b][g] = np.mean(stats[l1][l2][l3])
|
||
|
bar_sdvs[b][g] = np.std(stats[l1][l2][l3])
|
||
|
elif L1.startswith("select="):
|
||
|
select_label = l1 = L1.split("=")[1]
|
||
|
bar_labels = conf['order_l2']
|
||
|
group_labels = conf['order_l3']
|
||
|
bar_vals = [[0]*len(group_labels) for i in bar_labels]
|
||
|
bar_sdvs = [[0]*len(group_labels) for i in bar_labels]
|
||
|
for b in range(len(bar_labels)):
|
||
|
l2 = bar_labels[b]
|
||
|
for g in range(len(group_labels)):
|
||
|
l3 = group_labels[g]
|
||
|
bar_vals[b][g] = np.mean(stats[l1][l2][l3])
|
||
|
bar_sdvs[b][g] = np.std(stats[l1][l2][l3])
|
||
|
else:
|
||
|
usage()
|
||
|
|
||
|
# If group is before bar then flip (zip) the data
|
||
|
if [L1, L2, L3].index("group") < [L1, L2, L3].index("bar"):
|
||
|
bar_labels, group_labels = group_labels, bar_labels
|
||
|
bar_vals = zip(*bar_vals)
|
||
|
bar_sdvs = zip(*bar_sdvs)
|
||
|
|
||
|
print "bar_vals:", bar_vals
|
||
|
|
||
|
#
|
||
|
# Now render the bar graph
|
||
|
#
|
||
|
ind = np.arange(len(group_labels)) # the x locations for the groups
|
||
|
width = 0.8 * (1.0/len(bar_labels)) # the width of the bars
|
||
|
|
||
|
fig = plt.figure(figsize=(10,6), dpi=80)
|
||
|
plot = fig.add_subplot(1, 1, 1)
|
||
|
|
||
|
rects = []
|
||
|
for i in range(len(bar_vals)):
|
||
|
rects.append(plot.bar(ind+width*i, bar_vals[i], width, color=colors[i],
|
||
|
yerr=bar_sdvs[i], align='center'))
|
||
|
|
||
|
# add some
|
||
|
plot.set_ylabel('Milliseconds (less is better)')
|
||
|
plot.set_title("Javascript array test: %s" % select_label)
|
||
|
plot.set_xticks(ind+width)
|
||
|
plot.set_xticklabels( group_labels )
|
||
|
|
||
|
fontP = FontProperties()
|
||
|
fontP.set_size('small')
|
||
|
plot.legend( [r[0] for r in rects], bar_labels, prop=fontP,
|
||
|
loc = 'center right', bbox_to_anchor = (1.0, legendHeight))
|
||
|
|
||
|
def autolabel(rects):
|
||
|
# attach some text labels
|
||
|
for rect in rects:
|
||
|
height = rect.get_height()
|
||
|
if np.isnan(height):
|
||
|
height = 0.0
|
||
|
plot.text(rect.get_x()+rect.get_width()/2., height+20, '%d'%int(height),
|
||
|
ha='center', va='bottom', size='7')
|
||
|
|
||
|
for rect in rects:
|
||
|
autolabel(rect)
|
||
|
|
||
|
# Adjust axis sizes
|
||
|
axis = list(plot.axis())
|
||
|
axis[0] = -width # Make sure left side has enough for bar
|
||
|
#axis[1] = axis[1] * 1.20 # Add 20% to the right to make sure it fits
|
||
|
axis[2] = 0 # Make y-axis start at 0
|
||
|
axis[3] = axis[3] * 1.10 # Add 10% to the top
|
||
|
plot.axis(axis)
|
||
|
|
||
|
plt.show()
|