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
=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>
=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
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
Z<>
-=item Ordering Operations
+=item Set Operations
B<SORT, REV>
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>
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)) {
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,
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;
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;
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");
}
- 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;
im->start = start_tmp;
im->end = end_tmp;
+ im->step = max((long)im->step, (im->end-im->start)/im->xsize);
}
int
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*/
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 *);
}
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;
(*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;
}
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");
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;
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;
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;
(*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;
}
/* 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;
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';
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)
match_op(OP_SQRT,SQRT)
match_op(OP_SORT,SORT)
match_op(OP_REV,REV)
+ match_op(OP_TREND,TREND)
#undef match_op
}
}
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;
}
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;
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);