]> git.sesse.net Git - nms/commitdiff
Add lots of TG06 graph stuff.
authorroot <root@space>
Wed, 4 Apr 2007 10:14:07 +0000 (12:14 +0200)
committerroot <root@space>
Wed, 4 Apr 2007 10:14:07 +0000 (12:14 +0200)
web/ext/comparegraph.cpp [new file with mode: 0644]
web/ext/flowpusher.cpp [new file with mode: 0644]
web/ext/flowpusher.h [new file with mode: 0644]
web/ext/flowutil.cpp [new file with mode: 0644]
web/ext/flowutil.h [new file with mode: 0644]
web/ext/graph.cpp [new file with mode: 0755]
web/ext/graphall.cpp [new file with mode: 0644]
web/ext/totalcount.cpp [new file with mode: 0644]
web/ext/totalgraph.cpp [new file with mode: 0644]

diff --git a/web/ext/comparegraph.cpp b/web/ext/comparegraph.cpp
new file mode 100644 (file)
index 0000000..5beb37d
--- /dev/null
@@ -0,0 +1,172 @@
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <malloc.h>
+#include <vector>
+#include <algorithm>
+#include <pqxx/pqxx>
+#include "graph.h"
+#include "flowpusher.h"
+#include "flowutil.h"
+
+namespace pqxx {
+       template<>
+       void from_string<long long>(const char *from, long long &to)
+       {
+               to = atoll(from);
+       }
+}
+                                               
+
+int main(int argc, char **argv)
+{
+       int width = 1000, height = 500;
+       pqxx::connection conn05("dbname=nms05 host=localhost user=nms password=seesahS4");
+       pqxx::connection conn("dbname=nms host=localhost user=nms password=seesahS4");
+
+       std::vector<flow_element> flow, total_flow, total_flow05;
+       FlowPusher fp(flow);
+       int last_port = -1;
+       
+       mallopt(M_TRIM_THRESHOLD, -1);
+       
+       int num_total = 0;
+       pqxx::work t(conn, "fetch_all");
+       pqxx::icursorstream::icursorstream cstream(t, "select port,extract(epoch from time) as time,bytes_in,bytes_out from polls natural join switches where ((switchtype='es3024' and port < 25) or (switchtype='summit400' and port > 1)) order by switch,port,time", "fetch_all", 500);
+       
+       for ( ;; ) {
+               pqxx::result res;
+               
+               cstream >> res;
+               if (res.empty()) 
+                       break;
+
+               for (unsigned i = 0; i < res.size(); ++i) {
+                       int port = res[i][0].as<int>();
+                       double x = res[i][1].as<double>();
+                       unsigned long long y1 = res[i][2].as<long long>(), y2 = res[i][3].as<long long>();
+
+                       if (port != last_port) {
+                               if (last_port != -1) {
+                                       total_flow = sum_flows(total_flow, flow);
+                                       fprintf(stderr, "%u (%u)\n", last_port, ++num_total);
+                               }
+
+                               // reset
+                               last_port = port;
+                               fp.reset(x, y1, y2);
+                               continue;
+                       }
+
+                       fp.push(x, y1, y2);
+               }
+       }
+       total_flow = sum_flows(total_flow, flow);
+
+       unsigned long long min_y = 0;
+       unsigned long long max_y = 10000000;
+
+       for (unsigned i = 0; i < total_flow.size(); ++i) {
+               flow_element fe = total_flow[i];
+               
+               min_y = std::min(min_y, fe.y1);
+               max_y = std::max(max_y, fe.y1);
+               
+               min_y = std::min(min_y, fe.y2);
+               max_y = std::max(max_y, fe.y2);
+       }
+
+       printf("06 done.\n");
+       
+       num_total = 0;
+       pqxx::work t05(conn05, "fetch_all");
+       pqxx::icursorstream::icursorstream cstream05(t05, "select port,extract(epoch from (time + interval '1 year 20 days')) as time,bytes_in,bytes_out from polls natural join switches where (switchtype='es3024' and port < 25) order by switch,port,time", "fetch_all", 500);
+
+       last_port = -1;
+       
+       for ( ;; ) {
+               pqxx::result res;
+       
+               cstream05 >> res;
+               if (res.empty()) 
+                       break;
+       
+               for (unsigned i = 0; i < res.size(); ++i) {
+                       int port = res[i][0].as<int>();
+                       double x = res[i][1].as<double>();
+                       unsigned long long y1 = res[i][2].as<long long>(), y2 = res[i][3].as<long long>();
+
+                       if (port != last_port) {
+                               if (last_port != -1) {
+                                       total_flow05 = sum_flows(total_flow05, filter_flow(flow));
+                                       fprintf(stderr, "TG05: %u (%u)\n", last_port, ++num_total);
+                               }
+
+                               // reset
+                               last_port = port;
+                               fp.reset(x, y1, y2);
+                               continue;
+                       }
+
+                       fp.push(x, y1, y2);
+               }
+       }
+       total_flow05 = sum_flows(total_flow05, filter_flow(flow));
+
+       for (unsigned i = 0; i < total_flow05.size(); ++i) {
+               flow_element fe = total_flow05[i];
+               
+               min_y = std::min(min_y, fe.y1);
+               max_y = std::max(max_y, fe.y1);
+               
+               min_y = std::min(min_y, fe.y2);
+               max_y = std::max(max_y, fe.y2);
+       }
+       
+       double min_x = std::min(total_flow[0].x, total_flow05[0].x);
+       double max_x = std::max(total_flow[total_flow.size() - 1].x, total_flow05[total_flow05.size() - 1].x);
+       
+       graph *g = mygraph_new(width, height);
+       g = mygraph_make_graph(g, min_x, max_x, min_y, max_y, 5);
+
+       // PLOT FIRST
+       int *x = new int[total_flow.size()];
+       unsigned long long *y1 = new unsigned long long[total_flow.size()];
+       unsigned long long *y2 = new unsigned long long[total_flow.size()];
+
+       // de-interleave
+       for (unsigned i = 0; i < total_flow.size(); ++i) {
+               x[i] = total_flow[i].x;
+               y1[i] = total_flow[i].y1;
+               y2[i] = total_flow[i].y2;
+       }
+
+       mygraph_plot_series(g, x, y1, total_flow.size(), 1.0f, 0.0f, 0.0f);
+       mygraph_plot_series(g, x, y2, total_flow.size(), 0.0f, 0.0f, 1.0f);
+
+       delete[] x;
+       delete[] y1;
+       delete[] y2;
+       
+       // PLOT SECOND
+       x = new int[total_flow05.size()];
+       y1 = new unsigned long long[total_flow05.size()];
+       y2 = new unsigned long long[total_flow05.size()];
+
+       // de-interleave
+       for (unsigned i = 0; i < total_flow05.size(); ++i) {
+               x[i] = total_flow05[i].x;
+               y1[i] = total_flow05[i].y1;
+               y2[i] = total_flow05[i].y2;
+       }
+
+       mygraph_plot_series(g, x, y1, total_flow05.size(), 0.0f, 1.0f, 0.0f);
+       mygraph_plot_series(g, x, y2, total_flow05.size(), 1.0f, 0.0f, 1.0f);
+
+       delete[] x;
+       delete[] y1;
+       delete[] y2;
+       
+       mygraph_to_file(g, "comparative.png");
+       mygraph_cleanup(g);
+}
diff --git a/web/ext/flowpusher.cpp b/web/ext/flowpusher.cpp
new file mode 100644 (file)
index 0000000..7bcbf6a
--- /dev/null
@@ -0,0 +1,87 @@
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <malloc.h>
+#include <vector>
+#include "flowpusher.h"
+
+FlowPusher::FlowPusher(std::vector<flow_element> &flow) : flow(flow)
+{
+}
+
+void FlowPusher::find_diff(double x, double &prev_x, unsigned long long y1, unsigned long long prev_y1, unsigned long long y2, unsigned long long prev_y2,
+       unsigned long long &yf1, unsigned long long &yf2)
+{
+       // Heuristics: if last reading was more than ten minutes away, and both
+       //             readings went down from last reading, we assume the counters
+       //             were zeroed. If not, we assume wraparound.
+       bool over_10mins = (x - prev_x >= 600);
+       bool y1_wrapped = ((prev_y1 == 0 && y1 == 0) || y1 < prev_y1);
+       bool y2_wrapped = ((prev_y2 == 0 && y2 == 0) || y2 < prev_y2);
+       bool both_zero = (y1 == 0 && y2 == 0);  
+       bool any_wide = (prev_y1 > 4294967296ULL || prev_y2 > 4294967296ULL);
+       
+       if ((over_10mins && (y1_wrapped || y2_wrapped)) || both_zero || (any_wide && (y1_wrapped || y2_wrapped))) {
+               prev_y1 = 0;
+               prev_y2 = 0;
+
+               // our best estimate for when it was zeroed :-)
+               prev_x = (prev_x + x) / 2;
+       }
+
+       if (y1 < prev_y1) {
+               yf1 = (unsigned long long)(((unsigned long long)y1 + 4294967296ULL) - prev_y1);
+       } else {
+               yf1 = (unsigned long long)(y1 - prev_y1);
+       }
+       
+       if (y2 < prev_y2) {
+               yf2 = (unsigned long long)(((unsigned long long)y2 + 4294967296ULL) - prev_y2) / (x - prev_x);
+       } else {
+               yf2 = (unsigned long long)(y2 - prev_y2);
+       }
+}
+
+void FlowPusher::push(double x, unsigned long long y1, unsigned long long y2)
+{
+       unsigned long long yf1, yf2;
+
+       find_diff(x, prev_x, y1, prev_y1, y2, prev_y2, yf1, yf2);
+       yf1 /= (x - prev_x);
+       yf2 /= (x - prev_x);
+               
+       flow_element fe;
+       fe.x = unsigned((prev_x + x)*0.5);
+       fe.y1 = yf1;
+       fe.y2 = yf2;
+
+       min_x = std::min(min_x, fe.x);
+       max_x = std::max(max_x, fe.x);
+       
+       min_y = std::min(min_y, fe.y1);
+       max_y = std::max(max_y, fe.y1);
+       
+       min_y = std::min(min_y, fe.y2);
+       max_y = std::max(max_y, fe.y2);
+
+       flow.push_back(fe);
+
+       prev_x = x;
+       prev_y1 = y1;
+       prev_y2 = y2;
+}
+
+void FlowPusher::reset(double x, unsigned long long y1, unsigned long long y2)
+{
+       flow.resize(0);
+       
+       min_y = 0;
+       max_y = 10000000;
+       
+       max_x = time(NULL);
+       min_x = max_x - 86400;
+       
+       prev_x = x;
+       prev_y1 = y1;
+       prev_y2 = y2;
+}
diff --git a/web/ext/flowpusher.h b/web/ext/flowpusher.h
new file mode 100644 (file)
index 0000000..a16f7b1
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef _FLOWPUSHER_H
+#define _FLOWPUSHER_H 1
+
+struct flow_element {
+       unsigned x;
+       unsigned long long y1, y2;
+};
+
+class FlowPusher
+{
+private:
+       std::vector<flow_element> &flow;
+       unsigned min_x, max_x;
+       long long unsigned min_y, max_y;
+       double prev_x;
+       unsigned long long prev_y1, prev_y2;
+       
+public:
+       FlowPusher(std::vector<flow_element> &flow);
+       void reset(double x, unsigned long long y1, unsigned long long y2);
+       void push(double x, unsigned long long y1, unsigned long long y2);
+       static void find_diff(double x, double &prev_x, unsigned long long y1, unsigned long long prev_y1, unsigned long long y2, unsigned long long prev_y2,
+               unsigned long long &yf1, unsigned long long &yf2);
+       
+       unsigned get_min_x() { return min_x; }
+       unsigned get_max_x() { return max_x; }
+       unsigned get_min_y() { return min_y; }
+       unsigned get_max_y() { return max_y; }
+};
+
+#endif /* !defined(_FLOWPUSHER_H) */
diff --git a/web/ext/flowutil.cpp b/web/ext/flowutil.cpp
new file mode 100644 (file)
index 0000000..9df12dc
--- /dev/null
@@ -0,0 +1,128 @@
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <malloc.h>
+#include <vector>
+#include <algorithm>
+#include "graph.h"
+#include "flowutil.h"
+
+std::vector<flow_element> sum_flows(const std::vector<flow_element> &a, const std::vector<flow_element> &b)
+{
+       std::vector<flow_element> ret;
+       std::vector<flow_element>::const_iterator ia = a.begin(), ib = b.begin();
+
+       double last_xa = 0.0, last_y1a = 0.0, last_y2a = 0.0;
+       double last_xb = 0.0, last_y1b = 0.0, last_y2b = 0.0;
+       
+       while (ia != a.end() && ib != b.end()) {
+               if (ia->x == ib->x) {
+                       flow_element fea = *ia, feb = *ib, fe;
+                       
+                       last_xa = fea.x;
+                       last_y1a = fea.y1;
+                       last_y2a = fea.y2;
+                       
+                       last_xb = feb.x;
+                       last_y1b = feb.y1;
+                       last_y2b = feb.y2;
+               
+                       fe.x = fea.x;
+                       fe.y1 = fea.y1 + feb.y1;
+                       fe.y2 = fea.y2 + feb.y2;
+
+                       ret.push_back(fe);
+
+                       ++ia, ++ib;
+               } else if (ia->x < ib->x) {
+                       flow_element fe = *ia;
+                       
+                       last_xa = fe.x;
+                       last_y1a = fe.y1;
+                       last_y2a = fe.y2;
+                       
+                       double t = (fe.x - last_xb) / (ib->x - last_xb);
+                       fe.y1 += last_y1b + t * (ib->y1 - last_y1b);
+                       fe.y2 += last_y2b + t * (ib->y2 - last_y2b);
+
+                       ret.push_back(fe);
+
+                       ++ia;
+               } else {
+                       flow_element fe = *ib;
+                       
+                       last_xb = fe.x;
+                       last_y1b = fe.y1;
+                       last_y2b = fe.y2;
+                       
+                       double t = (fe.x - last_xa) / (ia->x - last_xa);
+                       fe.y1 += last_y1a + t * (ia->y1 - last_y1a);
+                       fe.y2 += last_y2a + t * (ia->y2 - last_y2a);
+
+                       ret.push_back(fe);
+                       ++ib;
+               }
+       }
+
+       while (ia != a.end()) {
+               ret.push_back(*ia);
+               ++ia;
+       }
+       while (ib != b.end()) {
+               ret.push_back(*ib);
+               ++ib;
+       }
+
+       return ret;
+}
+
+std::vector<flow_element> filter_flow(const std::vector<flow_element> &flow)
+{
+       unsigned long long last_y1 = 0, last_y2 = 0;
+       std::vector<flow_element> ret;
+       
+       for (std::vector<flow_element>::const_iterator i = flow.begin(); i != flow.end(); ++i) {
+/*             if ((i->y1 > 100000 && last_y1 < 10000 && i->y2 > 100000 && last_y2 < 1000) ||
+                   (last_y1 > 10000 && last_y2 > 10000 && i->y1 / last_y1 > 10 && i->y2 / last_y2 > 10)) {
+                       printf("yoyo: %llu %llu (%llu %llu)\n", i->y1, i->y2, last_y1, last_y2);
+               } else {
+                       ret.push_back(*i);
+                       last_y1 = i->y1;
+                       last_y2 = i->y2;
+               } */
+               if (!(i->x >= 1145056800 && i->x <= 1145070800)) {
+                       ret.push_back(*i);
+               }
+       }
+
+       return ret;
+}
+
+void make_graph(int port, unsigned width, unsigned height, unsigned min_x, unsigned max_x, unsigned long long min_y, unsigned long long max_y, std::vector<flow_element> &flow)
+{
+       char filename[256];
+       graph *g = mygraph_new(width, height);
+       g = mygraph_make_graph(g, min_x, max_x, min_y, max_y, 5);
+
+       int *x = new int[flow.size()];
+       unsigned long long *y1 = new unsigned long long[flow.size()];
+       unsigned long long *y2 = new unsigned long long[flow.size()];
+
+       // de-interleave
+       for (unsigned i = 0; i < flow.size(); ++i) {
+               x[i] = flow[i].x;
+               y1[i] = flow[i].y1;
+               y2[i] = flow[i].y2;
+       }
+
+       mygraph_plot_series(g, x, y1, flow.size(), 1.0f, 0.0f, 0.0f);
+       mygraph_plot_series(g, x, y2, flow.size(), 0.0f, 0.0f, 1.0f);
+       sprintf(filename, "port-%u-500-250.png", port);
+       mygraph_to_file(g, filename);
+       mygraph_cleanup(g);
+
+       delete[] x;
+       delete[] y1;
+       delete[] y2;
+}
+
diff --git a/web/ext/flowutil.h b/web/ext/flowutil.h
new file mode 100644 (file)
index 0000000..235ebc9
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef _FLOWUTIL_H
+#define _FLOWUTIL_H 1
+
+#include <vector>
+#include "flowpusher.h"
+
+std::vector<flow_element> sum_flows(const std::vector<flow_element> &a, const std::vector<flow_element> &b);
+std::vector<flow_element> filter_flow(const std::vector<flow_element> &flow);
+void make_graph(int port, unsigned width, unsigned height, unsigned min_x, unsigned max_x, unsigned long long min_y, unsigned long long max_y, std::vector<flow_element> &flow);
+
+#endif /* !defined(_FLOWUTIL_H) */
diff --git a/web/ext/graph.cpp b/web/ext/graph.cpp
new file mode 100755 (executable)
index 0000000..a516b31
--- /dev/null
@@ -0,0 +1,240 @@
+#include "graph.h"
+
+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;
+  mygraph = (graph *)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, double min_x, double max_x,
+                   double min_y, double 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; */
+
+  double xs = ((double)mygraph->width - (double)(xoffset+2)) /
+             (double)(max_x - min_x);
+
+  double ys = ((double)mygraph->height - 33.) / (double)(min_y - max_y);
+
+  mygraph->xs = xs;
+  mygraph->ys = ys;
+
+  double starthour = fmod((min_x + (double)tz_local_offset()) / 3600., 24.);
+  double diff, center, begin, end;
+
+  char string[20];
+  int i;
+  for (i = 0; i<240; 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 = (double)i - starthour;
+      begin = (diff * 3600.) * xs;
+      end = ((double)(i+1) - starthour) * 3600.0 * xs;
+      center = (begin + end) / 2.;
+
+      if (begin < 0.0)
+       continue;
+      if (begin > ((double)mygraph->width - ((double)xoffset)))
+       continue;
+
+      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 % 24);
+//           printf("showing string %s @ %fx%f\n", string, xoffset + center - (extents.width/2), (mygraph->height - extents.height - 2));
+
+      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);
+   long long ytick;
+  do
+    {
+      ytick = ((long long)max_y - (long long)min_y) / 11;
+      ytick = (long long)(ceil (ytick / tickgran) * tickgran);
+      tickgran /= 10;
+    } while (((long long)max_y - (long long)min_y) / ytick < 4);
+
+  int y;
+  unsigned long long traf;
+  for (i = -11; i<12; i++)
+    {
+      y = (int)((i * ytick - (long long)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 * ((unsigned long long)i * ytick);
+/*       printf("traffic: %d\n", traf); */
+
+      if (traf >= 500000000)
+       sprintf (string, "%.1f Gbit", ((double)traf/1000000000));
+      else if (traf >= 500000)
+       sprintf (string, "%.1f Mbit", ((double)traf/1000000));
+      else
+       sprintf (string, "%.1f kbit", ((double)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, unsigned long long *yvals, int n_vals,
+                    double r, double g, double b)
+{
+  int x, i;
+  unsigned long long y;
+  x = xvals[0];
+  y = yvals[0];
+
+  cairo_set_antialias(mygraph->cr, CAIRO_ANTIALIAS_DEFAULT);
+  cairo_set_source_rgb (mygraph->cr, r, g, b);
+
+  int xp = (int)((x - mygraph->min_x) * mygraph->xs + mygraph->xoffset + 1);
+  int yp = (int)((y - mygraph->max_y) * mygraph->ys + 10);
+  
+  cairo_move_to (mygraph->cr, xp, yp);
+
+/*   printf("Plotting from:\n");
+   printf("(%d, %d) %d (%d, %d)<br/>\n",
+        x, y, (int)((double)(x - (int)mygraph->min_x) * mygraph->xs + (double)(mygraph->xoffset + 1)) ,
+        (int)((double)(x - (int)mygraph->min_x) * mygraph->xs + (double)(mygraph->xoffset + 1)),
+        (int)((double)(y - (int)mygraph->max_y) * mygraph->ys + 10.)); */
+
+  int last_xp = xp, last_yp = yp;
+  
+  for (i = 1; i < n_vals; i++)
+    {
+      x = xvals[i];
+      y = yvals[i];
+      
+      int xp = (int)((x - mygraph->min_x) * mygraph->xs + mygraph->xoffset + 1);
+      int yp = (int)((y - mygraph->max_y) * mygraph->ys + 10);
+      
+      if (abs(xp - last_xp) < 2 && yp > last_yp)
+       continue;
+      
+      cairo_line_to (mygraph->cr, xp, yp);
+      last_xp = xp;
+      last_yp = yp;
+    }
+
+  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/graphall.cpp b/web/ext/graphall.cpp
new file mode 100644 (file)
index 0000000..a21fc45
--- /dev/null
@@ -0,0 +1,75 @@
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <malloc.h>
+#include <vector>
+#include <algorithm>
+#include "graph.h"
+#include "flowpusher.h"
+#include "flowutil.h"
+
+int main(int argc, char **argv)
+{
+       bool total_only = false;
+       int width = 500, height = 250;
+       
+       std::vector<flow_element> flow, total_flow;
+       FlowPusher fp(flow);
+       int last_port = -1;
+       
+       mallopt(M_TRIM_THRESHOLD, -1);
+       
+       if (argc == 2 && strcmp(argv[1], "--total-only") == 0) {
+               width = 1000;
+               height = 500;
+               total_only = true;
+       }
+
+       int num_total = 0;
+       
+       for ( ;; ) {
+               int port;
+               double x;
+               unsigned long long y1, y2;
+               
+               if (scanf("%d %lf %llu %llu", &port, &x, &y1, &y2) != 4)
+                       break;
+
+               if (port != last_port) {
+                       if (last_port != -1) {
+                               if (!total_only)
+                                       make_graph(last_port, width, height, fp.get_min_x(), fp.get_max_x(), fp.get_min_y(), fp.get_max_y(), flow);
+                               total_flow = sum_flows(total_flow, flow);
+                               fprintf(stderr, "%u (%u)\n", last_port, ++num_total);
+                       }
+
+                       // reset
+                       last_port = port;
+                       fp.reset(x, y1, y2);
+                       continue;
+               }
+
+               fp.push(x, y1, y2);
+       }
+
+       // last graph
+       if (!total_only)
+               make_graph(last_port, width, height, fp.get_min_x(), fp.get_max_x(), fp.get_min_y(), fp.get_max_y(), flow);
+       total_flow = sum_flows(total_flow, flow);
+       
+       // total graph
+       unsigned long long min_y = 0;
+       unsigned long long max_y = 10000000;
+
+       for (unsigned i = 0; i < total_flow.size(); ++i) {
+               flow_element fe = total_flow[i];
+               
+               min_y = std::min(min_y, fe.y1);
+               max_y = std::max(max_y, fe.y1);
+               
+               min_y = std::min(min_y, fe.y2);
+               max_y = std::max(max_y, fe.y2);
+       }
+       
+       make_graph(65535, width, height, total_flow[0].x, total_flow[total_flow.size() - 1].x, min_y, max_y, total_flow);
+}
diff --git a/web/ext/totalcount.cpp b/web/ext/totalcount.cpp
new file mode 100644 (file)
index 0000000..bb4b1c0
--- /dev/null
@@ -0,0 +1,74 @@
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <malloc.h>
+#include <vector>
+#include <algorithm>
+#include <pqxx/pqxx>
+#include "graph.h"
+#include "flowpusher.h"
+#include "flowutil.h"
+
+namespace pqxx {
+       template<>
+       void from_string<long long>(const char *from, long long &to)
+       {
+               to = atoll(from);
+       }
+}
+                                               
+int main(int argc, char **argv)
+{
+       int width = 1000, height = 500;
+       unsigned long long traffic = 0ULL;
+       pqxx::connection conn("dbname=nms host=localhost user=nms password=seesahS4");
+
+       std::vector<flow_element> flow;
+       int last_port = -1;
+       
+       mallopt(M_TRIM_THRESHOLD, -1);
+       
+       int num_total = 0;
+       pqxx::work t(conn, "fetch_all");
+//     pqxx::icursorstream::icursorstream cstream(t, "select port,extract(epoch from time) as time,bytes_in,bytes_out from polls natural join switches where ((switchtype='es3024' and port < 25) or (switchtype='summit400' and port > 1)) order by switch,port,time", "fetch_all", 500);
+       pqxx::icursorstream::icursorstream cstream(t, "select port,extract(epoch from time) as time,bytes_in,bytes_out from polls natural join switches where switch=1447 order by switch,port,time", "fetch_all", 500);
+       
+       double prev_x;
+       unsigned long long prev_y1, prev_y2;
+       
+       for ( ;; ) {
+               pqxx::result res;
+               
+               cstream >> res;
+               if (res.empty()) 
+                       break;
+
+               for (unsigned i = 0; i < res.size(); ++i) {
+                       int port = res[i][0].as<int>();
+                       double x = res[i][1].as<double>();
+                       unsigned long long y1 = res[i][2].as<long long>(), y2 = res[i][3].as<long long>();
+
+                       if (port != last_port) {
+                               if (last_port != -1) {
+                                       fprintf(stderr, "%.2f TB (%u)\n", traffic / double(1024.0 * 1024.0 * 1024.0 * 1024.0), ++num_total);
+                               }
+
+                               // reset
+                               last_port = port;
+                               prev_x = x;
+                               prev_y1 = y1;
+                               prev_y2 = y2;
+                               continue;
+                       }
+
+                       unsigned long long yf1, yf2;
+                       FlowPusher::find_diff(x, prev_x, y1, prev_y1, y2, prev_y2, yf1, yf2);
+                       traffic += 0.5 * (yf1 + yf2);
+                       
+                       prev_x = x;
+                       prev_y1 = y1;
+                       prev_y2 = y2;
+               }
+       }
+       fprintf(stderr, "%.2f TB\n", traffic / double(1024.0 * 1024.0 * 1024.0 * 1024.0));
+}
diff --git a/web/ext/totalgraph.cpp b/web/ext/totalgraph.cpp
new file mode 100644 (file)
index 0000000..f1301d2
--- /dev/null
@@ -0,0 +1,77 @@
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <malloc.h>
+#include <vector>
+#include <algorithm>
+#include <pqxx/pqxx>
+#include "flowpusher.h"
+#include "flowutil.h"
+
+namespace pqxx {
+       template<>
+       void from_string<long long>(const char *from, long long &to)
+       {
+               to = atoll(from);
+       }
+}
+                                               
+
+int main(int argc, char **argv)
+{
+       int width = 1000, height = 500;
+       pqxx::connection conn("dbname=nms host=localhost user=nms password=seesahS4");
+
+       std::vector<flow_element> flow, total_flow;
+       FlowPusher fp(flow);
+       int last_port = -1;
+       
+       mallopt(M_TRIM_THRESHOLD, -1);
+       
+       int num_total = 0;
+       pqxx::work t(conn, "fetch_all");
+       pqxx::icursorstream::icursorstream cstream(t, "select port,extract(epoch from time) as time,bytes_in,bytes_out from polls natural join switches where (switchtype='es3024' and port < 25) or (switchtype='summit400' and port > 1) order by switch,port,time", "fetch_all", 500);
+       
+       for ( ;; ) {
+               pqxx::result res;
+               
+               cstream >> res;
+               if (res.empty()) 
+                       break;
+
+               for (unsigned i = 0; i < res.size(); ++i) {
+                       int port = res[i][0].as<int>();
+                       double x = res[i][1].as<double>();
+                       unsigned long long y1 = res[i][2].as<long long>(), y2 = res[i][3].as<long long>();
+
+                       if (port != last_port) {
+                               if (last_port != -1) {
+                                       total_flow = sum_flows(total_flow, flow);
+                                       fprintf(stderr, "%u (%u)\n", last_port, ++num_total);
+                               }
+
+                               // reset
+                               last_port = port;
+                               fp.reset(x, y1, y2);
+                               continue;
+                       }
+
+                       fp.push(x, y1, y2);
+               }
+       }
+
+       unsigned long long min_y = 0;
+       unsigned long long max_y = 10000000;
+
+       for (unsigned i = 0; i < total_flow.size(); ++i) {
+               flow_element fe = total_flow[i];
+               
+               min_y = std::min(min_y, fe.y1);
+               max_y = std::max(max_y, fe.y1);
+               
+               min_y = std::min(min_y, fe.y2);
+               max_y = std::max(max_y, fe.y2);
+       }
+       
+       make_graph(65535, width, height, total_flow[0].x, total_flow[total_flow.size() - 1].x, min_y, max_y, total_flow);
+}