misc fixed and TREND and reduce functionality by
authoroetiker <oetiker@a5681a0c-68f1-0310-ab6d-d61299d08faa>
Fri, 24 Sep 2004 21:11:09 +0000 (21:11 +0000)
committeroetiker <oetiker@a5681a0c-68f1-0310-ab6d-d61299d08faa>
Fri, 24 Sep 2004 21:11:09 +0000 (21:11 +0000)
-- David M. Grimes <dgrimes@navisite.com>

git-svn-id: svn://svn.oetiker.ch/rrdtool/trunk/program@291 a5681a0c-68f1-0310-ab6d-d61299d08faa

CONTRIBUTORS
doc/rrdgraph_data.src
doc/rrdgraph_rpn.src
src/rrd_graph.c
src/rrd_graph.h
src/rrd_graph_helper.c
src/rrd_resize.c
src/rrd_rpncalc.c
src/rrd_rpncalc.h
src/rrd_xport.c

index b924d24..717ff1f 100644 (file)
@@ -60,7 +60,7 @@ Debugging and code contributions
        David L. Barker <dave@ncomtech.com> xport function bug fixes
        Mike Slifcak <slif@bellsouth.net> many rrdtool-1.1.x fixes
        Peter Speck <speck@vitality.dk> eps/svg/pdf file format code in rrdtool-1.x
-       David Grimes <dgrimes@navisite.com> SQRT/SORT/REV/SHIFT
+       David Grimes <dgrimes@navisite.com> SQRT/SORT/REV/SHIFT/TREND
 
 Documentation
 
index 88ac260..1f8fcb7 100644 (file)
@@ -2,7 +2,7 @@
 
 =head1 SYNOPSIS
 
-B<DEF:>I<E<lt>vnameE<gt>>=I<E<lt>rrdfileE<gt>>:I<E<lt>ds-nameE<gt>>:I<E<lt>CFE<gt>>[:step=I<E<lt>stepE<gt>>][:start=I<E<lt>timeE<gt>>][:end=I<E<lt>timeE<gt>>]
+B<DEF:>I<E<lt>vnameE<gt>>=I<E<lt>rrdfileE<gt>>:I<E<lt>ds-nameE<gt>>:I<E<lt>CFE<gt>>[:step=I<E<lt>stepE<gt>>][:start=I<E<lt>timeE<gt>>][:end=I<E<lt>timeE<gt>>][:reduce=I<E<lt>B<CF>E<gt>>]
 
 B<VDEF>:I<vname>=I<RPN expression>
 
@@ -18,7 +18,7 @@ a language called B<RPN> which is described in its own manual page.
 
 =head1 DEF
 
-B<DEF:>I<E<lt>vnameE<gt>>=I<E<lt>rrdfileE<gt>>:I<E<lt>ds-nameE<gt>>:I<E<lt>CFE<gt>>[:step=I<E<lt>stepE<gt>>][:start=I<E<lt>timeE<gt>>][:end=I<E<lt>timeE<gt>>]
+B<DEF:>I<E<lt>vnameE<gt>>=I<E<lt>rrdfileE<gt>>:I<E<lt>ds-nameE<gt>>:I<E<lt>CFE<gt>>[:step=I<E<lt>stepE<gt>>][:start=I<E<lt>timeE<gt>>][:end=I<E<lt>timeE<gt>>][:reduce=I<E<lt>B<CF>E<gt>>]
 
 This command fetches data from an B<RRD> file.  The virtual name
 I<vname> can then be used throughout the rest of the script. By
@@ -39,6 +39,11 @@ a resolution of 1800 seconds per B<CDP>, you should create an
 image with width 400 and time span 400*1800 seconds (use appropriate
 start and end times, such as C<--start end-8days8hours>).
 
+If consolidation needs to be done, the B<CF> of the B<RRA> specified in the
+B<DEF> itself will be used to reduce the data density.  This behaviour can
+be changed using C<:reduce=I<E<lt>B<CF>E<gt>>>.  This optional parameter
+specifies the B<CF> to use during the data reduction phase.
+
 Example:
 
         DEF:ds0=router.rrd:ds0:AVERAGE
index ae1a91b..4aad477 100644 (file)
@@ -108,7 +108,7 @@ Round down,up to the nearest integer
 
 Z<>
 
-=item Ordering Operations
+=item Set Operations
 
 B<SORT, REV>
 
