#!/usr/bin/env python import sys import os.path # # Chosen randomly by a seriously colour-blind dude (me! :-) using: # http://www.colorschemer.com/online.html # COLORS=["003df5", "f53d00", "00f5b8", "00b8f5", "00f53d", "ff7094"] if len(sys.argv) == 1: print >> sys.stderr, "usage: %s [... ]" % sys.argv[0] sys.exit(1) data_files = sys.argv[1:] if len(data_files) > len(COLORS): print >> sys.stderr, "Only %d data sets are supported" % len (COLORS) def process_data(data): f = file(data) buf = f.read() results = {} for l in buf.splitlines(): s = l.split() # example line: # 32 | 0.160/ 0.160/ 0.160/ 0.000 61.46/98.40/99.04/47.52/5.16 0/0/82187/2406919 | 0.170/ 0.178/ 0.180/ 0.004 52.22/97.32/99.48/0.52/16.10 0/0/72332/3331704 msg_size = int(s[0]) # process the backslashes from the throughput figures for i in range(2,6) + range(9,13): s[i] = s[i].strip('/') (gh_min, gh_avg, gh_max, gh_dev) = s[2:6] (hg_min, hg_avg, hg_max, hg_dev) = s[9:13] gh_idles = s[6].split('/') hg_idles = s[13].split('/') gh_vmexits = s[7].split('/') hg_vmexits = s[14].split('/') def calc_util(idles): # cpu figures are avg/cpu#0/cpu#1/cpu#2/cpu#3 # convert to average utilization across cpu#2 and cpu#3 return (200.0 - float(idles[3]) - float(idles[4])) / 2 def calc_exit(exits): # sum of vmexits across the four cpus return int(exits[0]) + int(exits[1]) + int(exits[2]) + int(exits[3]) results[msg_size] = {} results[msg_size]['tput'] = (gh_avg, hg_avg) results[msg_size]['util'] = (calc_util(gh_idles), calc_util(hg_idles)) results[msg_size]['exit'] = (calc_exit(gh_vmexits), calc_exit(hg_vmexits)) return results results = [] for f in data_files: results.append(process_data(f)) msg_sizes = results[0].keys() msg_sizes.sort() def aggregate(results, msg_sizes, key, idx): l = [] for msg_size in msg_sizes: l.append(str(results[msg_size][key][idx])) return ','.join(l) BASEURL="http://chart.apis.google.com/chart" CHSIZE="chs=770x385" CHTYPE="cht=lc" # 4 pixel black diamond for each data point CHMARK="chm=" + '|'.join(("d,000000,%d,-1,4.0" % i) for i in range(0,len(data_files))) #CHLEGEND="chdl=" + '|'.join(os.path.basename(f) for f in data_files) CHAXIS="chxt=x,y" CHXLABEL="chxl=0:|" + '|'.join(str(m) for m in msg_sizes) def chart(results, msg_sizes, key, max, idx): scale="chds=0,%d" % max chyrange="chxr=1,0,%d" % max data = "chd=t:" + '|'.join(aggregate(r, msg_sizes, key, idx) for r in results) colors="chco=" + ','.join(COLORS[:len(results)]) legend="chdl=orig|patch" return BASEURL + "?" + \ CHSIZE + "&" + \ data + "&" + \ scale + '&' + \ CHTYPE + '&' + \ colors + '&' + \ CHMARK + '&' + \ legend + '&' + \ CHAXIS + '&' + \ chyrange + '&' + \ CHXLABEL indices = [ ( "g-h", "guest->host" ), ( "h-g", "host->guest" ) ] keys = { 'tput' : "throughput", 'util' : "cpu utilization", 'exit' : "vmexits" } patches = [os.path.basename(f) for f in data_files[1:]] def output_page(idx, key, basename, url): f = file("%s-%s-%s.html" % (indices[idx][0], key, basename), "w"); title = "%s %s with %s" % (indices[idx][1], keys[key], basename) f.write("%s

%s

\n" % (title, title)) for (i, t) in indices: f.write("%s\n" % (i, key, basename, t)) f.write("||\n") for k in keys.keys(): f.write("%s\n" % (indices[idx][0], k, basename, keys[k])) f.write("||\n") for p in patches: f.write("%s\n" % (indices[idx][0], key, p, p)) f.write("

\n") f.write("\n" % url) pf = file("/home/markmc/trash/2008-11-06/" + basename) f.write("
%s
" % pf.read()) pf.close() f.write("If you're interested, the nasty scripts I used to generate these are here\n") f.write("\n") f.close() for idx in [0, 1]: for (key, max) in [('tput', 10), ('util', 100), ('exit', 4000000)]: for i in range(1, len(results)): url = chart([results[i-1], results[i]], msg_sizes, key, max, idx) output_page(idx, key, patches[i-1], url)