From 5122a33e162b84fe1f5ff681c85c9bb6b7ae8af5 Mon Sep 17 00:00:00 2001 From: Christopher Kenna Date: Tue, 7 Dec 2010 02:06:39 -0500 Subject: netsec graphing --- netsec.py | 223 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 223 insertions(+) create mode 100755 netsec.py (limited to 'netsec.py') diff --git a/netsec.py b/netsec.py new file mode 100755 index 0000000..b1f4f30 --- /dev/null +++ b/netsec.py @@ -0,0 +1,223 @@ +#!/usr/bin/env python +import defapp + +from plot import decode +from util import load_csv_file, write_csv_file + +from math import ceil + +from numpy import amin, amax, mean, median, std, histogram, zeros, arange + +from os.path import splitext, basename +from optparse import make_option as o + +from gnuplot import gnuplot, FORMATS, Plot, label, curve + +options = [ + # output options + o('-f', '--format', action='store', dest='format', type='choice', + choices=FORMATS, help='output format'), + o(None, '--save-script', action='store_true', dest='save_script'), + o('-p', '--prefix', action='store', dest='prefix'), + + # formatting options + # These may or may not be supported by a particular experiment plotter. + o(None, '--smooth', action='store_true', dest='smooth'), + o(None, '--hist', action='store_true', dest='histogram'), + ] + +defaults = { + # output options + 'format' : 'pdf', + 'save_script' : False, + 'prefix' : '', + + # formatting options + 'histogram' : False, + 'smooth' : False, + } + +def get_stats_label(samples): + avg = mean(samples) + med = median(samples) + dev = std(samples) + max = amax(samples) + min = amin(samples) + return "min=%.2f max=%.2f avg=%.2f median=%.2f std=%.2f" \ + % (min, max, avg, med, dev) + +class NetsecPlotter(defapp.App): + def __init__(self): + defapp.App.__init__(self, options, defaults, no_std_opts=True) + self.tmpfiles = [] + + def make_plot(self, fname=None): + p = Plot() + p.output = "%s%s.%s" % (self.options.prefix, fname, self.options.format) + p.format = self.options.format + return p + + def setup_png(self, plot): + # standard png options; usually correct; never tweaked for paper + if self.options.format == 'png': + plot.font_size = 'large' + plot.size = (1024, 768) + plot.xticks = (0, 1) + plot.yticks = (0, 0.1) + plot.default_style = "linespoints" + return True + else: + return False + + def write(self, data, name, ext='data'): + if self.options.save_script: + fname = "%s.%s" % (name, ext) + write_csv_file(fname, data) + return fname + else: + tmp = write_csv_file(None, data) + # keep a reference so that it isn't deleted + self.tmpfiles.append(tmp) + return tmp.name + + def load(self, datafile): + data = load_csv_file(datafile) + print "loaded %d lines" % len(data) + return data + + def write_histogram(self, samples, name): + max = amax(samples) + (hist, edges) = histogram(samples, bins=max, + range=(0.5,max+.5)) + data = zeros((len(edges)-1, 3)) + cumulative = 0 + for i in xrange(len(hist)): + data[i, 0] = (edges[i] + edges[i + 1]) / 2.0 + data[i, 1] = hist[i] + cumulative += hist[i] + data[i, 2] = cumulative + + if len(hist) > 20: + label_freq = 10 + else: + label_freq = 1 + + for_file = [] + for i, row in enumerate(data): + label = '%d' % row[0] if row[0] % label_freq == 0 else '' + for_file.append([row[0], row[1], row[2], label]) + + return (data, self.write(for_file, name, ext='hist')) + + def render(self, p): + if self.options.save_script: + p.gnuplot_save(p.output + '.plot') + else: + p.gnuplot_exec() + + def plot_hchisto(self, datafile, name, conf): + data = self.load(datafile) + + #max_val = amax(data[:,1]) + + if self.options.histogram: + name += '_hist' + + p = self.make_plot(name) + + # place a label on the graph + p.labels = [label(0.5, 0.9, get_stats_label(data[:,1]), + coord=['graph', 'screen'], align='center')] + + (data, fname) = self.write_histogram(data[:,1], name) + p.xlabel = "hop count" + + p.ylabel = "number of sources" + p.setup_histogram(gap=1, boxwidth=1.0) + p.title = "hop counts;" + + if 'per-host' in conf: + p.title += " HC per-host: %s" % conf['per-host'] + + if 'as-num' in conf: + p.title += " AS=%s, IP/mask=%s/%s MB=%s Unique Hosts=%s" % \ + (conf['as-num'], conf['as-str'], conf['as-mask'], \ + conf['megabytes'], conf['num-hosts']) + +# p.xrange = (0, ceil(max_cost)) + p.xticks = (0, 10) +# p.yticks = (0, 1) + #p.yrange = (0, (ceil(amax(data[:,1]) / 100) * 100)) + + + ymax = amax(data[:,1]) + p.curves = [curve(histogram=fname, col=2, labels_col=4)] + p.yrange = (1, amax(data[:,1]) + 2) + + if ymax > 10000: + p.ylog = True + + #print "not implemented yet..." + #return + ## plot raw samples + #p.title = "raw decoding cost; input=%s; host=%s" \ + # % (conf['file'], conf['host']) + + #p.ylabel = "decoding cost (ms)" + #p.xlabel = "frame number" + #p.xrange = (0, len(data)) + ##p.xticks = (0, 100) + #p.yticks = (0, 1) + #p.yrange = (1, ceil(max_cost) + 2) + + #p.curves = [curve(fname=fname, xcol=2, ycol=1, title="decoding cost")] + + + #### Styling. + + if not self.setup_png(p): + p.rounded_caps = True + p.font = 'Helvetica' + + p.font_size = '10' + p.size = ('20cm', '10cm') + p.monochrome = False + p.dashed_lines = False + p.key = 'off' + p.default_style = 'points lw 1' + + if self.options.smooth: + p.default_style += " smooth bezier" + + self.render(p) + + + def plot_file(self, datafile): + bname = basename(datafile) + name, ext = splitext(bname) + conf = decode(name) + + if 'per-host' in conf or 'as-num' in conf: + self.plot_hchisto(datafile, name, conf) + + #for plot_type in plotters: + # if plot_type in conf: + # try: + # plotters[plot_type](datafile, name, conf) + # except IOError as err: + # self.err("Skipped '%s' (%s)." % err) + # break + #else: + # self.err("Skipped '%s'; unkown experiment type." + # % bname) + + # release all tmp files + self.tmpfiles = [] + + def default(self, _): + for i, datafile in enumerate(self.args): + self.out("[%d/%d] Processing %s ..." % (i + 1, len(self.args), datafile)) + self.plot_file(datafile) + +if __name__ == "__main__": + NetsecPlotter().launch() -- cgit v1.2.2