]> git.sesse.net Git - nms/commitdiff
Merge from andun.
authorSteinar H. Gunderson <sesse@samfundet.no>
Fri, 7 Apr 2006 13:55:13 +0000 (13:55 +0000)
committerSteinar H. Gunderson <sesse@samfundet.no>
Fri, 7 Apr 2006 13:55:13 +0000 (13:55 +0000)
Patches applied:

 * korbekk@start.no--2006--public/nms--kjetil--1.0--base-0
   tag of sgunderson@bigfoot.com--2006/nms--mainline--1.0--patch-29

 * korbekk@start.no--2006--public/nms--kjetil--1.0--patch-1
   new graph generating code in C to make it faster (about 5x faster)

web/ext/Makefile.PL [new file with mode: 0644]
web/ext/Makefile.super [new file with mode: 0644]
web/ext/glue.pl [new file with mode: 0644]
web/ext/graph.c [new file with mode: 0644]
web/ext/graph.h [new file with mode: 0644]
web/ext/graph.i [new file with mode: 0644]
web/ext/showswitch.pl [new file with mode: 0755]

diff --git a/web/ext/Makefile.PL b/web/ext/Makefile.PL
new file mode 100644 (file)
index 0000000..e12c8d6
--- /dev/null
@@ -0,0 +1,10 @@
+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
+);
diff --git a/web/ext/Makefile.super b/web/ext/Makefile.super
new file mode 100644 (file)
index 0000000..f88fc9f
--- /dev/null
@@ -0,0 +1,12 @@
+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
diff --git a/web/ext/glue.pl b/web/ext/glue.pl
new file mode 100644 (file)
index 0000000..c1f384c
--- /dev/null
@@ -0,0 +1,13 @@
+#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;
diff --git a/web/ext/graph.c b/web/ext/graph.c
new file mode 100644 (file)
index 0000000..ddd726b
--- /dev/null
@@ -0,0 +1,246 @@
+#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);
+}
+
diff --git a/web/ext/graph.h b/web/ext/graph.h
new file mode 100644 (file)
index 0000000..2d39217
--- /dev/null
@@ -0,0 +1,43 @@
+/* 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);
+
diff --git a/web/ext/graph.i b/web/ext/graph.i
new file mode 100644 (file)
index 0000000..b04056c
--- /dev/null
@@ -0,0 +1,29 @@
+%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);
diff --git a/web/ext/showswitch.pl b/web/ext/showswitch.pl
new file mode 100755 (executable)
index 0000000..8cfa390
--- /dev/null
@@ -0,0 +1,237 @@
+#!/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";