@@ -120,6 +120,30 @@ Example: C<CDEF:x=v1,v2,v3,v4,v5,v6,6,SORT,POP,5,REV,POP,+,+,+,4,/> will
 compute the average of the values v1..v6 after removing the smallest and
 largest.
 
+B<TREND>
+
+Create a "sliding window" average of another data series.
+
+Usage:
+CDEF:smoothed=x,1800,TREND
+
+This will create a half-hour (1800 second) sliding window average of x.  The
+average is essentially computed as shown here:
+
+                 +---!---!---!---!---!---!---!---!--->
+                                                     now
+                       delay     t0
+                 <--------------->
+                         delay       t1
+                     <--------------->  
+                              delay      t2
+                         <--------------->
+
+
+     Value at sample (t0) will be the average between (t0-delay) and  (t0)
+     Value at sample (t1) will be the average between (t1-delay) and  (t1)
+     Value at sample (t2) will be the average between (t2-delay) and  (t2)
+
 =item Special values
 
 B<UNKN>
index 438b3e1..d22c853 100644 (file)
@@ -698,6 +698,7 @@ data_fetch(image_desc_t *im )
                continue;
            if ((strcmp(im->gdes[i].rrd, im->gdes[ii].rrd) == 0)
                        && (im->gdes[i].cf    == im->gdes[ii].cf)
+                       && (im->gdes[i].cf_reduce == im->gdes[ii].cf_reduce)
                        && (im->gdes[i].start == im->gdes[ii].start)
                        && (im->gdes[i].end   == im->gdes[ii].end)
                        && (im->gdes[i].step  == im->gdes[ii].step)) {
@@ -730,9 +731,10 @@ data_fetch(image_desc_t *im )
                return -1;
            }
            im->gdes[i].data_first = 1;     
