X-Git-Url: https://git.verplant.org/?a=blobdiff_plain;f=src%2Frrd_graph.c;h=27314776c0d3d9e152bd83a4f332c6818e3b341d;hb=e882b59504803ffe62eaeff5efaf0ff730d85744;hp=18f7d2382cc9c25650439c147059dec5da5925b3;hpb=9460822de0482683f76ebcaf17c0e1ed5cee0000;p=rrdtool.git diff --git a/src/rrd_graph.c b/src/rrd_graph.c index 18f7d23..2731477 100644 --- a/src/rrd_graph.c +++ b/src/rrd_graph.c @@ -4,7 +4,10 @@ * rrd__graph.c make creates ne rrds ****************************************************************************/ +#if 0 #include "rrd_tool.h" +#endif + #include #include #include @@ -13,7 +16,9 @@ #include #include #endif -#include "rrd_rpncalc.h" + +#include "rrd_graph.h" +#include "rrd_graph_helper.h" #define SmallFont gdLucidaNormal10 #define LargeFont gdLucidaBold12 @@ -26,56 +31,6 @@ # define DPRINT(x) #endif -#define DEF_NAM_FMT "%29[_A-Za-z0-9]" - -enum tmt_en {TMT_SECOND=0,TMT_MINUTE,TMT_HOUR,TMT_DAY, - TMT_WEEK,TMT_MONTH,TMT_YEAR}; - -enum grc_en {GRC_CANVAS=0,GRC_BACK,GRC_SHADEA,GRC_SHADEB, - GRC_GRID,GRC_MGRID,GRC_FONT,GRC_FRAME,GRC_ARROW,__GRC_END__}; - - -enum gf_en {GF_PRINT=0,GF_GPRINT,GF_COMMENT,GF_HRULE,GF_VRULE,GF_LINE1, - GF_LINE2,GF_LINE3,GF_AREA,GF_STACK,GF_TICK, - GF_DEF, GF_CDEF, GF_VDEF}; - -enum if_en {IF_GIF=0,IF_PNG=1}; - -enum vdef_op_en { - VDEF_MAXIMUM /* like the MAX in (G)PRINT */ - ,VDEF_MINIMUM /* like the MIN in (G)PRINT */ - ,VDEF_AVERAGE /* like the AVERAGE in (G)PRINT */ - ,VDEF_PERCENT /* Nth percentile */ - ,VDEF_FIRST /* first non-unknown value and time */ - ,VDEF_LAST /* last non-unknown value and time */ - }; -typedef struct vdef_t { - enum vdef_op_en op; - double param; /* parameter for function, if applicable */ - double val; /* resulting value */ - time_t when; /* timestamp, if applicable */ -} vdef_t; - -typedef struct col_trip_t { - int red; /* red = -1 is no color */ - int green; - int blue; - int i; /* color index assigned in gif image i=-1 is unasigned*/ -} col_trip_t; - - -typedef struct xlab_t { - long minsec; /* minimum sec per pix */ - enum tmt_en gridtm; /* grid interval in what ?*/ - long gridst; /* how many whats per grid*/ - enum tmt_en mgridtm; /* label interval in what ?*/ - long mgridst; /* how many whats per label*/ - enum tmt_en labtm; /* label interval in what ?*/ - long labst; /* how many whats per label*/ - long precis; /* label precision -> label placement*/ - char *stst; /* strftime string*/ -} xlab_t; - xlab_t xlab[] = { {0, TMT_SECOND,30, TMT_MINUTE,5, TMT_MINUTE,5, 0,"%H:%M"}, {2, TMT_MINUTE,1, TMT_MINUTE,5, TMT_MINUTE,5, 0,"%H:%M"}, @@ -110,11 +65,6 @@ double yloglab[][12]= {{ 1e9, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* sensible y label intervals ...*/ -typedef struct ylab_t { - double grid; /* grid spacing */ - int lfac[4]; /* associated label spacing*/ -} ylab_t; - ylab_t ylab[]= { {0.1, {1,2, 5,10}}, {0.2, {1,5,10,20}}, @@ -144,133 +94,6 @@ col_trip_t graph_col[] = { /* default colors */ {255,0,0,-1} /*arrow*/ }; -/* this structure describes the elements which can make up a graph. - because they are quite diverse, not all elements will use all the - possible parts of the structure. */ -#ifdef HAVE_SNPRINTF -#define FMT_LEG_LEN 200 -#else -#define FMT_LEG_LEN 2000 -#endif - -typedef struct graph_desc_t { - enum gf_en gf; /* graphing function */ - char vname[30]; /* name of the variable */ - long vidx; /* gdes reference */ - char rrd[255]; /* name of the rrd_file containing data */ - char ds_nam[DS_NAM_SIZE]; /* data source name */ - long ds; /* data source number */ - enum cf_en cf; /* consolidation function */ - col_trip_t col; /* graph color */ - char format[FMT_LEG_LEN+5]; /* format for PRINT AND GPRINT */ - char legend[FMT_LEG_LEN+5]; /* legend*/ - gdPoint legloc; /* location of legend */ - double yrule; /* value for y rule line and for VDEF */ - time_t xrule; /* time for x rule line and for VDEF */ - vdef_t vf; /* instruction for VDEF function */ - rpnp_t *rpnp; /* instructions for CDEF function */ - - /* description of data fetched for the graph element */ - time_t start,end; /* timestaps for first and last data element */ - unsigned long step; /* time between samples */ - unsigned long ds_cnt; /* how many data sources are there in the fetch */ - long data_first; /* first pointer to this data */ - char **ds_namv; /* name of datasources in the fetch. */ - rrd_value_t *data; /* the raw data drawn from the rrd */ - rrd_value_t *p_data; /* processed data, xsize elments */ - -} graph_desc_t; - -#define ALTYGRID 0x01 /* use alternative y grid algorithm */ -#define ALTAUTOSCALE 0x02 /* use alternative algorithm to find lower and upper bounds */ -#define ALTAUTOSCALE_MAX 0x04 /* use alternative algorithm to find upper bounds */ -#define NOLEGEND 0x08 /* use no legend */ - -typedef struct image_desc_t { - - /* configuration of graph */ - - char graphfile[MAXPATH]; /* filename for graphic */ - long xsize,ysize; /* graph area size in pixels */ - col_trip_t graph_col[__GRC_END__]; /* real colors for the graph */ - char ylegend[200]; /* legend along the yaxis */ - char title[200]; /* title for graph */ - int draw_x_grid; /* no x-grid at all */ - int draw_y_grid; /* no x-grid at all */ - xlab_t xlab_user; /* user defined labeling for xaxis */ - char xlab_form[200]; /* format for the label on the xaxis */ - - double ygridstep; /* user defined step for y grid */ - int ylabfact; /* every how many y grid shall a label be written ? */ - - time_t start,end; /* what time does the graph cover */ - unsigned long step; /* any preference for the default step ? */ - rrd_value_t minval,maxval; /* extreme values in the data */ - int rigid; /* do not expand range even with - values outside */ - char* imginfo; /* construct an xorigin \ @@ -326,8 +149,6 @@ ytr(image_desc_t *im, double value){ } } - - /* conversion function for symbolic entry names */ @@ -427,7 +248,7 @@ auto_scale( ) { - char *symbol[] = {"a", /* 10e-18 Ato */ + char *symbol[] = {"a", /* 10e-18 Atto */ "f", /* 10e-15 Femto */ "p", /* 10e-12 Pico */ "n", /* 10e-9 Nano */ @@ -437,7 +258,7 @@ auto_scale( "k", /* 10e3 Kilo */ "M", /* 10e6 Mega */ "G", /* 10e9 Giga */ - "T", /* 10e12 Terra */ + "T", /* 10e12 Tera */ "P", /* 10e15 Peta */ "E"};/* 10e18 Exa */ @@ -468,7 +289,7 @@ si_unit( ) { - char symbol[] = {'a', /* 10e-18 Ato */ + char symbol[] = {'a', /* 10e-18 Atto */ 'f', /* 10e-15 Femto */ 'p', /* 10e-12 Pico */ 'n', /* 10e-9 Nano */ @@ -478,7 +299,7 @@ si_unit( 'k', /* 10e3 Kilo */ 'M', /* 10e6 Mega */ 'G', /* 10e9 Giga */ - 'T', /* 10e12 Terra */ + 'T', /* 10e12 Tera */ 'P', /* 10e15 Peta */ 'E'};/* 10e18 Exa */ @@ -1303,49 +1124,59 @@ print_calc(image_desc_t *im, char ***prdata) return 0; } case GF_GPRINT: + /* PRINT and GPRINT can now print VDEF generated values. + * There's no need to do any calculations on them as these + * calculations were already made. + */ vidx = im->gdes[i].vidx; - max_ii =((im->gdes[vidx].end - - im->gdes[vidx].start) - /im->gdes[vidx].step - *im->gdes[vidx].ds_cnt); - printval = DNAN; - validsteps = 0; - for(ii=im->gdes[vidx].ds+im->gdes[vidx].ds_cnt; - ii < max_ii+im->gdes[vidx].ds_cnt; - ii+=im->gdes[vidx].ds_cnt){ - if (! finite(im->gdes[vidx].data[ii])) - continue; - if (isnan(printval)){ - printval = im->gdes[vidx].data[ii]; - validsteps++; - continue; - } + if (im->gdes[vidx].gf==GF_VDEF) { /* simply use vals */ + printval = im->gdes[vidx].vf.val; + } else { /* need to calculate max,min,avg etcetera */ + max_ii =((im->gdes[vidx].end + - im->gdes[vidx].start) + / im->gdes[vidx].step + * im->gdes[vidx].ds_cnt); + printval = DNAN; + validsteps = 0; + for(ii=im->gdes[vidx].ds+im->gdes[vidx].ds_cnt; + ii < max_ii+im->gdes[vidx].ds_cnt; + ii+=im->gdes[vidx].ds_cnt){ + if (! finite(im->gdes[vidx].data[ii])) + continue; + if (isnan(printval)){ + printval = im->gdes[vidx].data[ii]; + validsteps++; + continue; + } - switch (im->gdes[i].cf){ - case CF_HWPREDICT: - case CF_DEVPREDICT: - case CF_DEVSEASONAL: - case CF_SEASONAL: - case CF_AVERAGE: - validsteps++; - printval += im->gdes[vidx].data[ii]; - break; - case CF_MINIMUM: - printval = min( printval, im->gdes[vidx].data[ii]); - break; - case CF_FAILURES: - case CF_MAXIMUM: - printval = max( printval, im->gdes[vidx].data[ii]); - break; - case CF_LAST: - printval = im->gdes[vidx].data[ii]; + switch (im->gdes[i].cf){ + case CF_HWPREDICT: + case CF_DEVPREDICT: + case CF_DEVSEASONAL: + case CF_SEASONAL: + case CF_AVERAGE: + validsteps++; + printval += im->gdes[vidx].data[ii]; + break; + case CF_MINIMUM: + printval = min( printval, im->gdes[vidx].data[ii]); + break; + case CF_FAILURES: + case CF_MAXIMUM: + printval = max( printval, im->gdes[vidx].data[ii]); + break; + case CF_LAST: + printval = im->gdes[vidx].data[ii]; + } } - } - if (im->gdes[i].cf == CF_AVERAGE || im -> gdes[i].cf > CF_LAST) { - if (validsteps > 1) { - printval = (printval / validsteps); + if (im->gdes[i].cf==CF_AVERAGE || im->gdes[i].cf > CF_LAST) { + if (validsteps > 1) { + printval = (printval / validsteps); + } } - } + } /* prepare printval */ + + if ((percent_s = strstr(im->gdes[i].format,"%S")) != NULL) { /* Magfact is set to -1 upon entry to print_calc. If it * is still less than 0, then we need to run auto_scale. @@ -1360,10 +1191,10 @@ print_calc(image_desc_t *im, char ***prdata) printval /= magfact; } *(++percent_s) = 's'; - } - else if (strstr(im->gdes[i].format,"%s") != NULL) { + } else if (strstr(im->gdes[i].format,"%s") != NULL) { auto_scale(im,&printval,&si_symb,&magfact); } + if (im->gdes[i].gf == GF_PRINT){ (*prdata)[prlines-2] = malloc((FMT_LEG_LEN+2)*sizeof(char)); if (bad_format(im->gdes[i].format)) { @@ -2766,7 +2597,7 @@ rrd_graph(int argc, char **argv, char ***prdata, int *xsize, int *ysize) for(i=optind+1;iFMT_LEG_LEN) argv[i][argstart+FMT_LEG_LEN-3]='\0' ; @@ -3060,62 +2921,47 @@ printf("DEBUG: strstart==%i\n",strstart); free(rpnex); break; case GF_VDEF: - /* - * strstart is set to zero and will NOT be changed - * if the comma is not matched. This means that it - * remains zero. Although strstart is initialized to - * zero at the beginning of this loop, we do it again - * here just in case someone changes the code... - * - * According to the docs we cannot rely on the - * returned value from sscanf; it can be 2 or 3, - * depending on %n incrementing it or not. - */ - strstart=0; + strstart=parse_vname1(&argv[i][argstart],&im,"VDEF"); + if (strstart==0) return -1; + + argstart+=strstart; sscanf( - &argv[i][argstart], - DEF_NAM_FMT "=" DEF_NAM_FMT ",%n", - im.gdes[im.gdes_c-1].vname, - varname, - &strstart); - if (strstart){ - /* checking both variable names */ - if (find_var(&im,im.gdes[im.gdes_c-1].vname) != -1){ - im_free(&im); - rrd_set_error("duplicate variable '%s'", - im.gdes[im.gdes_c-1].vname); - return -1; - } else { - if ((im.gdes[im.gdes_c-1].vidx=find_var(&im,varname)) == -1){ - im_free(&im); - rrd_set_error("variable '%s' not known in VDEF '%s'", - varname, - im.gdes[im.gdes_c-1].vname); - return -1; - } else { - if(im.gdes[im.gdes[im.gdes_c-1].vidx].gf != GF_DEF - && im.gdes[im.gdes[im.gdes_c-1].vidx].gf != GF_CDEF){ - rrd_set_error("variable '%s' not DEF nor CDEF in VDEF '%s'", - varname, - im.gdes[im.gdes_c-1].vname); - im_free(&im); - return -1; - } - } - /* parsed upto and including the first comma. Now - * see what function is requested. This function - * sets the error string. - */ - if (vdef_parse(&im.gdes[im.gdes_c-1],&argv[i][argstart+strstart])<0) { - im_free(&im); - return -1; - }; - } - } else { + &argv[i][argstart], + DEF_NAM_FMT ",%n", + varname,&strstart + ); + if (strstart==0) { im_free(&im); - rrd_set_error("can't parse VDEF '%s'",&argv[i][argstart]); + rrd_set_error("Cannot parse '%s' in VDEF '%s'", + &argv[i][argstart], + im.gdes[im.gdes_c-1].vname); return -1; } + if ((im.gdes[im.gdes_c-1].vidx=find_var(&im,varname)) == -1) { + im_free(&im); + rrd_set_error("variable '%s' not known in VDEF '%s'", + varname, + im.gdes[im.gdes_c-1].vname); + return -1; + }; + if ( + im.gdes[im.gdes[im.gdes_c-1].vidx].gf != GF_DEF + && im.gdes[im.gdes[im.gdes_c-1].vidx].gf != GF_CDEF) { + rrd_set_error("variable '%s' not DEF nor CDEF in VDEF '%s'", + varname, + im.gdes[im.gdes_c-1].vname); + im_free(&im); + return -1; + }; + + /* parsed upto and including the first comma. Now + * see what function is requested. This function + * sets the error string. + */ + if (vdef_parse(&im.gdes[im.gdes_c-1],&argv[i][argstart+strstart])<0) { + im_free(&im); + return -1; + }; break; case GF_DEF: if (sscanf( @@ -3256,6 +3102,7 @@ char *str; else if (!strcmp("MAXIMUM",func)) gdes->vf.op = VDEF_MAXIMUM; else if (!strcmp("AVERAGE",func)) gdes->vf.op = VDEF_AVERAGE; else if (!strcmp("MINIMUM",func)) gdes->vf.op = VDEF_MINIMUM; + else if (!strcmp("TOTAL", func)) gdes->vf.op = VDEF_TOTAL; else if (!strcmp("FIRST", func)) gdes->vf.op = VDEF_FIRST; else if (!strcmp("LAST", func)) gdes->vf.op = VDEF_LAST; else { @@ -3290,6 +3137,7 @@ char *str; case VDEF_MAXIMUM: case VDEF_AVERAGE: case VDEF_MINIMUM: + case VDEF_TOTAL: case VDEF_FIRST: case VDEF_LAST: if (isnan(param)) { @@ -3329,7 +3177,7 @@ printf("DEBUG: start == %lu, end == %lu, %lu steps\n" ); #endif - switch (im->gdes[gdi].vf.op) { + switch (dst->vf.op) { case VDEF_PERCENT: { rrd_value_t * array; int field; @@ -3347,7 +3195,7 @@ printf("DEBUG: start == %lu, end == %lu, %lu steps\n" field = (steps-1)*dst->vf.param/100; dst->vf.val = array[field]; dst->vf.when = 0; /* no time component */ -#if 1 +#if 0 for(step=0;stepvf.val = DNAN; dst->vf.when = 0; } else { - dst->vf.val = data[steps*src->ds_cnt]; + dst->vf.val = data[step*src->ds_cnt]; dst->vf.when = src->start + (step+1)*src->step; } while (step != steps) { if (finite(data[step*src->ds_cnt])) { if (data[step*src->ds_cnt] > dst->vf.val) { - dst->vf.val = data[steps*src->ds_cnt]; + dst->vf.val = data[step*src->ds_cnt]; dst->vf.when = src->start + (step+1)*src->step; } } step++; } break; + case VDEF_TOTAL: case VDEF_AVERAGE: { int cnt=0; double sum=0.0; @@ -3380,12 +3229,16 @@ printf("DEBUG: %3li:%10.2f %c\n",step,array[step],step==field?'*':' '); if (finite(data[step*src->ds_cnt])) { sum += data[step*src->ds_cnt]; cnt ++; - } - step++; + }; } if (cnt) { - dst->vf.val = sum/cnt; - dst->vf.when = 0; /* no time component */ + if (dst->vf.op == VDEF_TOTAL) { + dst->vf.val = sum*src->step; + dst->vf.when = cnt*src->step; /* not really "when" */ + } else { + dst->vf.val = sum/cnt; + dst->vf.when = 0; /* no time component */ + }; } else { dst->vf.val = DNAN; dst->vf.when = 0; @@ -3399,13 +3252,13 @@ printf("DEBUG: %3li:%10.2f %c\n",step,array[step],step==field?'*':' '); dst->vf.val = DNAN; dst->vf.when = 0; } else { - dst->vf.val = data[steps*src->ds_cnt]; + dst->vf.val = data[step*src->ds_cnt]; dst->vf.when = src->start + (step+1)*src->step; } while (step != steps) { if (finite(data[step*src->ds_cnt])) { if (data[step*src->ds_cnt] < dst->vf.val) { - dst->vf.val = data[steps*src->ds_cnt]; + dst->vf.val = data[step*src->ds_cnt]; dst->vf.when = src->start + (step+1)*src->step; } } @@ -3446,7 +3299,7 @@ printf("DEBUG: %3li:%10.2f %c\n",step,array[step],step==field?'*':' '); return 0; } -/* NaN <= -INF <= finite_values <= INF */ +/* NaN < -INF < finite_values < INF */ int vdef_percent_compar(a,b) const void *a,*b; @@ -3468,3 +3321,4 @@ const void *a,*b; /* If we reach this, both values must be finite */ if ( *(double *)a < *(double *)b ) return -1; else return 1; } +