new operand on rrdgraph CDEFs: PREV(xxxx) -- Gonzalo Augusto Arana Tagle <garana...
authoroetiker <oetiker@a5681a0c-68f1-0310-ab6d-d61299d08faa>
Fri, 5 Jul 2002 18:57:02 +0000 (18:57 +0000)
committeroetiker <oetiker@a5681a0c-68f1-0310-ab6d-d61299d08faa>
Fri, 5 Jul 2002 18:57:02 +0000 (18:57 +0000)
git-svn-id: svn://svn.oetiker.ch/rrdtool/trunk/program@156 a5681a0c-68f1-0310-ab6d-d61299d08faa

doc/cdeftutorial.pod
doc/rrdgraph_rpn.src
src/rrd_graph.c
src/rrd_rpncalc.c
src/rrd_rpncalc.h

index fe58063..101f1c9 100644 (file)
@@ -838,6 +838,31 @@ the other half of your graph. This can be done in a relatively simple
 way: what you need is the "wipeout" variable and place a negative
 sign before it:  "CDEF:wipeout2=wipeout,-1,*"
     
+=head2 Filtering data
+
+You may do some complex data filtering:
+
+  MEDIAN FILTER: filters shot noise
+
+    DEF:var=database.rrd:traffic:AVERAGE
+    CDEF:prev1=PREV(var)
+    CDEF:prev2=PREV(prev1)
+    CDEF:prev3=PREV(prev2)
+    CDEF:median=prev1,prev2,prev3,+,+,3,/
+    LINE3:median#000077:filtered
+    LINE1:prev2#007700:'raw data'
+
+
+  DERIVATE:
+
+    DEF:var=database.rrd:traffic:AVERAGE
+    CDEF:prev1=PREV(var)
+    CDEF:time=TIME
+    CDEF:prevtime=PREV(time)
+    CDEF:derivate=var,prev1,-,time,prevtime,-,/
+    LINE3:derivate#000077:derivate
+    LINE1:var#007700:'raw data'
+
 =head1 Out of ideas for now
 
 This document was created from questions asked by either myself or
index 8b5d49b..a8c4b11 100644 (file)
@@ -123,6 +123,13 @@ set or otherwise the result of this B<CDEF> at the previous time
 step. This allows you to do calculations across the data.  This
 function cannot be used in B<VDEF> instructions.
 
+B<PREV(vname)>
+
+Pushes an I<unknown> value if this is the first value of a data
+set or otherwise the result of vname variable at the previous time
+step. This allows you to do calculations across the data.  This
+function cannot be used in B<VDEF> instructions.
+
 Z<>
 
 =item Time
