summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: f99ffdd)
raw | patch | inline | side by side (parent: f99ffdd)
author | oetiker <oetiker@a5681a0c-68f1-0310-ab6d-d61299d08faa> | |
Fri, 5 Jul 2002 18:57:02 +0000 (18:57 +0000) | ||
committer | oetiker <oetiker@a5681a0c-68f1-0310-ab6d-d61299d08faa> | |
Fri, 5 Jul 2002 18:57:02 +0000 (18:57 +0000) |
diff --git a/doc/cdeftutorial.pod b/doc/cdeftutorial.pod
index fe580634e25032e1dc085c6c1407bebb9f5c9975..101f1c9d0f70317524c08aa74fb079949e643cb1 100644 (file)
--- a/doc/cdeftutorial.pod
+++ b/doc/cdeftutorial.pod
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
diff --git a/doc/rrdgraph_rpn.src b/doc/rrdgraph_rpn.src
index 8b5d49bbf92a842af2e74501717cca1d1ef5c4e1..a8c4b112634c76fd92236e71eac8bde6a12dab95 100644 (file)
--- a/doc/rrdgraph_rpn.src
+++ b/doc/rrdgraph_rpn.src
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
diff --git a/src/rrd_graph.c b/src/rrd_graph.c
index 80c4d0ffc4da8f913ca9c779f46e020a4e45a398..18be57376507aada5ab24a74e34d1d3a8748a120 100644 (file)
--- a/src/rrd_graph.c
+++ b/src/rrd_graph.c
* 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;
/* 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;
diff --git a/src/rrd_rpncalc.c b/src/rrd_rpncalc.c
index ab2bd36ca909797973d37ac864189a2b5b214e88..3c7ccb81ac6f2f518c748c33396ef3e065b3badc 100644 (file)
--- a/src/rrd_rpncalc.c
+++ b/src/rrd_rpncalc.c
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;
}
}
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;
}
}
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) \
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,*)
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)
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;
diff --git a/src/rrd_rpncalc.h b/src/rrd_rpncalc.h
index 4796695c20c6cdb90be6367511a5415ef7bf609a..915c949bae429cf2bb024e6dd3b40f4425973c19 100644 (file)
--- a/src/rrd_rpncalc.h
+++ b/src/rrd_rpncalc.h
* 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,