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
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
* 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;
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;
* 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,