index 80c4d0f..18be573 100644 (file)
@@ -853,19 +853,22 @@ data_calc( image_desc_t *im){
                 *   resulting data source.
                 */
                for(rpi=0;im->gdes[gdi].rpnp[rpi].op != OP_END;rpi++){
-                   if(im->gdes[gdi].rpnp[rpi].op == OP_VARIABLE){
+               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[ptr].ds_cnt == 0) {
 #if 0
-printf("DEBUG: inside CDEF '%s' processing VDEF '%s'\n",
+                       printf("DEBUG: inside CDEF '%s' processing VDEF '%s'\n",
        im->gdes[gdi].vname,
        im->gdes[ptr].vname);
-printf("DEBUG: value from vdef is %f\n",im->gdes[ptr].vf.val);
+                       printf("DEBUG: value from vdef is %f\n",im->gdes[ptr].vf.val);
 #endif
                            im->gdes[gdi].rpnp[rpi].val = im->gdes[ptr].vf.val;
                            im->gdes[gdi].rpnp[rpi].op  = OP_NUMBER;
                        } else {
-                           if ((steparray = rrd_realloc(steparray, (++stepcnt+1)*sizeof(*steparray)))==NULL){
+                       if ((steparray =
+                                rrd_realloc(steparray,
+                                                        (++stepcnt+1)*sizeof(*steparray)))==NULL){
                                rrd_set_error("realloc steparray");
                                rpnstack_free(&rpnstack);
                                return -1;
@@ -904,7 +907,8 @@ printf("DEBUG: value from vdef is %f\n",im->gdes[ptr].vf.val);
 
                 /* move the data pointers to the correct period */
                 for(rpi=0;im->gdes[gdi].rpnp[rpi].op != OP_END;rpi++){
-                    if(im->gdes[gdi].rpnp[rpi].op == OP_VARIABLE){
+               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;
index ab2bd36..3c7ccb8 100644 (file)
@@ -40,7 +40,8 @@ short rpn_compact(rpnp_t *rpnp, rpn_cdefds_t **rpnc, short *count)
                 return -1;
             }
             (*rpnc)[i].val = (short) temp;
-        } else if (rpnp[i].op == OP_VARIABLE) {
+         } else if (rpnp[i].op == OP_VARIABLE ||
+                                rpnp[i].op == OP_PREV_OTHER) {
             (*rpnc)[i].val = (short) rpnp[i].ptr;
         }
     }
@@ -63,7 +64,8 @@ rpnp_t * rpn_expand(rpn_cdefds_t *rpnc)
         rpnp[i].op = (long) rpnc[i].op;
         if (rpnp[i].op == OP_NUMBER) {
             rpnp[i].val = (double) rpnc[i].val;
-        } else if (rpnp[i].op == OP_VARIABLE) {
+         } else if (rpnp[i].op == OP_VARIABLE ||
+                                rpnp[i].op == OP_PREV_OTHER) {
             rpnp[i].ptr = (long) rpnc[i].val;
         }
     }
@@ -106,6 +108,12 @@ void rpn_compact2str(rpn_cdefds_t *rpnc,ds_def_t *ds_def,char **str)
             char *ds_name = ds_def[rpnc[i].val].ds_nam;
             add_op(OP_VARIABLE, ds_name)
                 }
+
+         if (rpnc[i].op == OP_PREV_OTHER) {
+               char *ds_name = ds_def[rpnc[i].val].ds_nam;
+               add_op(OP_VARIABLE, ds_name)
+         }
+
 #undef add_op
         
 #define add_op(VV,VVV) \
@@ -261,6 +269,21 @@ rpn_parse(void *key_hash,char *expr,long (*lookup)(void *,char*)){
            expr+=strlen(#VVV); \
        }
 
+
+#define match_op_param(VV,VVV) \
+        else if (sscanf(expr, #VVV "(%[a-z0-9]s)",vname) == 1) { \
+          int length = 0; \
+          if ((length = strlen(#VVV)+strlen(vname)+2, \
+              expr[length] == ',' || expr[length] == '\0') ) { \
+             rpnp[steps].op = VV; \
+             rpnp[steps].ptr = (*lookup)(key_hash,vname); \
+             if (rpnp[steps].ptr < 0) { \
+                          free(rpnp); \
+                          return NULL; \
+                        } else expr+=length; \
+          } \
+        }
+
        match_op(OP_ADD,+)
        match_op(OP_SUB,-)
        match_op(OP_MUL,*)
@@ -289,6 +312,7 @@ rpn_parse(void *key_hash,char *expr,long (*lookup)(void *,char*)){
        match_op(OP_UN,UN)
        match_op(OP_NEGINF,NEGINF)
        match_op(OP_NE,NE)
+         match_op_param(OP_PREV_OTHER,PREV)
        match_op(OP_PREV,PREV)
        match_op(OP_INF,INF)
        match_op(OP_ISINF,ISINF)
@@ -410,6 +434,13 @@ rpn_calc(rpnp_t *rpnp, rpnstack_t *rpnstack, long data_idx,
                    rpnstack -> s[++stptr] = output[output_idx-1];
                }
                break;
+       case OP_PREV_OTHER:
+         if ((output_idx-1) <= 0) {
+               rpnstack -> s[++stptr] = DNAN;
+         } else {
+               rpnstack -> s[++stptr] = rpnp[rpnp[rpi].ptr].data[output_idx-1];
+         }
+         break;
            case OP_UNKN:
                rpnstack -> s[++stptr] = DNAN; 
                break;
index 4796695..915c949 100644 (file)
@@ -8,7 +8,7 @@
  * This is because COMPUTE (CDEF) DS store OP nodes by number (name is not
  * an option due to limited par array size). OP nodes must have the same
  * numeric values, otherwise the stored numbers will mean something different. */
-enum op_en {OP_NUMBER=0,OP_VARIABLE,OP_INF,OP_PREV,OP_NEGINF,
+enum op_en {OP_NUMBER=0,OP_VARIABLE,OP_INF,OP_PREV,OP_PREV_OTHER,OP_NEGINF,
            OP_UNKN,OP_NOW,OP_TIME,OP_ADD,OP_MOD,OP_SUB,OP_MUL,
            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,