--- /dev/null
+my $libs = `pkg-config --libs cairo`;
+my $inc = `pkg-config --cflags cairo`;
+
+use ExtUtils::MakeMaker;
+WriteMakefile(
+ 'NAME' => 'mygraph', # Name of module
+ 'LIBS' => $libs,
+ 'INC' => $inc,
+ 'OBJECT' => 'graph_wrap.o' # All object files
+);
--- /dev/null
+all:
+ swig -perl5 graph.i
+ perl Makefile.PL
+ make
+ mv blib/arch/auto/mygraph/mygraph.so ./
+ mv blib/lib/mygraph.pm ./
+ rm -fr blib
+ rm pm_to_blib
+
+clean:
+ rm -f mygraph.pm mygraph.so graph_wrap.c graph_wrap.o \
+ Makefile mygraph.bs
--- /dev/null
+#glue
+
+sub create_array {
+ my $len = scalar(@_);
+ my $ia = mygraph::int_array($len);
+ for (my $i = 0; $i < $len; $i++) {
+ my $val = shift;
+ mygraph::int_set($ia,$i,$val);
+ }
+ return $ia;
+}
+
+1;
--- /dev/null
+#include "graph.h"
+
+
+void
+mygraph_fill_background(graph *mygraph);
+
+void
+mygraph_draw_graph (cairo_t *cr,
+ int x,
+ int y );
+
+graph *
+mygraph_new (int width, int height)
+{
+ graph *mygraph;
+ mygraph = malloc(sizeof(graph));
+ mygraph->width = width;
+ mygraph->height = height;
+
+
+ int stride = width * 4;
+ unsigned char *image;
+ image = (unsigned char *) malloc (sizeof(unsigned char) * stride * height);
+
+ mygraph->surface = cairo_image_surface_create_for_data (image, CAIRO_FORMAT_ARGB32,
+ width, height, stride);
+ mygraph->cr = cairo_create (mygraph->surface);
+
+ cairo_set_source_rgb (mygraph->cr, 1.0, 1.0, 1.0);
+ mygraph_fill_background (mygraph);
+
+ cairo_select_font_face (mygraph->cr, "Sans", CAIRO_FONT_SLANT_NORMAL,
+ CAIRO_FONT_WEIGHT_NORMAL);
+ cairo_set_font_size (mygraph->cr, 10);
+
+ cairo_set_antialias(mygraph->cr, CAIRO_ANTIALIAS_NONE);
+ cairo_set_line_width (mygraph->cr, 1.0);
+
+ return mygraph;
+}
+
+graph *
+mygraph_make_graph (graph *mygraph, float min_x, float max_x,
+ float min_y, float max_y, int tickgran)
+{
+ int xoffset = 70;
+ cairo_text_extents_t extents;
+
+ mygraph->xoffset = xoffset;
+ mygraph->min_x = min_x;
+ mygraph->max_x = max_x;
+ mygraph->min_y = min_y;
+ mygraph->max_y = max_y;
+
+/* cairo_t *cr; */
+/* cairo_surface_t *surface; */
+
+ float xs = ((float)mygraph->width - (float)(xoffset+2)) /
+ (float)(max_x - min_x);
+
+ float ys = ((float)mygraph->height - 33.) / (float)(min_y - max_y);
+
+ mygraph->xs = xs;
+ mygraph->ys = ys;
+
+ float starthour = fmod((min_x + (float)tz_local_offset()) / 3600., 24.);
+ float diff, center, begin, end;
+
+ char string[20];
+
+ int i;
+ for (i = 0; i<24; i++)
+ { // Hour marks and text
+ if ((i % 2) == 0)
+ cairo_set_source_rgb (mygraph->cr, 1.0, 1.0, 1.0);
+ else
+ cairo_set_source_rgb (mygraph->cr, 0.90, 0.90, 1.0);
+
+ diff = fmod((float)i - starthour + 24., 24.);
+ begin = (diff * 3600.) * xs;
+ end = ((fmod(((float)i+1) - starthour + 24., 24.)) * 3600.) * xs;
+ center = (begin + end) / 2.;
+
+ if (begin > end)
+ begin = 0.;
+
+ // printf("i: %d, starthour: %f, diff: %f, begin: %f, end: %f\n", i, starthour, diff, begin, end);
+
+ if (begin < 0.)
+ begin = 0.0;
+ if (begin > ((float)mygraph->width - ((float)xoffset)))
+ continue;
+ // printf("drawing\n");
+
+ cairo_rectangle (mygraph->cr, xoffset+begin, 0,
+ end - begin, mygraph->height);
+
+ cairo_fill (mygraph->cr);
+
+ if (begin <= 0.0 || end >= mygraph->width - (xoffset))
+ continue;
+
+ cairo_set_source_rgb (mygraph->cr, 0.0, 0.0, 0.0);
+
+ sprintf(string, "%d", i);
+ // printf("showing string %s\n", string);
+
+ cairo_text_extents (mygraph->cr, string, &extents);
+ cairo_move_to (mygraph->cr, xoffset + center -
+ (extents.width/2),
+ (mygraph->height - extents.height - 2));
+
+ cairo_show_text (mygraph->cr, string);
+
+ }
+
+ cairo_set_source_rgb (mygraph->cr, 0.4, 0.4, 0.4);
+ int ytick;
+ do
+ {
+ ytick = ((int)max_y - (int)min_y) / 11;
+ ytick = ceil (ytick / tickgran) * tickgran;
+ tickgran *= 0.1;
+ } while (((int)max_y - (int)min_y) / ytick < 4);
+
+ int y, traf;
+ for (i = -11; i<12; i++)
+ {
+ y = (i * ytick - (int)max_y) * ys + 10;
+ if (y < 2 || y > mygraph->height - 18)
+ continue;
+
+/* printf("draw line at %d\n", y); */
+
+ cairo_move_to (mygraph->cr, xoffset, y);
+ cairo_line_to (mygraph->cr, mygraph->width-1, y);
+
+ if (i == 0)
+ {
+
+ cairo_set_source_rgb (mygraph->cr, 0.0, 0.0, 1.0);
+ cairo_stroke (mygraph->cr);
+ cairo_set_source_rgb (mygraph->cr, 0.6, 0.6, 0.6);
+ }
+ else
+ cairo_stroke (mygraph->cr);
+
+ // draw text
+ traf = 8 * (i * ytick);
+/* printf("traffic: %d\n", traf); */
+
+ if (traf >= 500000000)
+ sprintf (string, "%.1f Gbit", ((float)traf/1000000000));
+ else if (traf >= 500000)
+ sprintf (string, "%.1f Mbit", ((float)traf/1000000));
+ else
+ sprintf (string, "%.1f kbit", ((float)traf/1000));
+
+ cairo_text_extents (mygraph->cr, string, &extents);
+
+ if (y - (extents.height/2) < 2 ||
+ y + (extents.height/2) > mygraph->height - (extents.height + 2))
+ continue;
+
+ cairo_move_to (mygraph->cr,
+ xoffset - 4 - extents.width,
+ y + (extents.height/2));
+
+ cairo_show_text (mygraph->cr, string);
+ }
+
+ cairo_rectangle (mygraph->cr, xoffset, 0, mygraph->width-xoffset-1, mygraph->height-1);
+
+ cairo_set_source_rgb (mygraph->cr, 0.0, 0.0, 0.0);
+ cairo_stroke (mygraph->cr);
+
+ return mygraph;
+}
+
+void
+mygraph_plot_series (graph *mygraph, int *xvals, int *yvals, int n_vals,
+ float r, float g, float b)
+{
+ int x, y, i;
+ x = xvals[0];
+ y = yvals[0];
+
+ cairo_set_antialias(mygraph->cr, CAIRO_ANTIALIAS_DEFAULT);
+ cairo_set_source_rgb (mygraph->cr, r, g, b);
+
+ cairo_move_to (mygraph->cr,
+ (int)((float)(x - (int)mygraph->min_x) *
+ mygraph->xs + (float)(mygraph->xoffset + 1)),
+ (int)((float)(y - (int)mygraph->max_y) * mygraph->ys + 10.));
+
+/* printf("Plotting from:\n"); */
+/* printf("(%d, %d) %d (%d, %d)<br/>\n", */
+/* x, y, (int)((float)(x - (int)mygraph->min_x) * mygraph->xs + (float)(mygraph->xoffset + 1)) , */
+/* (int)((float)(x - (int)mygraph->min_x) * mygraph->xs + (float)(mygraph->xoffset + 1)), */
+/* (int)((float)(y - (int)mygraph->max_y) * mygraph->ys + 10.)); */
+
+ for (i = 1; i < n_vals; i++)
+ {
+
+ if (mygraph->xs * (xvals[i] - x) < 2 &&
+ mygraph->ys * (yvals[i] - y) > -2)
+ continue;
+
+ x = xvals[i];
+ y = yvals[i];
+
+ cairo_line_to (mygraph->cr,
+ (int)((float)(x - (int)mygraph->min_x) *
+ mygraph->xs + (float)(mygraph->xoffset + 1)),
+ (int)((float)(y - (int)mygraph->max_y) * mygraph->ys + 10.));
+
+/* printf("(%d, %d) = > (%d, %d)<br/>\n", */
+/* x, y, */
+/* (int)((x - (int)x-mygraph->min_x) * (int)mygraph->xs + (int)mygraph->xoffset + 1), */
+/* (int)((y - (int)mygraph->max_y) * (int)mygraph->ys + 10)); */
+
+ }
+
+ cairo_stroke(mygraph->cr);
+}
+
+void
+mygraph_to_file (graph *mygraph, char *filename)
+{
+ cairo_surface_write_to_png (mygraph->surface, filename);
+}
+
+void
+mygraph_cleanup (graph *self)
+{
+ cairo_destroy (self->cr);
+ cairo_surface_destroy (self->surface);
+}
+
+void
+mygraph_fill_background (graph *mygraph)
+{
+ cairo_rectangle (mygraph->cr, 0, 0, mygraph->width, mygraph->height);
+ cairo_fill (mygraph->cr);
+}
+
--- /dev/null
+/* Copyright (C) 2006 Kjetil Ørbekk, Norway */
+
+#include <cairo.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+typedef struct _graph {
+ cairo_t *cr;
+ cairo_surface_t *surface;
+ int width;
+ int height;
+ int xoffset;
+ int yoffset;
+ float min_x;
+ float max_x;
+ float min_y;
+ float max_y;
+ float xs;
+ float ys;
+} graph;
+
+int tz_local_offset() { return 7200; } // riktig?
+
+void mygraph_fill_background(graph *mygraph);
+
+void mygraph_draw_graph (cairo_t *cr, int x, int y );
+
+graph *mygraph_new (int width, int height);
+
+graph *mygraph_make_graph (graph *mygraph, float min_x,
+ float max_x, float min_y, float max_y,
+ int tickgran);
+
+void mygraph_plot_series (graph *mygraph, int *xvals, int *yvals,
+ int n_vals, float r, float g, float b);
+
+void mygraph_to_file (graph *mygraph, char *filename);
+
+void mygraph_cleanup (graph *self);
+
+void mygraph_fill_background (graph *mygraph);
+
--- /dev/null
+%module mygraph
+%{
+#include "graph.c"
+%}
+
+%inline
+%{
+ // Add some helper functions for C arrays
+ int *int_array(int size) {
+ return (int *) malloc(sizeof(int)*size);
+ }
+ void int_destroy(int *a) {
+ free(a);
+ }
+ void int_set(int *a, int i, int val) {
+ a[i] = val;
+ }
+ int int_get(int *a, int i) {
+ return a[i];
+ }
+%}
+
+graph *mygraph_new (int width, int height);
+graph *mygraph_make_graph (graph *mygraph, float min_x,
+ float max_x, float min_y, float max_y, int tickgran);
+void mygraph_cleanup (graph *mygraph);
+void mygraph_to_file (graph *mygraph, char *filename);
+void mygraph_plot_series (graph *mygraph, int *xvals, int *yvals, int n_vals,
+ float r, float g, float b);
--- /dev/null
+#!/usr/bin/perl
+use CGI;
+use DBI;
+use Time::HiRes;
+use POSIX ":sys_wait_h";
+use strict;
+use warnings;
+
+use mygraph;
+require 'glue.pl';
+
+my $cgi = CGI->new;
+my $switch = 9; #$cgi->param('id');
+my $width = $cgi->param('width');
+my $height = $cgi->param('height');
+my @pids = ();
+my $resthtml = "";
+
+$width = 500 unless (defined($width));
+$height = 250 unless (defined($height));
+
+my $graph = mygraph::mygraph_new($width, $height);
+
+my $start = [Time::HiRes::gettimeofday];
+my $dbh = DBI->connect("dbi:Pg:dbname=tg", "tg", "tg06")
+ or die "Couldn't connect to database";
+
+# Fetch the name
+my $ref = $dbh->selectrow_hashref('SELECT sysname FROM switches WHERE switch=?', undef, $switch);
+
+print $cgi->header(-type=>'text/html; charset=utf-8');
+print <<"EOF";
+<html>
+ <head>
+ <title>snmp</title>
+ </head>
+ <body>
+ <h1>Switch $switch ($ref->{'sysname'})</h1>
+EOF
+
+my $q = $dbh->prepare('select port,coalesce(description, \'Port \' || port) as description,extract(epoch from time) as time,bytes_in,bytes_out from polls natural join switches natural left join portnames where time between \'2005-03-23 05:17:36+01\' and \'2005-03-24 05:17:36+01\' and switch=? order by switch,port,time;');
+$q->execute($switch);
+
+my (@totx, @toty1, @toty2) = ();
+
+my (@x, @y1, @y2) = ();
+my $last_port = -1;
+my $portname = "";
+my $min_x = 1111637856.70337; #time;
+my $max_x = 1111551456; #time - 86400;
+my ($min_y, $max_y, $prev_time, $prev_in, $prev_out);
+my ($if,$of,$ifv,$ofv);
+my $idx;
+my ($min_ty,$max_ty) = (0, 10_000_000/8);
+
+$prev_time = -1;
+my $last_totx;
+while (my $ref = $q->fetchrow_hashref()) {
+ my $time = $ref->{'time'};
+ my $in = $ref->{'bytes_in'};
+ my $out = $ref->{'bytes_out'};
+ next if ($time == $prev_time);
+
+ if ($ref->{'port'} != $last_port) {
+ if ($last_port != -1) {
+ my $filename = "$switch-$last_port-$width-$height.png";
+
+ # reap children
+ waitpid(-1, WNOHANG);
+
+ my $numpids = 0;
+
+ my $pid = fork();
+ if ($pid == 0) {
+ # write out the graph
+ # print "$width, $height, $min_x, $max_x, $min_y, $max_y, 5<br/>\n";
+
+ my $x_c = create_array(@x);
+ my $y1_c = create_array(@y1);
+ my $y2_c = create_array(@y2);
+
+# my $startthis = [Time::HiRes::gettimeofday];
+ mygraph::mygraph_make_graph($graph, $min_x, $max_x, $min_y, $max_y, 5);
+ mygraph::mygraph_plot_series($graph, $x_c, $y1_c, $#x, 255, 0, 0);
+ mygraph::mygraph_plot_series($graph, $x_c, $y2_c, $#x, 0, 0, 255);
+ mygraph::mygraph_to_file($graph, "img/$filename");
+# mygraph::mygraph_cleanup ($graph);
+# my $elapsedthis = Time::HiRes::tv_interval($startthis);
+# printf "$elapsedthis seconds<br/>\n";
+
+ exit;
+ }
+
+ push @pids, $pid;
+
+ $resthtml .= "<div style=\"float: left;\"><h2>$portname</h2>\n";
+ $resthtml .= "<p><img src=\"img/$filename\" width=\"$width\" height=\"$height\" /></p></div>\n";
+ }
+
+ # Reset all the variables
+ @x = ();
+ @y1 = ();
+ @y2 = ();
+ ($min_y,$max_y) = (0, 10_000_000/8);
+ $prev_time = $ref->{'time'};
+ $prev_in = $ref->{'bytes_in'};
+ $prev_out = $ref->{'bytes_out'};
+ $last_port = $ref->{'port'};
+ $portname = $ref->{'description'};
+ ($if,$of,$ifv,$ofv) = (0,0,0,0);
+ ($prev_time,$prev_in,$prev_out) = ($time,$in,$out);
+ $idx = 0;
+ $last_totx = undef;
+ next;
+ }
+
+ # Assume overflow (unless the switch has been down for >10 minutes)
+ my ($calc_in, $calc_out) = ($in, $out);
+ if ($in < $prev_in || $out < $prev_out) {
+ # ick, heuristics
+ if ($prev_time - $time > 600 || ($in + 4294967296 - $prev_in) > 2147483648 || ($out + 4294967296 - $prev_out) > 2147483648) {
+ ($prev_time,$prev_in,$prev_out) = ($time,$in,$out);
+ next;
+ }
+
+ $calc_in += 4294967296 if ($in < $prev_in);
+ $calc_out += 4294967296 if ($out < $prev_out);
+ }
+
+ # Remove dupes
+ if ($in == $prev_in && $out == $prev_out) {
+ ($prev_time,$prev_in,$prev_out) = ($time,$in,$out);
+ next;
+ }
+
+ # Find the current flow
+ my $if = ($calc_in - $prev_in) / ($time - $prev_time);
+ my $of = ($calc_out - $prev_out) / ($time - $prev_time);
+
+ # Summarize (we don't care about the summed variance for now)
+ $min_x = $time if (!defined($min_x) || $time < $min_x);
+ $max_x = $time if (!defined($max_x) || $time > $max_x);
+ $min_y = $if if (!defined($min_y) || $if < $min_y);
+ $min_y = $of if ($of < $min_y);
+ $max_y = $if if (!defined($max_y) || $if > $max_y);
+ $max_y = $of if ($of > $max_y);
+
+ my $pt = 0.5 * ($time + $prev_time);
+
+ push @x, $pt;
+ push @y1, $if;
+ push @y2, $of;
+
+ while ($idx < $#totx && $pt > $totx[$idx]) {
+ ++$idx;
+ }
+ if ($idx >= $#totx) {
+ push @totx, $pt;
+ push @toty1, $if;
+ push @toty2, $of;
+ ++$idx;
+
+ $min_ty = $if if (!defined($min_ty) || $if < $min_ty);
+ $min_ty = $of if ($of < $min_ty);
+ $max_ty = $if if (!defined($max_ty) || $if > $max_ty);
+ $max_ty = $of if ($of > $max_ty);
+ } else {
+ if (!defined($last_totx) || $last_totx != $idx) {
+ $toty1[$idx] += $if;
+ $toty2[$idx] += $of;
+ }
+ $last_totx = $idx;
+
+ $min_ty = $toty1[$idx] if (!defined($min_ty) || $toty1[$idx] < $min_ty);
+ $min_ty = $toty2[$idx] if ($toty2[$idx] < $min_ty);
+ $max_ty = $toty1[$idx] if (!defined($max_ty) || $toty1[$idx] > $max_ty);
+ $max_ty = $toty2[$idx] if ($toty2[$idx] > $max_ty);
+ }
+
+ ($prev_time,$prev_in,$prev_out) = ($time,$in,$out);
+}
+$dbh->disconnect;
+
+# last graph
+my $filename = "$switch-$last_port-$width-$height.png";
+
+my $pid = fork();
+if ($pid == 0) {
+ my $x_c = create_array(@x);
+ my $y1_c = create_array(@y1);
+ my $y2_c = create_array(@y2);
+
+# my $startthis = [Time::HiRes::gettimeofday];
+ mygraph::mygraph_make_graph($graph, $min_x, $max_x, $min_y, $max_y, 5);
+ mygraph::mygraph_plot_series($graph, $x_c, $y1_c, $#x, 255, 0, 0);
+ mygraph::mygraph_plot_series($graph, $x_c, $y2_c, $#x, 0, 0, 255);
+ mygraph::mygraph_to_file($graph, "img/$filename");
+# mygraph::mygraph_cleanup ($graph);
+# my $elapsedthis = Time::HiRes::tv_interval($startthis);
+# printf "$elapsedthis seconds<br/>\n";
+
+ exit;
+}
+
+push @pids, $pid;
+
+$resthtml .= "<div style=\"float: left;\"><h2>$portname</h2>\n";
+$resthtml .= "<p><img src=\"img/$filename\" width=\"$width\" height=\"$height\" /></p></div>\n";
+
+# total graph
+$filename = "$switch-$width-$height.png";
+my $x_c = create_array(@totx);
+my $y1_c = create_array(@toty1);
+my $y2_c = create_array(@toty2);
+
+# my $startthis = [Time::HiRes::gettimeofday];
+mygraph::mygraph_make_graph($graph, $min_x, $max_x, $min_y, $max_y, 5);
+mygraph::mygraph_plot_series($graph, $x_c, $y1_c, $#totx, 255, 0, 0);
+mygraph::mygraph_plot_series($graph, $x_c, $y2_c, $#totx, 0, 0, 255);
+mygraph::mygraph_to_file($graph, "img/$filename");
+#mygraph::mygraph_cleanup ($graph);
+# my $elapsedthis = Time::HiRes::tv_interval($startthis);
+# printf "$elapsedthis seconds<br/>\n";
+
+# Wait for all the other graphs to be done
+while (waitpid(-1, 0) != -1) {
+ 1;
+}
+
+print $resthtml;
+
+print "<div style=\"float: left;\"><h2>Total</h2>\n";
+print "<p><img src=\"img/$filename\" width=\"$width\" height=\"$height\" /></p></div>\n";
+
+my $elapsed = Time::HiRes::tv_interval($start);
+printf "<p style=\"clear: both;\">Page and all graphs generated in %.2f seconds.</p>\n", $elapsed;
+print "</body>\n</html>\n";