From 0209ff81818995fcd2e2b7080c0ca504fa14d949 Mon Sep 17 00:00:00 2001 From: oetiker Date: Tue, 24 Aug 2004 05:26:09 +0000 Subject: [PATCH] CDEF operators SHIFT, SQRT, SORT, and REV (reverse). See documentation for what they do. This included removal of redundant code in the rrd_xport path, replaced with a call to rrd_graph_script(). -- David M. Grimes git-svn-id: svn://svn.oetiker.ch/rrdtool/trunk/program@290 a5681a0c-68f1-0310-ab6d-d61299d08faa --- CONTRIBUTORS | 2 +- doc/rrdgraph_rpn.src | 16 ++++++- src/rrd_graph.c | 47 +++++++++++++++---- src/rrd_graph.h | 9 +++- src/rrd_graph_helper.c | 85 +++++++++++++++++++++++++++++++--- src/rrd_rpncalc.c | 47 ++++++++++++++++++- src/rrd_rpncalc.h | 3 +- src/rrd_xport.c | 122 +++---------------------------------------------- 8 files changed, 192 insertions(+), 139 deletions(-) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 9254b18..b924d24 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -60,7 +60,7 @@ Debugging and code contributions David L. Barker xport function bug fixes Mike Slifcak many rrdtool-1.1.x fixes Peter Speck eps/svg/pdf file format code in rrdtool-1.x - + David Grimes SQRT/SORT/REV/SHIFT Documentation diff --git a/doc/rrdgraph_rpn.src b/doc/rrdgraph_rpn.src index b765f9a..ae1a91b 100644 --- a/doc/rrdgraph_rpn.src +++ b/doc/rrdgraph_rpn.src @@ -94,9 +94,9 @@ B<+, -, *, /, %> Add, subtract, multiply, divide, modulo -B +B -Sine, cosine (input in radians), log, exp (natural logarithm) +Sine, cosine (input in radians), log, exp (natural logarithm), square root B @@ -108,6 +108,18 @@ Round down,up to the nearest integer Z<> +=item Ordering Operations + +B + +Pop one element from the stack. This is the I of items to be sorted +(or reversed). The top I of the remaining elements are then sorted +(or reversed) in place on the stack. + +Example: C will +compute the average of the values v1..v6 after removing the smallest and +largest. + =item Special values B diff --git a/src/rrd_graph.c b/src/rrd_graph.c index 6d91954..438b3e1 100644 --- a/src/rrd_graph.c +++ b/src/rrd_graph.c @@ -188,6 +188,7 @@ enum gf_en gf_conv(char *string){ conv_if(VDEF,GF_VDEF) conv_if(PART,GF_PART) conv_if(XPORT,GF_XPORT) + conv_if(SHIFT,GF_SHIFT) return (-1); } @@ -822,6 +823,28 @@ data_calc( image_desc_t *im){ switch (im->gdes[gdi].gf) { case GF_XPORT: break; + case GF_SHIFT: { + graph_desc_t *vdp = &im->gdes[im->gdes[gdi].vidx]; + + /* remove current shift */ + vdp->start -= vdp->shift; + vdp->end -= vdp->shift; + + /* vdef */ + if (im->gdes[gdi].shidx >= 0) + vdp->shift = im->gdes[im->gdes[gdi].shidx].vf.val; + /* constant */ + else + vdp->shift = im->gdes[gdi].shval; + + /* normalize shift to multiple of consolidated step */ + vdp->shift = (vdp->shift / vdp->step) * vdp->step; + + /* apply shift */ + vdp->start += vdp->shift; + vdp->end += vdp->shift; + break; + } case GF_VDEF: /* A VDEF has no DS. This also signals other parts * of rrdtool that this is a VDEF value, not a CDEF. @@ -911,14 +934,13 @@ data_calc( image_desc_t *im){ for(rpi=0;im->gdes[gdi].rpnp[rpi].op != OP_END;rpi++){ if(im->gdes[gdi].rpnp[rpi].op == OP_VARIABLE || im->gdes[gdi].rpnp[rpi].op == OP_PREV_OTHER){ - long ptr = im->gdes[gdi].rpnp[rpi].ptr; - if(im->gdes[gdi].start > im->gdes[ptr].start) { - im->gdes[gdi].rpnp[rpi].data += im->gdes[gdi].rpnp[rpi].ds_cnt - * ((im->gdes[gdi].start - im->gdes[ptr].start) / im->gdes[ptr].step); - } + long ptr = im->gdes[gdi].rpnp[rpi].ptr; + long diff = im->gdes[gdi].start - im->gdes[ptr].start; + + if(diff > 0) + im->gdes[gdi].rpnp[rpi].data += (diff / im->gdes[ptr].step) * im->gdes[ptr].ds_cnt; } } - if(steparray == NULL){ rrd_set_error("rpn expressions without DEF" @@ -1016,8 +1038,10 @@ data_proc( image_desc_t *im ){ ** the time of the graph. Beware. */ vidx = im->gdes[ii].vidx; - if ( ((long int)gr_time >= (long int)im->gdes[vidx].start) && - ((long int)gr_time <= (long int)im->gdes[vidx].end) ) { + if (im->gdes[vidx].gf == GF_VDEF) { + value = im->gdes[vidx].vf.val; + } else if (((long int)gr_time >= (long int)im->gdes[vidx].start) && + ((long int)gr_time <= (long int)im->gdes[vidx].end) ) { value = im->gdes[vidx].data[ (unsigned long) floor( (double)(gr_time - im->gdes[vidx].start) @@ -1333,6 +1357,7 @@ print_calc(image_desc_t *im, char ***prdata) case GF_CDEF: case GF_VDEF: case GF_PART: + case GF_SHIFT: case GF_XPORT: break; } @@ -2348,6 +2373,7 @@ graph_paint(image_desc_t *im, char ***calcpr) case GF_HRULE: case GF_VRULE: case GF_XPORT: + case GF_SHIFT: break; case GF_TICK: for (ii = 0; ii < im->xsize; ii++) @@ -2569,6 +2595,7 @@ gdes_alloc(image_desc_t *im){ im->gdes[im->gdes_c-1].data_first=0; im->gdes[im->gdes_c-1].p_data=NULL; im->gdes[im->gdes_c-1].rpnp=NULL; + im->gdes[im->gdes_c-1].shift=0; im->gdes[im->gdes_c-1].col = 0x0; im->gdes[im->gdes_c-1].legend[0]='\0'; im->gdes[im->gdes_c-1].rrd[0]='\0'; @@ -2631,7 +2658,7 @@ rrd_graph(int argc, char **argv, char ***prdata, int *xsize, int *ysize, FILE *s strncpy(im.graphfile,argv[optind],MAXPATH-1); im.graphfile[MAXPATH-1]='\0'; - rrd_graph_script(argc,argv,&im); + rrd_graph_script(argc,argv,&im,1); if (rrd_test_error()) { im_free(&im); return -1; @@ -2776,7 +2803,7 @@ rrd_graph_options(int argc, char *argv[],image_desc_t *im) {"lazy", no_argument, 0, 'z'}, {"zoom", required_argument, 0, 'm'}, {"no-legend", no_argument, 0, 'g'}, - {"only-graph", no_argument, 0, 'j'}, + {"only-graph", no_argument, 0, 'j'}, {"alt-y-grid", no_argument, 0, 'Y'}, {"no-minor", no_argument, 0, 'I'}, {"alt-autoscale", no_argument, 0, 'A'}, diff --git a/src/rrd_graph.h b/src/rrd_graph.h index 13f7160..607ab70 100644 --- a/src/rrd_graph.h +++ b/src/rrd_graph.h @@ -27,7 +27,7 @@ enum grc_en {GRC_CANVAS=0,GRC_BACK,GRC_SHADEA,GRC_SHADEB, enum gf_en {GF_PRINT=0,GF_GPRINT,GF_COMMENT,GF_HRULE,GF_VRULE,GF_LINE, GF_AREA,GF_STACK,GF_TICK, - GF_DEF, GF_CDEF, GF_VDEF, + GF_DEF, GF_CDEF, GF_VDEF, GF_SHIFT, GF_PART, GF_XPORT}; enum vdef_op_en { @@ -113,6 +113,11 @@ typedef struct graph_desc_t { vdef_t vf; /* instruction for VDEF function */ rpnp_t *rpnp; /* instructions for CDEF function */ + /* SHIFT implementation */ + int shidx; /* gdes reference for offset (-1 --> constant) */ + time_t shval; /* offset if shidx is -1 */ + time_t shift; /* current shift applied */ + /* 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 */ @@ -215,7 +220,7 @@ int scan_for_col(char *, int, char *); int rrd_graph(int, char **, char ***, int *, int *, FILE *); void rrd_graph_init(image_desc_t *); void rrd_graph_options(int, char **, image_desc_t *); -void rrd_graph_script(int, char **, image_desc_t *); +void rrd_graph_script(int, char **, image_desc_t *, int); int rrd_graph_check_vname(image_desc_t *, char *, char *); int rrd_graph_color(image_desc_t *, char *, char *, int); int rrd_graph_legend(graph_desc_t *, char *); diff --git a/src/rrd_graph_helper.c b/src/rrd_graph_helper.c index a15c0ed..c359f7a 100644 --- a/src/rrd_graph_helper.c +++ b/src/rrd_graph_helper.c @@ -15,6 +15,8 @@ int rrd_parse_legend (char *, unsigned int *, graph_desc_t *); int rrd_parse_color (char *, graph_desc_t *); int rrd_parse_CF (char *, unsigned int *, graph_desc_t *); int rrd_parse_print (char *, unsigned int *, graph_desc_t *, image_desc_t *); +int rrd_parse_shift (char *, unsigned int *, graph_desc_t *, image_desc_t *); +int rrd_parse_xport (char *, unsigned int *, graph_desc_t *, image_desc_t *); int rrd_parse_PVHLAST (char *, unsigned int *, graph_desc_t *, image_desc_t *); int rrd_parse_vname (char *, unsigned int *, graph_desc_t *, image_desc_t *); int rrd_parse_def (char *, unsigned int *, graph_desc_t *, image_desc_t *); @@ -161,6 +163,77 @@ rrd_parse_print(char *line, unsigned int *eaten, graph_desc_t *gdp, image_desc_t return 0; } +int +rrd_parse_shift(char *line, unsigned int *eaten, graph_desc_t *gdp, image_desc_t *im) { + char *l = strdup(line + *eaten), *p; + int rc = 1; + + p = strchr(l, ','); + if (p == NULL) { + rrd_set_error("Invalid SHIFT syntax"); + goto out; + } + *p++ = '\0'; + + if ((gdp->vidx=find_var(im,l))<0) { + rrd_set_error("Not a valid vname: %s in line %s",l,line); + goto out; + } + + /* constant will parse; otherwise, must be VDEF reference */ + if (sscanf(p, "%ld", &gdp->shval) != 1) { + graph_desc_t *vdp; + + if ((gdp->shidx=find_var(im, p))<0) { + rrd_set_error("invalid offset vname: %s", p); + goto out; + } + + vdp = &im->gdes[gdp->shidx]; + if (vdp->gf != GF_VDEF) { + rrd_set_error("offset must specify value or VDEF"); + goto out; + } + } else { + gdp->shidx = -1; + } + + *eaten = strlen(line); + rc = 0; + + out: + free(l); + return rc; +} + +int +rrd_parse_xport(char *line, unsigned int *eaten, graph_desc_t *gdp, image_desc_t *im) { + char *l = strdup(line + *eaten), *p; + int rc = 1; + + p = strchr(l, ':'); + if (p != NULL) + *p++ = '\0'; + else + p = ""; + + if ((gdp->vidx=find_var(im, l))==-1){ + rrd_set_error("unknown variable '%s'",l); + goto out; + } + + if (strlen(p) >= FMT_LEG_LEN) + *(p + FMT_LEG_LEN) = '\0'; + + strcpy(gdp->legend, p); + *eaten = strlen(line); + rc = 0; + + out: + free(l); + return rc; +} + /* Parsing of PART, VRULE, HRULE, LINE, AREA, STACK and TICK ** is done in one function. Stacking STACK is silently ignored ** as it is redundant. Stacking PART, VRULE, HRULE or TICK is @@ -463,10 +536,10 @@ rrd_parse_cdef(char *line, unsigned int *eaten, graph_desc_t *gdp, image_desc_t } void -rrd_graph_script(int argc, char *argv[], image_desc_t *im) { +rrd_graph_script(int argc, char *argv[], image_desc_t *im, int optno) { int i; - for (i=optind+1;igf) { -#if 0 - /* future command */ - case GF_SHIFT: vname:value -#endif + case GF_SHIFT: /* vname:value */ + if (rrd_parse_shift(argv[i],&eaten,gdp,im)) return; + break; case GF_XPORT: + if (rrd_parse_xport(argv[i],&eaten,gdp,im)) return; break; case GF_PRINT: /* vname:CF:format -or- vname:format */ case GF_GPRINT: /* vname:CF:format -or- vname:format */ diff --git a/src/rrd_rpncalc.c b/src/rrd_rpncalc.c index 94796d1..75c24cf 100644 --- a/src/rrd_rpncalc.c +++ b/src/rrd_rpncalc.c @@ -154,6 +154,9 @@ void rpn_compact2str(rpn_cdefds_t *rpnc,ds_def_t *ds_def,char **str) add_op(OP_LTIME,LTIME) add_op(OP_TIME,TIME) add_op(OP_ATAN,ATAN) + add_op(OP_SQRT,SQRT) + add_op(OP_SORT,SORT) + add_op(OP_REV,REV) #undef add_op } @@ -323,7 +326,9 @@ rpn_parse(void *key_hash,char *expr,long (*lookup)(void *,char*)){ match_op(OP_NOW,NOW) match_op(OP_TIME,TIME) match_op(OP_ATAN,ATAN) - + match_op(OP_SQRT,SQRT) + match_op(OP_SORT,SORT) + match_op(OP_REV,REV) #undef match_op @@ -367,6 +372,14 @@ rpnstack_free(rpnstack_t *rpnstack) rpnstack -> dc_stacksize = 0; } +static int +rpn_compare_double(const void *x, const void *y) +{ + double diff = *((const double *)x) - *((const double *)y); + + return (diff < 0) ? -1 : (diff > 0) ? 1 : 0; +} + /* rpn_calc: run the RPN calculator; also performs variable substitution; * moved and modified from data_calc() originally included in rrd_graph.c * arguments: @@ -660,6 +673,38 @@ rpn_calc(rpnp_t *rpnp, rpnstack_t *rpnstack, long data_idx, stackunderflow(0); rpnstack->s[stptr] = isinf(rpnstack->s[stptr]) ? 1.0 : 0.0; break; + case OP_SQRT: + stackunderflow(0); + rpnstack -> s[stptr] = sqrt(rpnstack -> s[stptr]); + break; + case OP_SORT: + stackunderflow(0); + { + int spn = (int)rpnstack -> s[stptr--]; + + stackunderflow(spn-1); + qsort(rpnstack -> s + stptr-spn+1, spn, sizeof(double), + rpn_compare_double); + } + break; + case OP_REV: + stackunderflow(0); + { + int spn = (int)rpnstack -> s[stptr--]; + double *p, *q; + + stackunderflow(spn-1); + + p = rpnstack -> s + stptr-spn+1; + q = rpnstack -> s + stptr; + while (p < q) { + double x = *q; + + *q-- = *p; + *p++ = x; + } + } + break; case OP_END: break; } diff --git a/src/rrd_rpncalc.h b/src/rrd_rpncalc.h index fe456f2..9fd547a 100644 --- a/src/rrd_rpncalc.h +++ b/src/rrd_rpncalc.h @@ -15,7 +15,8 @@ enum op_en {OP_NUMBER=0,OP_VARIABLE,OP_INF,OP_PREV,OP_NEGINF, OP_DIV,OP_SIN, OP_DUP, OP_EXC, OP_POP, OP_COS,OP_LOG,OP_EXP,OP_LT,OP_LE,OP_GT,OP_GE,OP_EQ,OP_IF, OP_MIN,OP_MAX,OP_LIMIT, OP_FLOOR, OP_CEIL, - OP_UN,OP_END,OP_LTIME,OP_NE,OP_ISINF,OP_PREV_OTHER,OP_COUNT,OP_ATAN}; + OP_UN,OP_END,OP_LTIME,OP_NE,OP_ISINF,OP_PREV_OTHER,OP_COUNT, + OP_ATAN,OP_SQRT,OP_SORT,OP_REV}; typedef struct rpnp_t { enum op_en op; diff --git a/src/rrd_xport.c b/src/rrd_xport.c index cceefe2..95bf35b 100644 --- a/src/rrd_xport.c +++ b/src/rrd_xport.c @@ -43,11 +43,7 @@ rrd_xport(int argc, char **argv, int *xsize, { image_desc_t im; - int i; - long long_tmp; time_t start_tmp=0,end_tmp=0; - char symname[100]; - long scancount; struct rrd_time_value start_tv, end_tv; char *parsetime_error = NULL; @@ -91,12 +87,11 @@ rrd_xport(int argc, char **argv, int *xsize, } break; case 'm': - long_tmp = atol(optarg); - if (long_tmp < 10) { + im.xsize = atol(optarg); + if (im.xsize < 10) { rrd_set_error("maxrows below 10 rows"); return -1; } - im.xsize = long_tmp; break; case '?': rrd_set_error("unknown option '%c'", optopt); @@ -122,115 +117,10 @@ rrd_xport(int argc, char **argv, int *xsize, im.start = start_tmp; im.end = end_tmp; - for(i=optind;i=1){ - if(strstart <= 0){ - im.gdes[im.gdes_c-1].legend[0] = '\0'; - } else { - scan_for_col(&argv[i][argstart+strstart],FMT_LEG_LEN,im.gdes[im.gdes_c-1].legend); - } - if((im.gdes[im.gdes_c-1].vidx=find_var(&im,varname))==-1){ - im_free(&im); - rrd_set_error("unknown variable '%s'",varname); - return -1; - } - } else { - im_free(&im); - rrd_set_error("can't parse '%s'",&argv[i][argstart]); - return -1; - } - break; - default: - break; - } - + rrd_graph_script(argc,argv,&im,0); + if (rrd_test_error()) { + im_free(&im); + return -1; } if (im.gdes_c == 0){ -- 2.11.0