index d1ab0dea2a95b2942659055a76239dd92f8a61be..b563db40a8c5154c96dfb57badec4379187fd334 100644 (file)
/****************************************************************************
- * RRDtool 1.2.23 Copyright by Tobi Oetiker, 1997-2007
+ * RRDtool 1.4.3 Copyright by Tobi Oetiker, 1997-2010
****************************************************************************
* rrd_rpncalc.c RPN calculator functions
****************************************************************************/
+#include <limits.h>
+#include <locale.h>
+#include <stdlib.h>
+
#include "rrd_tool.h"
#include "rrd_rpncalc.h"
-#include "rrd_graph.h"
-#include <limits.h>
+// #include "rrd_graph.h"
short addop2str(
enum op_en op,
time_t); /* used to implement LTIME */
short rpn_compact(
- rpnp_t * rpnp,
- rpn_cdefds_t ** rpnc,
+ rpnp_t *rpnp,
+ rpn_cdefds_t **rpnc,
short *count)
{
short i;
}
rpnp_t *rpn_expand(
- rpn_cdefds_t * rpnc)
+ rpn_cdefds_t *rpnc)
{
short i;
rpnp_t *rpnp;
/* DS_CDEF_MAX_RPN_NODES is small, so at the expense of some wasted
* memory we avoid any reallocs */
rpnp = (rpnp_t *) calloc(DS_CDEF_MAX_RPN_NODES, sizeof(rpnp_t));
- if (rpnp == NULL)
+ if (rpnp == NULL) {
+ rrd_set_error("failed allocating rpnp array");
return NULL;
+ }
for (i = 0; rpnc[i].op != OP_END; ++i) {
- rpnp[i].op = (long) rpnc[i].op;
+ rpnp[i].op = (op_en)rpnc[i].op;
if (rpnp[i].op == OP_NUMBER) {
rpnp[i].val = (double) rpnc[i].val;
} else if (rpnp[i].op == OP_VARIABLE || rpnp[i].op == OP_PREV_OTHER) {
* str: out string, memory is allocated by the function, must be freed by the
* the caller */
void rpn_compact2str(
- rpn_cdefds_t * rpnc,
- ds_def_t * ds_def,
+ rpn_cdefds_t *rpnc,
+ ds_def_t *ds_def,
char **str)
{
unsigned short i, offset = 0;
(*str)[offset++] = ',';
#define add_op(VV,VVV) \
- if (addop2str(rpnc[i].op, VV, VVV, str, &offset) == 1) continue;
+ if (addop2str((enum op_en)(rpnc[i].op), VV, VVV, str, &offset) == 1) continue;
if (rpnc[i].op == OP_NUMBER) {
/* convert a short into a string */
#undef add_op
#define add_op(VV,VVV) \
- if (addop2str(rpnc[i].op, VV, #VVV, str, &offset) == 1) continue;
+ if (addop2str((enum op_en)rpnc[i].op, VV, #VVV, str, &offset) == 1) continue;
add_op(OP_ADD, +)
add_op(OP_SUB, -)
add_op(OP_SORT, SORT)
add_op(OP_REV, REV)
add_op(OP_TREND, TREND)
+ add_op(OP_TRENDNAN, TRENDNAN)
+ add_op(OP_PREDICT, PREDICT)
+ add_op(OP_PREDICTSIGMA, PREDICTSIGMA)
add_op(OP_RAD2DEG, RAD2DEG)
add_op(OP_DEG2RAD, DEG2RAD)
add_op(OP_AVG, AVG)
add_op(OP_ABS, ABS)
+ add_op(OP_ADDNAN, ADDNAN)
#undef add_op
}
(*str)[offset] = '\0';
rpnp_t *rpn_parse(
void *key_hash,
const char *const expr_const,
- long (*lookup) (void *,
- char *))
+ long (*lookup) (void *,
+ char *))
{
int pos = 0;
char *expr;
long steps = -1;
rpnp_t *rpnp;
char vname[MAX_VNAME_LEN + 10];
+ char *old_locale;
+
+ old_locale = setlocale(LC_NUMERIC, "C");
rpnp = NULL;
expr = (char *) expr_const;
while (*expr) {
if ((rpnp = (rpnp_t *) rrd_realloc(rpnp, (++steps + 2) *
sizeof(rpnp_t))) == NULL) {
+ setlocale(LC_NUMERIC, old_locale);
return NULL;
}
else if (strncmp(expr, #VVV, strlen(#VVV))==0 && ( expr[strlen(#VVV)] == ',' || expr[strlen(#VVV)] == '\0' )){ \
rpnp[steps].op = VV; \
expr+=strlen(#VVV); \
- }
-
+ }
#define match_op_param(VV,VVV) \
else if (sscanf(expr, #VVV "(" DEF_NAM_FMT ")",vname) == 1) { \
match_op(OP_SORT, SORT)
match_op(OP_REV, REV)
match_op(OP_TREND, TREND)
+ match_op(OP_TRENDNAN, TRENDNAN)
+ match_op(OP_PREDICT, PREDICT)
+ match_op(OP_PREDICTSIGMA, PREDICTSIGMA)
match_op(OP_RAD2DEG, RAD2DEG)
match_op(OP_DEG2RAD, DEG2RAD)
match_op(OP_AVG, AVG)
match_op(OP_ABS, ABS)
+ match_op(OP_ADDNAN, ADDNAN)
#undef match_op
else if ((sscanf(expr, DEF_NAM_FMT "%n", vname, &pos) == 1)
&& ((rpnp[steps].ptr = (*lookup) (key_hash, vname)) !=
}
else {
+ setlocale(LC_NUMERIC, old_locale);
free(rpnp);
return NULL;
}
+
if (*expr == 0)
break;
if (*expr == ',')
expr++;
else {
+ setlocale(LC_NUMERIC, old_locale);
free(rpnp);
return NULL;
}
}
rpnp[steps + 1].op = OP_END;
+ setlocale(LC_NUMERIC, old_locale);
return rpnp;
}
void rpnstack_init(
- rpnstack_t * rpnstack)
+ rpnstack_t *rpnstack)
{
rpnstack->s = NULL;
rpnstack->dc_stacksize = 0;
}
void rpnstack_free(
- rpnstack_t * rpnstack)
+ rpnstack_t *rpnstack)
{
if (rpnstack->s != NULL)
free(rpnstack->s);
* 0 on success
*/
short rpn_calc(
- rpnp_t * rpnp,
- rpnstack_t * rpnstack,
+ rpnp_t *rpnp,
+ rpnstack_t *rpnstack,
long data_idx,
- rrd_value_t * output,
+ rrd_value_t *output,
int output_idx)
{
int rpi;
if (stptr + 5 > rpnstack->dc_stacksize) {
/* could move this to a separate function */
rpnstack->dc_stacksize += rpnstack->dc_stackblock;
- rpnstack->s = rrd_realloc(rpnstack->s,
+ rpnstack->s = (double*)rrd_realloc(rpnstack->s,
(rpnstack->dc_stacksize) *
sizeof(*(rpnstack->s)));
if (rpnstack->s == NULL) {
+ rpnstack->s[stptr];
stptr--;
break;
+ case OP_ADDNAN:
+ stackunderflow(1);
+ if (isnan(rpnstack->s[stptr - 1])) {
+ rpnstack->s[stptr - 1] = rpnstack->s[stptr];
+ } else if (isnan(rpnstack->s[stptr])) {
+ /* NOOP */
+ /* rpnstack->s[stptr - 1] = rpnstack->s[stptr - 1]; */
+ } else {
+ rpnstack->s[stptr - 1] = rpnstack->s[stptr - 1]
+ + rpnstack->s[stptr];
+ }
+
+ stptr--;
+ break;
case OP_SUB:
stackunderflow(1);
rpnstack->s[stptr - 1] = rpnstack->s[stptr - 1]
break;
case OP_IF:
stackunderflow(2);
- rpnstack->s[stptr - 2] = rpnstack->s[stptr - 2] != 0.0 ?
- rpnstack->s[stptr - 1] : rpnstack->s[stptr];
+ rpnstack->s[stptr - 2] = (isnan(rpnstack->s[stptr - 2])
+ || rpnstack->s[stptr - 2] ==
+ 0.0) ? rpnstack->s[stptr] : rpnstack->
+ s[stptr - 1];
stptr--;
stptr--;
break;
}
}
break;
+ case OP_PREDICT:
+ case OP_PREDICTSIGMA:
+ stackunderflow(2);
+ {
+ /* the local averaging window (similar to trend, but better here, as we get better statistics thru numbers)*/
+ int locstepsize = rpnstack->s[--stptr];
+ /* the number of shifts and range-checking*/
+ int shifts = rpnstack->s[--stptr];
+ stackunderflow(shifts);
+ // handle negative shifts special
+ if (shifts<0) {
+ stptr--;
+ } else {
+ stptr-=shifts;
+ }
+ /* the real calculation */
+ double val=DNAN;
+ /* the info on the datasource */
+ time_t dsstep = (time_t) rpnp[rpi - 1].step;
+ int dscount = rpnp[rpi - 1].ds_cnt;
+ int locstep = (int)ceil((float)locstepsize/(float)dsstep);
+
+ /* the sums */
+ double sum = 0;
+ double sum2 = 0;
+ int count = 0;
+ /* now loop for each position */
+ int doshifts=shifts;
+ if (shifts<0) { doshifts=-shifts; }
+ for(int loop=0;loop<doshifts;loop++) {
+ /* calculate shift step */
+ int shiftstep=1;
+ if (shifts<0) {
+ shiftstep = loop*rpnstack->s[stptr];
+ } else {
+ shiftstep = rpnstack->s[stptr+loop];
+ }
+ if(shiftstep <0) {
+ rrd_set_error("negative shift step not allowed: %i",shiftstep);
+ return -1;
+ }
+ shiftstep=(int)ceil((float)shiftstep/(float)dsstep);
+ /* loop all local shifts */
+ for(int i=0;i<=locstep;i++) {
+ /* now calculate offset into data-array - relative to output_idx*/
+ int offset=shiftstep+i;
+ /* and process if we have index 0 of above */
+ if ((offset>=0)&&(offset<output_idx)) {
+ /* get the value */
+ val =rpnp[rpi - 1].data[-dscount * offset];
+ /* and handle the non NAN case only*/
+ if (! isnan(val)) {
+ sum+=val;
+ sum2+=val*val;
+ count++;
+ }
+ }
+ }
+ }
+ /* do the final calculations */
+ val=DNAN;
+ if (rpnp[rpi].op == OP_PREDICT) { /* the average */
+ if (count>0) {
+ val = sum/(double)count;
+ }
+ } else {
+ if (count>1) { /* the sigma case */
+ val=count*sum2-sum*sum;
+ if (val<0) {
+ val=DNAN;
+ } else {
+ val=sqrt(val/((float)count*((float)count-1.0)));
+ }
+ }
+ }
+ rpnstack->s[stptr] = val;
+ }
+ break;
case OP_TREND:
+ case OP_TRENDNAN:
stackunderflow(1);
if ((rpi < 2) || (rpnp[rpi - 2].op != OP_VARIABLE)) {
rrd_set_error("malformed trend arguments");
time_t step = (time_t) rpnp[rpi - 2].step;
if (output_idx > (int) ceil((float) dur / (float) step)) {
+ int ignorenan = (rpnp[rpi].op == OP_TREND);
double accum = 0.0;
int i = 0;
+ int count = 0;
do {
- accum +=
+ double val =
rpnp[rpi - 2].data[rpnp[rpi - 2].ds_cnt * i--];
+ if (ignorenan || !isnan(val)) {
+ accum += val;
+ ++count;
+ }
+
dur -= step;
} while (dur > 0);
- rpnstack->s[--stptr] = (accum / -i);
+ rpnstack->s[--stptr] =
+ (count == 0) ? DNAN : (accum / count);
} else
rpnstack->s[--stptr] = DNAN;
}