/****************************************************************/
/* */
/* distrib.c (see readme.html for program explanation) */
/* */
/* author : Philippe Simonet, Philippe.Simonet@swiisstelecom.com*/
/* */
/* change log : */
/* */
/* v. 1.00 : initial update (SIP) (23.06.97) */
/* */
/* */
/* */
/************************************************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <malloc.h>
#include <time.h>
#include "gd.h"
#include "gdfonts.h"
#define FALSE 0
#define TRUE 1
#define TEXT 1
#define RECT 2
#define POLY 3
#define COLOR 4
#define COLORDEF 5
#define LINK 6
#define COMPOUND 7
#define ENDCOMPOUND 8
#define GIFAREA 9
#define URL 10
#define IN 11
#define OUT 12
#define INOUT 13
#define UNKNOWN 99
#ifndef max
#define max(a,b) ((a)>(b))?(a):(b)
#endif
#ifndef min
#define min(a,b) ((a)<(b))?(a):(b)
#endif
int distcount;
int xsize, ysize, rounds, rate;
int dist[1000][2];
/************************************************************************/
/* analyze command-line options */
static int optind = 0; /* Global argv index. */
static char *scan = NULL; /* Private scan pointer. */
static int scale = 15;
int getopt1( int argc, char *argv[], char *optstring, char ** optarg )
{
int c; /* return value */
char *place;
char *index();
*optarg = NULL;
/* check argument validity */
if (scan == NULL || *scan == '\0') {
if (optind == 0) optind++;
if (optind >= argc) return EOF;
place = argv[optind];
if (place[0] != '-' || place[1] == '\0') return EOF;
optind++;
if (place[1] == '-' && place[2] == '\0') return EOF;
scan = place+1;
}
c = *scan++; /* get option character */
place = strchr(optstring, c);
if (place == NULL || c == ':') return '?';
/* set optarg if needed */
if (*++place == ':') {
if (*scan != '\0') {
*optarg = scan; scan = NULL;
} else {
*optarg = argv[optind], optind++;
}
}
return c;
}
/************************************************************************/
void computes_distrib ( FILE * fi, int length, int nb, unsigned int maxbytes ) {
int i,j;
unsigned long time, in, out, maxin, maxout;
for ( i = 0; i < length; i ++ ) {
in = 0; out = 0;
/* compute mean on 'nb' items */
for (j = 0; j < nb; j ++ ) {
unsigned long wi, wo;
if (fscanf(fi,"%lu %lu %lu %lu %lu\n",&time,&wi,&wo,&maxin, &maxout) != 5) {
printf ( "config file error !!!\n" );
} else {
in += wi; out += wo;
}
}
in /= nb; out /= nb;
if ( in >= maxbytes ) in = maxbytes-1;
if ( out >= maxbytes ) out = maxbytes-1;
dist[(( in*distcount)/maxbytes)][0] ++;
dist[((out*distcount)/maxbytes)][1] ++;
}
};
/************************************************************************/
/* in case of trouble ... */
void print_error ( void )
{
fprintf ( stderr, "Read mrtg log files and build distribution graphs.\n" );
fprintf ( stderr, "Version 1.1, 27.06.97.\n" );
fprintf ( stderr, "Use : case 1 : (1 distr. log file)\n" );
fprintf ( stderr, " distrib -i logfile -o gfile -w width -h height -t type -r rate -d count\n" );
fprintf ( stderr, " ifile : input log file name,\n" );
fprintf ( stderr, " gfile : output gif file (will be overwritten),\n" );
fprintf ( stderr, " count : histogram count,\n" );
fprintf ( stderr, " rate : line rate,\n" );
fprintf ( stderr, " type : length of measurement (d/w/m/y).\n" );
fprintf ( stderr, "Use : case 2 : (distr. from distrib. file)\n" );
fprintf ( stderr, " distrib -i distrib -o gfile -w width -h height -t x -r top -d count\n" );
fprintf ( stderr, " ifile : input distribution summary file name,\n" );
fprintf ( stderr, " gfile : output gif file (will be overwritten),\n" );
fprintf ( stderr, " top : how may top n,\n" );
fprintf ( stderr, " count : histogram count,\n" );
fprintf ( stderr, " type : 'x'.\n" );
}
/************************************************************************/
#define r(color) ((color&0x0000ff)>>0)
#define g(color) ((color&0x00ff00)>>8)
#define b(color) ((color&0xff0000)>>16)
#define rgb(color) ((color&0x0000ff)>>0),((color&0x00ff00)>>8),((color&0xff0000)>>16)
/************************************************************************/
/* build a color or find the nearest color in the color table */
int find_color ( gdImagePtr graph, int color ) {
int i_col;
if ( (i_col = gdImageColorExact(graph,r(color), g(color), b(color))) == -1 ) {
if ( (i_col = gdImageColorAllocate(graph,r(color), g(color), b(color))) == -1 ) {
i_col = gdImageColorClosest(graph,r(color), g(color), b(color));
}
}
return (i_col);
}
/************************************************************************/
/* draw the gif file */
void draw_distrib_gif ( FILE * score, FILE * gif )
{
#define c_blank 245,245,245 /* base colors */
#define c_light 194,194,194
#define c_dark 100,100,100
#define c_black 0,0,0
#define c_white 255,255,0
#define c_blue 0,0,255
#define c_red 255,0,0
#define c_green 0,255,0
gdImagePtr graph;
int i_light,i_dark,i_blank, i_black, i_white, i_blue, i_red, i_green;
int color[4000][2];
graph = gdImageCreate(xsize, ysize);
/* the first color allocated will be the background color. */
i_blank = gdImageColorAllocate(graph,c_blank);
i_light = gdImageColorAllocate(graph,c_light);
i_dark = gdImageColorAllocate(graph,c_dark);
gdImageInterlace(graph, 1);
i_black = gdImageColorAllocate(graph,c_black);
i_white = gdImageColorAllocate(graph,c_white);
i_red = gdImageColorAllocate(graph,c_red);
i_green = gdImageColorAllocate(graph,c_green);
i_blue = gdImageColorAllocate(graph,c_blue);
{
int i;
for (i = 0; i <= distcount; i++ ) {
color[distcount - i - 1][0] = gdImageColorAllocate(graph, (255*i)/distcount, 255, (255*i)/distcount);
}
for (i = 0; i <= distcount; i++ ) {
color[distcount - i - 1][1] = gdImageColorAllocate(graph, (255*i)/distcount, (255*i)/distcount, 255);
}
}
/* draw the image border */
gdImageLine(graph,0,0,xsize-1,0,i_light);
gdImageLine(graph,1,1,xsize-2,1,i_light);
gdImageLine(graph,0,0,0,ysize-1,i_light);
gdImageLine(graph,1,1,1,ysize-2,i_light);
gdImageLine(graph,xsize-1,0,xsize-1,ysize-1,i_dark);
gdImageLine(graph,0,ysize-1,xsize-1,ysize-1,i_dark);
gdImageLine(graph,xsize-2,1,xsize-2,ysize-2,i_dark);
gdImageLine(graph,1,ysize-2,xsize-2,ysize-2,i_dark);
{ /* date the graph */
struct tm *newtime;
time_t aclock;
time( &aclock ); /* Get time in seconds */
newtime = localtime( &aclock ); /* Convert time to struct */
/* tm form */
gdImageString(graph, gdFontSmall,gdFontSmall->w,3,asctime( newtime ),i_dark);
};
/*i_col = find_color(graph, colortable[pcurrententry->color]);
gdImageFilledRectangle(graph,
pcurrententry->coords[0],
pcurrententry->coords[1],
pcurrententry->coords[2],
pcurrententry->coords[3],i_col2);
}
gdImageString(graph, gdFontSmall,
pcurrententry->coords[0],
pcurrententry->coords[1],
pcurrententry->str,
i_col );
gdImageStringUp(graph, gdFontSmall,
pcurrententry->coords[0],
pcurrententry->coords[1],
pcurrententry->str,
i_col );
gdImagePtr brush_2pix;
brush_2pix = gdImageCreate(2,2);
gdImageColorAllocate(
brush_2pix,
r(colortable[colorratetable[pcurrententry->rate]]),
g(colortable[colorratetable[pcurrententry->rate]]),
b(colortable[colorratetable[pcurrententry->rate]]) );
gdImageSetBrush(graph, brush_2pix);
i_col = gdBrushed;
gdImageLine(graph, x, y, x2, y2,i_col);
gdImageDestroy(brush_2pix);*/
/* draw axes and graphs */
{
int w = gdFontSmall->w, h = gdFontSmall->h, i, j, k, incrx, incry;
char str[4000];
int nbaxesx = (rate + 1);
int nbaxesy = 6;
int textx = 7;
int texty = 15;
incry = (ysize-(h*2)-(w*texty))/(nbaxesy-1);
incrx = (xsize-(w*(textx+2)))/(nbaxesx-1);
j = 100;
for ( i = h*2; i <= ((h*2) + (incry * (nbaxesy-1))) ; i+= incry ) {
gdImageLine(graph,w*textx,i,w*textx + (incrx*(nbaxesx-1)),i,i_black); /* horizontal */
sprintf ( str, "%3u%%", j ); j-= 100/(nbaxesy-1);
gdImageString(graph, gdFontSmall,w,i-h/2,str,i_black );
}
j = 0;
for ( i = w*7; i <= ((w*7) + (incrx * (nbaxesx-1))) ; i+= incrx ) {
/*gdImageLine(graph,i,h*2,i,h*2 + (incry*(AXESY-1)),i_black);*/ /* vertical */
/*sprintf ( str, "%3u%%", j ); j+= (100/(AXESX-1));
gdImageStringUp(graph, gdFontSmall, i - w/2, ysize - h, str, i_black );*/
}
for ( i = 0; i < rate; i ++ ) {
char *name,*ptr;
int tin=0, tout=0;
int x1, x2, y1, y2, mrgx;
if ( fscanf ( score, "%s", str ) == EOF ) break;
/*printf ( "%s\n", str );*/
name = str;
if ((ptr = strtok( str, ":")) == NULL) continue;
/*printf ( "%s:", name );*/
for ( j = 0; j < distcount; j++ ) {
dist[j][0] = dist[j][0] = 0;
if ((ptr = strtok( NULL, "/,")) == NULL) continue;
dist[j][0] = atoi(ptr); tin += dist[j][0];
if ((ptr = strtok( NULL, "/,")) == NULL) continue;
dist[j][1] = atoi(ptr); tout += dist[j][1];
/*printf ( "%u/%u,",dist[j][0],dist[j][1] );*/
}
/*printf ( "\n" );*/
/* draw label and graphs */
mrgx = incrx/5;
x1 = (w*textx) + (i*incrx) + (incrx/2) - (h/2);
y1 = ysize-h;
gdImageStringUp( graph, gdFontSmall, x1, y1, str, i_black );
for (k = 0; k < 2; k ++ ) {
y1 = ysize-((texty-4) * w);
if ( k == 0 ) {
x1 = (w*textx) + (i*incrx) + mrgx;
x2 = x1 + (incrx/3);
gdImageStringUp( graph, gdFontSmall, x1, y1, "in", i_black );
} else {
x2 = (w*textx) + ((i+1)*incrx) - mrgx;
x1 = x2 - (incrx/3);
gdImageStringUp( graph, gdFontSmall, x1, y1, "out", i_black );
}
y2 = h*2 + (incry*(nbaxesy-1));
for ( j = distcount-1; j >=0 ; j-- ) {
y1 = y2 - (((ysize-(h*2)-(w*texty) - 2) * dist[j][k]) / tin);
if (j == 0) { /* 'correct' cumulative error */
y1 = h*2;
}
gdImageFilledRectangle(graph, x1, y1, x2, y2,color[j][k]);
gdImageRectangle(graph, x1, y1, x2, y2,i_black);
y2 = y1;
}
}
/*
int x1, x2, y1, y2, mrgx;
mrgx = incrx/5;
x1 = (w*7) + (i*incrx) + mrgx;
x2 = x1 + (incrx/3);
y2 = h*2 + (incry*(AXESY-1)) - 2;
y1 = y2 - (((ysize-(h*2)-(w*7) - 2) * dist[i][0]) / rounds);
gdImageFilledRectangle(graph, x1, y1, x2, y2,i_green);
gdImageRectangle(graph, x1, y1, x2, y2,i_dark);
x2 = (w*7) + ((i+1)*incrx) - mrgx;
x1 = x2 - (incrx/3);
y2 = h*2 + (incry*(AXESY-1)) - 2;
y1 = y2 - (((ysize-(h*2)-(w*7) - 2) * dist[i][1]) / rounds);
gdImageFilledRectangle(graph, x1, y1, x2, y2,i_blue);
gdImageRectangle(graph, x1, y1, x2, y2,i_dark);
*/
}
}
gdImageGif(graph, gif);
gdImageDestroy(graph);
}
/************************************************************************/
/* draw the gif file, based on the tentry desciption */
void draw_gif ( FILE * gif )
{
#define c_blank 245,245,245 /* base colors */
#define c_light 194,194,194
#define c_dark 100,100,100
#define c_black 0,0,0
#define c_white 255,255,0
#define c_blue 0,0,255
#define c_red 255,0,0
#define c_green 0,255,0
gdImagePtr graph;
int i_light,i_dark,i_blank, i_black, i_white, i_blue, i_red, i_green;
graph = gdImageCreate(xsize, ysize);
/* the first color allocated will be the background color. */
i_blank = gdImageColorAllocate(graph,c_blank);
i_light = gdImageColorAllocate(graph,c_light);
i_dark = gdImageColorAllocate(graph,c_dark);
gdImageInterlace(graph, 1);
i_black = gdImageColorAllocate(graph,c_black);
i_white = gdImageColorAllocate(graph,c_white);
i_red = gdImageColorAllocate(graph,c_red);
i_green = gdImageColorAllocate(graph,c_green);
i_blue = gdImageColorAllocate(graph,c_blue);
/* draw the image border */
gdImageLine(graph,0,0,xsize-1,0,i_light);
gdImageLine(graph,1,1,xsize-2,1,i_light);
gdImageLine(graph,0,0,0,ysize-1,i_light);
gdImageLine(graph,1,1,1,ysize-2,i_light);
gdImageLine(graph,xsize-1,0,xsize-1,ysize-1,i_dark);
gdImageLine(graph,0,ysize-1,xsize-1,ysize-1,i_dark);
gdImageLine(graph,xsize-2,1,xsize-2,ysize-2,i_dark);
gdImageLine(graph,1,ysize-2,xsize-2,ysize-2,i_dark);
{ /* date the graph */
struct tm *newtime;
time_t aclock;
time( &aclock ); /* Get time in seconds */
newtime = localtime( &aclock ); /* Convert time to struct */
/* tm form */
gdImageString(graph, gdFontSmall,gdFontSmall->w,3,asctime( newtime ),i_dark);
};
/*i_col = find_color(graph, colortable[pcurrententry->color]);
gdImageFilledRectangle(graph,
pcurrententry->coords[0],
pcurrententry->coords[1],
pcurrententry->coords[2],
pcurrententry->coords[3],i_col2);
}
gdImageString(graph, gdFontSmall,
pcurrententry->coords[0],
pcurrententry->coords[1],
pcurrententry->str,
i_col );
gdImageStringUp(graph, gdFontSmall,
pcurrententry->coords[0],
pcurrententry->coords[1],
pcurrententry->str,
i_col );
gdImagePtr brush_2pix;
brush_2pix = gdImageCreate(2,2);
gdImageColorAllocate(
brush_2pix,
r(colortable[colorratetable[pcurrententry->rate]]),
g(colortable[colorratetable[pcurrententry->rate]]),
b(colortable[colorratetable[pcurrententry->rate]]) );
gdImageSetBrush(graph, brush_2pix);
i_col = gdBrushed;
gdImageLine(graph, x, y, x2, y2,i_col);
gdImageDestroy(brush_2pix);*/
/* draw axes and graphs */
{
int w = gdFontSmall->w, h = gdFontSmall->h, i, j, incrx, incry, maxio;
char str[20];
#define AXESX (distcount + 1)
#define AXESY 6
maxio = 0;
for ( i = 0; i < distcount; i ++ ) {
if (maxio < dist[i][0]) maxio = dist[i][0];
if (maxio < dist[i][1]) maxio = dist[i][1];
}
incry = (ysize-(h*2)-(w*7))/(AXESY-1); incrx = (xsize-(w*9))/(AXESX-1);
j = 100;
for ( i = h*2; i <= ((h*2) + (incry * (AXESY-1))) ; i+= incry ) {
gdImageLine(graph,w*7,i,w*7 + (incrx*(AXESX-1)),i,i_black); /* horizontal */
sprintf ( str, "%3u%%", j ); j-= 100/(AXESY-1);
gdImageString(graph, gdFontSmall,w,i-h/2,str,i_black );
}
j = 0;
for ( i = w*7; i <= ((w*7) + (incrx * (AXESX-1))) ; i+= incrx ) {
gdImageLine(graph,i,h*2,i,h*2 + (incry*(AXESY-1)),i_black); /* vertical */
sprintf ( str, "%3u%%", j ); j+= (100/(AXESX-1));
gdImageStringUp(graph, gdFontSmall, i - w/2, ysize - h, str, i_black );
}
for ( i = 0; i < distcount; i ++ ) {
int x1, x2, y1, y2, mrgx;
mrgx = incrx/5;
x1 = (w*7) + (i*incrx) + mrgx;
x2 = x1 + (incrx/3);
y2 = h*2 + (incry*(AXESY-1)) - 2;
y1 = y2 - (((ysize-(h*2)-(w*7) - 2) * dist[i][0]) / rounds);
/* printf ( "x1 %u, y1 %u, x2 %u, y2 %u.\n", x1, y1, x2, y2 );*/
gdImageFilledRectangle(graph, x1, y1, x2, y2,i_green);
gdImageRectangle(graph, x1, y1, x2, y2,i_dark);
x2 = (w*7) + ((i+1)*incrx) - mrgx;
x1 = x2 - (incrx/3);
y2 = h*2 + (incry*(AXESY-1)) - 2;
y1 = y2 - (((ysize-(h*2)-(w*7) - 2) * dist[i][1]) / rounds);
/* printf ( "x1 %u, y1 %u, x2 %u, y2 %u.\n", x1, y1, x2, y2 );*/
gdImageFilledRectangle(graph, x1, y1, x2, y2,i_blue);
gdImageRectangle(graph, x1, y1, x2, y2,i_dark);
}
}
gdImageGif(graph, gif);
gdImageDestroy(graph);
}
/************************************************************************/
void main ( int argc, char * argv[] )
{
FILE *config = NULL, *gif = NULL;
char *sconfig = NULL, *sgif = NULL;
char *optarg;
char type;
int i;
/* globals */
xsize = 400, ysize = 150; type = 'd'; rate = 1250000; distcount = 10;
do {
/***************************************************************/
/* 0 : read program arguments */
while ( ( i = getopt1( argc, argv, "o:i:t:w:h:r:d:", &optarg ) ) != EOF ) {
switch ( i ) {
case 'i':
sconfig = optarg;
break;
case 'o':
sgif = optarg;
break;
case 'w':
if ( optarg != NULL ) {
xsize = atoi (optarg);
}
break;
case 'r':
if ( optarg != NULL ) {
rate = atoi (optarg);
}
break;
case 'd':
if ( optarg != NULL ) {
distcount = atoi (optarg);
}
break;
case 'h':
if ( optarg != NULL ) {
ysize = atoi (optarg);
}
break;
case 't':
if ( optarg != NULL ) type = optarg[0];
if (type != 'd' && type != 'm' && type != 'w' && type != 'y' && type != 'x' ) {
print_error();
exit (0);
}
break;
case '?':
print_error();
exit (0);
break;
default:
break;
}
}
if ( sgif == NULL || sconfig == NULL ) {
print_error();
break;
}
/***************************************************************/
/* 1 : OPEN FILES */
gif = fopen ( sgif, "wb" );
if ( gif == NULL ) {
fprintf ( stderr, "Error opening %s.\n", sgif );
fclose ( config );
break;
}
config = fopen ( sconfig, "r" );
if ( config == NULL ) {
fprintf ( stderr, "Error opening %s.\n", sconfig );
break;
}
if ( type != 'x' ) {
/***************************************************************/
for ( i = 0; i < distcount; i ++ ) {
dist[i][0] = 0; dist[i][1] = 0;
}
{ /* read first line ... */
unsigned long time, in, out;
fscanf ( config, "%lu %lu %lu\n", &time, &in, &out ); /* read first line */
}
switch ( type ) {
case 'd':
computes_distrib ( config, 288, 1, rate );
rounds = 288; /* 288 * 5' = 24 hours */
break;
case 'w':
computes_distrib ( config, 100, 6, rate ); /* 600 * 5', with mean on 6 (30')*/
computes_distrib ( config, 236, 1, rate );
rounds = 336; /* 336 * 30' = 7 days */
break;
case 'm':
computes_distrib ( config, 25, 24, rate ); /* 600 * 5', with mean on 24 (2hours) */
computes_distrib ( config, 150, 4, rate ); /* 600 *30', with mean on 4 */
computes_distrib ( config, 185, 1, rate );
rounds = 360; /* 260 * 2 hours = 30 days */
break;
case 'y':
computes_distrib ( config, 2,300, rate ); /* 600 * 5', with mean on 300 ~= 1 day */
computes_distrib ( config, 12, 50, rate ); /* 600 *30', with mean on 50 ~= 1 day */
computes_distrib ( config, 50, 12, rate ); /* 600 * 2h, with mean on 12 */
computes_distrib ( config, 300, 1, rate );
rounds = 364;
break;
}
for ( i = 0; i < distcount; i ++ ) {
printf ( "%u:%u,%u.\n", i, dist[i][0],dist[i][1] );
}
/***************************************************************/
draw_gif ( gif );
/***************************************************************/
fclose ( gif );
fclose ( config );
break;
} else {
draw_distrib_gif ( config, gif );
fclose ( config );
fclose ( gif );
break;
}
} while ( TRUE );
}