+           im->gdes[i].step = im->step;
        
            if (ft_step < im->gdes[i].step) {
-               reduce_data(im->gdes[i].cf,
+               reduce_data(im->gdes[i].cf_reduce,
                            ft_step,
                            &im->gdes[i].start,
                            &im->gdes[i].end,
@@ -838,7 +840,7 @@ data_calc( image_desc_t *im){
                        vdp->shift = im->gdes[gdi].shval;
 
                /* normalize shift to multiple of consolidated step */
-               vdp->shift = (vdp->shift / vdp->step) * vdp->step;
+               vdp->shift = (vdp->shift / (long)vdp->step) * (long)vdp->step;
 
                /* apply shift */
                vdp->start += vdp->shift;
@@ -934,8 +936,8 @@ 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;
-                       long    diff = im->gdes[gdi].start - im->gdes[ptr].start;
+                        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;
@@ -2570,13 +2572,7 @@ graph_paint(image_desc_t *im, char ***calcpr)
 int
 gdes_alloc(image_desc_t *im){
 
-    unsigned long def_step = (im->end-im->start)/im->xsize;
-    
-    if (im->step > def_step) /* step can be increassed ... no decreassed */
-      def_step = im->step;
-
     im->gdes_c++;
-    
     if ((im->gdes = (graph_desc_t *) rrd_realloc(im->gdes, (im->gdes_c)
                                           * sizeof(graph_desc_t)))==NULL){
        rrd_set_error("realloc graph_descs");
@@ -2584,7 +2580,7 @@ gdes_alloc(image_desc_t *im){
     }
 
 
-    im->gdes[im->gdes_c-1].step=def_step; 
+    im->gdes[im->gdes_c-1].step=im->step;
     im->gdes[im->gdes_c-1].stack=0;
     im->gdes[im->gdes_c-1].debug=0;
     im->gdes[im->gdes_c-1].start=im->start; 
@@ -3081,6 +3077,7 @@ rrd_graph_options(int argc, char *argv[],image_desc_t *im)
     
     im->start = start_tmp;
     im->end = end_tmp;
+    im->step = max((long)im->step, (im->end-im->start)/im->xsize);
 }
 
 int
index 607ab70..7cf2a6e 100644 (file)
@@ -104,6 +104,7 @@ typedef  struct graph_desc_t {
     char           ds_nam[DS_NAM_SIZE]; /* data source name */
     long           ds;         /* data source number */
     enum cf_en     cf;         /* consolidation function */
+    enum cf_en     cf_reduce;  /* consolidation function for reduce_data() */
     gfx_color_t    col;        /* graph color */
     char  format[FMT_LEG_LEN+5]; /* format for PRINT AND GPRINT */
     char  legend[FMT_LEG_LEN+5]; /* legend*/
index c359f7a..29bcb5d 100644 (file)
@@ -13,7 +13,7 @@
 int rrd_parse_find_gf (char *, unsigned int *, graph_desc_t *);
 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_CF      (char *, unsigned int *, graph_desc_t *, enum cf_en *);
 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 *);
@@ -98,7 +98,7 @@ rrd_parse_color(char *string, graph_desc_t *gdp) {
 }
 
 int
-rrd_parse_CF(char *line, unsigned int *eaten, graph_desc_t *gdp) {
+rrd_parse_CF(char *line, unsigned int *eaten, graph_desc_t *gdp, enum cf_en *cf) {
     char               symname[CF_NAM_SIZE];
     int                        i=0;
 
@@ -110,7 +110,7 @@ rrd_parse_CF(char *line, unsigned int *eaten, graph_desc_t *gdp) {
     (*eaten)+=i;
     dprintf("- using CF '%s'\n",symname);
 
-    if ((int)(gdp->cf = cf_conv(symname))==-1) {
+    if ((int)(*cf = cf_conv(symname))==-1) {
        rrd_set_error("Unknown CF '%s' in '%s'",symname,line);
        return 1;
     }
@@ -145,7 +145,7 @@ rrd_parse_print(char *line, unsigned int *eaten, graph_desc_t *gdp, image_desc_t
        case GF_DEF:
        case GF_CDEF:
            dprintf("- vname is of type DEF or CDEF, looking for CF\n");
-           if (rrd_parse_CF(line,eaten,gdp)) return 1;
+           if (rrd_parse_CF(line,eaten,gdp,&gdp->cf)) return 1;
            break;
        case GF_VDEF:
            dprintf("- vname is of type VDEF\n");
@@ -307,7 +307,7 @@ rrd_parse_PVHLAST(char *line, unsigned int *eaten, graph_desc_t *gdp, image_desc
     if (colorfound) { /* no legend if no color */
        if (gdp->gf == GF_TICK) {
            dprintf("- looking for optional number\n");
-           sscanf(&line[*eaten],"%lf:%n",&gdp->yrule,&j);
+           sscanf(&line[*eaten],"%lf%n",&gdp->yrule,&j);
            if (j) {
                dprintf("- found number %f\n",gdp->yrule);
                (*eaten)+=j;
@@ -315,6 +315,8 @@ rrd_parse_PVHLAST(char *line, unsigned int *eaten, graph_desc_t *gdp, image_desc
                    rrd_set_error("Tick factor should be <= 1.0");
                    return 1;
                }
+               if (line[*eaten] == ':')
+                   (*eaten)++;
            } else {
                dprintf("- not found, defaulting to 0.1\n");
                gdp->yrule=0.1;
@@ -379,7 +381,7 @@ rrd_parse_vname(char *line, unsigned int *eaten, graph_desc_t *gdp, image_desc_t
 int
 rrd_parse_def(char *line, unsigned int *eaten, graph_desc_t *gdp, image_desc_t *im) {
     int                        i=0;
-    char               command[6]; /* step, start, end */
+    char               command[7]; /* step, start, end, reduce */
     char               tmpstr[256];
     struct rrd_time_value      start_tv,end_tv;
     time_t             start_tmp=0,end_tmp=0;
@@ -411,21 +413,26 @@ rrd_parse_def(char *line, unsigned int *eaten, graph_desc_t *gdp, image_desc_t *
     (*eaten)+=i;
     dprintf("- using DS '%s'\n",gdp->ds_nam);
 
-    if (rrd_parse_CF(line,eaten,gdp)) return 1;
-
+    if (rrd_parse_CF(line,eaten,gdp,&gdp->cf)) return 1;
+    gdp->cf_reduce = gdp->cf;
+    
     if (line[*eaten]=='\0') return 0;
 
     while (1) {
        dprintf("- optional parameter follows: %s\n", &line[*eaten]);
        i=0;
-       sscanf(&line[*eaten], "%5[a-z]=%n", command, &i);
+       sscanf(&line[*eaten], "%6[a-z]=%n", command, &i);
        if (!i) {
            rrd_set_error("Parse error in '%s'",line);
            return 1;
        }
        (*eaten)+=i;
        dprintf("- processing '%s'\n",command);
-       if (!strcmp("step",command)) {
+       if (!strcmp("reduce",command)) {
+         if (rrd_parse_CF(line,eaten,gdp,&gdp->cf_reduce)) return 1;
+         if (line[*eaten] != '\0')
+             (*eaten)--;
+       } else if (!strcmp("step",command)) {
            i=0;
            sscanf(&line[*eaten],"%lu%n",&gdp->step,&i);
            (*eaten)+=i;
index 3e67af7..6b1648e 100644 (file)
@@ -170,8 +170,10 @@ rrd_resize(int argc, char **argv)
     }
     /* Move the rest of the CDPs
     */
-    while (!(feof(infile))) {
-        fread(&buffer,sizeof(rrd_value_t),1,infile);
+    while (1) {
+       fread(&buffer,sizeof(rrd_value_t),1,infile);
+       if (feof(infile))
+           break;
         fwrite(&buffer,sizeof(rrd_value_t),1,outfile);
     }
     rrdnew.rra_def[target_rra].row_cnt += modify;
index 75c24cf..3cd582b 100644 (file)
@@ -157,7 +157,7 @@ void rpn_compact2str(rpn_cdefds_t *rpnc,ds_def_t *ds_def,char **str)
          add_op(OP_SQRT,SQRT)
          add_op(OP_SORT,SORT)
          add_op(OP_REV,REV)
-
+         add_op(OP_TREND,TREND)
 #undef add_op
               }
     (*str)[offset] = '\0';
@@ -319,7 +319,7 @@ rpn_parse(void *key_hash,char *expr,long (*lookup)(void *,char*)){
        match_op(OP_NEGINF,NEGINF)
        match_op(OP_NE,NE)
        match_op(OP_COUNT,COUNT)
-         match_op_param(OP_PREV_OTHER,PREV)
+       match_op_param(OP_PREV_OTHER,PREV)
        match_op(OP_PREV,PREV)
        match_op(OP_INF,INF)
        match_op(OP_ISINF,ISINF)
@@ -329,6 +329,7 @@ rpn_parse(void *key_hash,char *expr,long (*lookup)(void *,char*)){
        match_op(OP_SQRT,SQRT)
        match_op(OP_SORT,SORT)
        match_op(OP_REV,REV)
+       match_op(OP_TREND,TREND)
 #undef match_op
 
 
@@ -705,6 +706,29 @@ rpn_calc(rpnp_t *rpnp, rpnstack_t *rpnstack, long data_idx,
                    }
                }
                break;
+           case OP_TREND:
+               stackunderflow(1);
+               if ((rpi < 2) || (rpnp[rpi-2].op != OP_VARIABLE)) {
+                   rrd_set_error("malformed trend arguments");
+                   return -1;
+               } else {
+                   time_t dur = (time_t)rpnstack -> s[stptr];
+                   time_t step = (time_t)rpnp[rpi-2].step;
+
+                   if (output_idx > (int)ceil((float)dur / (float)step)) {
+                       double accum = 0.0;
+                       int i = 0;
+               
+                       do {
+                           accum += rpnp[rpi-2].data[rpnp[rpi-2].ds_cnt * i--];
+                           dur -= step;
+                       } while (dur > 0);
+
+                       rpnstack -> s[--stptr] = (accum / -i);
+                   } else
+                       rpnstack -> s[--stptr] = DNAN;
+               }
+               break;
            case OP_END:
                break;
        }
index 9fd547a..39909a6 100644 (file)
@@ -16,7 +16,7 @@ enum op_en {OP_NUMBER=0,OP_VARIABLE,OP_INF,OP_PREV,OP_NEGINF,
            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_SQRT,OP_SORT,OP_REV};
+           OP_ATAN,OP_SQRT,OP_SORT,OP_REV,OP_TREND};
 
 typedef struct rpnp_t {
     enum op_en   op;
index 95bf35b..3ba1b52 100644 (file)
@@ -116,7 +116,8 @@ rrd_xport(int argc, char **argv, int *xsize,
     
     im.start = start_tmp;
     im.end = end_tmp;
-
+    im.step = max((long)im.step, (im.end-im.start)/im.xsize);
+    
     rrd_graph_script(argc,argv,&im,0);
     if (rrd_test_error()) {
        im_free(&im);