X-Git-Url: https://git.octo.it/?p=rrdtool.git;a=blobdiff_plain;f=src%2Frrd_hw.c;h=0ffb64b40e524582b9fb50d55d1f4e74cde4aac1;hp=85b4fd71e444ba0fb230fbcb0298deb05cde5776;hb=f207955a7e325708d056d3dd912863dc9930a71c;hpb=7c016dfa001ae254bf4e18126f814ee8f0abd821 diff --git a/src/rrd_hw.c b/src/rrd_hw.c index 85b4fd7..0ffb64b 100644 --- a/src/rrd_hw.c +++ b/src/rrd_hw.c @@ -1,17 +1,18 @@ /***************************************************************************** - * RRDtool 1.0.21 Copyright Tobias Oetiker, 1997 - 2000 + * RRDtool 1.2rc6 Copyright by Tobi Oetiker, 1997-2005 ***************************************************************************** - * rrd_hw.c + * rrd_hw.c : Support for Holt-Winters Smoothing/ Aberrant Behavior Detection ***************************************************************************** * Initial version by Jake Brutlag, WebTV Networks, 5/1/00 *****************************************************************************/ #include "rrd_tool.h" +#include "rrd_hw.h" /* #define DEBUG */ +/* private functions */ unsigned long MyMod(signed long val, unsigned long mod); - int update_hwpredict(rrd_t *rrd, unsigned long cdp_idx, unsigned long rra_idx, unsigned long ds_idx, unsigned short CDP_scratch_idx); int update_seasonal(rrd_t *rrd, unsigned long cdp_idx, unsigned long rra_idx, @@ -352,12 +353,12 @@ update_devseasonal(rrd_t *rrd, unsigned long cdp_idx, unsigned long rra_idx, fprintf(stderr,"Initialization of seasonal deviation\n"); #endif rrd -> cdp_prep[cdp_idx].scratch[CDP_scratch_idx].u_val = - abs(prediction - rrd -> cdp_prep[cdp_idx].scratch[CDP_scratch_idx].u_val); + fabs(prediction - rrd -> cdp_prep[cdp_idx].scratch[CDP_scratch_idx].u_val); } else { /* exponential smoothing update */ rrd -> cdp_prep[cdp_idx].scratch[CDP_scratch_idx].u_val = (rrd -> rra_def[rra_idx].par[RRA_seasonal_gamma].u_val)* - abs(prediction - rrd -> cdp_prep[cdp_idx].scratch[CDP_scratch_idx].u_val) + fabs(prediction - rrd -> cdp_prep[cdp_idx].scratch[CDP_scratch_idx].u_val) + (1 - rrd -> rra_def[rra_idx].par[RRA_seasonal_gamma].u_val)* (rrd -> cdp_prep[cdp_idx].scratch[CDP_last_seasonal_deviation].u_val); } @@ -442,9 +443,6 @@ update_failures(rrd_t *rrd, unsigned long cdp_idx, unsigned long rra_idx, /* determine if a failure has occurred and update the failure array */ violation_cnt = violation; - /* WARNING: this cast makes XML files non-portable across platforms, - * because an array of longs on disk is treated as an array of chars - * in memory. */ violations_array = (char *) ((void *) rrd -> cdp_prep[cdp_idx].scratch); for (i = current_rra -> par[RRA_window_len].u_cnt; i > 1; i--) { @@ -478,7 +476,7 @@ erase_violations(rrd_t *rrd, unsigned long cdp_idx, unsigned long rra_idx) fprintf(stderr,"erase_violations called for non-FAILURES RRA: %s\n", rrd -> rra_def[rra_idx].cf); #endif - return; + return; } #ifdef DEBUG @@ -490,12 +488,11 @@ erase_violations(rrd_t *rrd, unsigned long cdp_idx, unsigned long rra_idx) fprintf(stderr,"\n"); #endif - /* WARNING: this cast makes XML files non-portable across platforms, - * because an array of longs on disk is treated as an array of chars - * in memory. */ + /* WARNING: an array of longs on disk is treated as an array of chars + * in memory. */ violations_array = (char *) ((void *) rrd -> cdp_prep[cdp_idx].scratch); /* erase everything in the part of the CDP scratch array that will be - * used to store violations for the current window */ + * used to store violations for the current window */ for (i = rrd -> rra_def[rra_idx].par[RRA_window_len].u_cnt; i > 0; i--) { violations_array[i-1] = 0; @@ -524,6 +521,7 @@ apply_smoother(rrd_t *rrd, unsigned long rra_idx, unsigned long rra_start, unsigned long offset; FIFOqueue **buffers; rrd_value_t *working_average; + rrd_value_t *baseline; offset = floor(0.025*row_count); if (offset == 0) return 0; /* no smoothing */ @@ -572,6 +570,7 @@ apply_smoother(rrd_t *rrd, unsigned long rra_idx, unsigned long rra_start, } /* need working average initialized to 0 */ working_average = (rrd_value_t *) calloc(row_length,sizeof(rrd_value_t)); + baseline = (rrd_value_t *) calloc(row_length,sizeof(rrd_value_t)); /* compute sums of the first 2*offset terms */ for (i = 0; i < 2*offset; ++i) @@ -599,19 +598,57 @@ apply_smoother(rrd_t *rrd, unsigned long rra_idx, unsigned long rra_start, /* overwrite rdd_values entry, the old value is already * saved in buffers */ rrd_values[k*row_length + j] = working_average[j]/(2*offset + 1); + baseline[j] += rrd_values[k*row_length + j]; /* remove a term from the sum */ working_average[j] -= queue_pop(buffers[j]); } } - + for (i = 0; i < row_length; ++i) { queue_dealloc(buffers[i]); + baseline[i] /= row_count; } free(buffers); free(working_average); + if (cf_conv(rrd->rra_def[rra_idx].cf_nam) == CF_SEASONAL) { + for (j = 0; j < row_length; ++j) + { + for (i = 0; i < row_count; ++i) + { + rrd_values[i*row_length + j] -= baseline[j]; + } + /* update the baseline coefficient, + * first, compute the cdp_index. */ + offset = (rrd->rra_def[rra_idx].par[RRA_dependent_rra_idx].u_cnt) + * row_length + j; + (rrd->cdp_prep[offset]).scratch[CDP_hw_intercept].u_val += baseline[j]; + } + /* flush cdp to disk */ + fflush(rrd_file); + if (fseek(rrd_file,sizeof(stat_head_t) + + rrd->stat_head->ds_cnt * sizeof(ds_def_t) + + rrd->stat_head->rra_cnt * sizeof(rra_def_t) + + sizeof(live_head_t) + + rrd->stat_head->ds_cnt * sizeof(pdp_prep_t),SEEK_SET)) + { + rrd_set_error("apply_smoother: seek to cdp_prep failed"); + free(rrd_values); + return -1; + } + if (fwrite( rrd -> cdp_prep, + sizeof(cdp_prep_t), + (rrd->stat_head->rra_cnt) * rrd->stat_head->ds_cnt, rrd_file) + != (rrd->stat_head->rra_cnt) * (rrd->stat_head->ds_cnt) ) + { + rrd_set_error("apply_smoother: cdp_prep write failed"); + free(rrd_values); + return -1; + } + } /* endif CF_SEASONAL */ + /* flush updated values to disk */ fflush(rrd_file); if (fseek(rrd_file,rra_start,SEEK_SET)) @@ -622,7 +659,7 @@ apply_smoother(rrd_t *rrd, unsigned long rra_idx, unsigned long rra_start, } /* write as a single block */ if (fwrite(rrd_values,sizeof(rrd_value_t),row_length*row_count,rrd_file) - != row_length*row_count) + != row_length*row_count) { rrd_set_error("apply_smoother: write failed to %lu",rra_start); free(rrd_values); @@ -631,9 +668,101 @@ apply_smoother(rrd_t *rrd, unsigned long rra_idx, unsigned long rra_start, fflush(rrd_file); free(rrd_values); + free(baseline); return 0; } +/* Reset aberrant behavior model coefficients, including intercept, slope, + * seasonal, and seasonal deviation for the specified data source. */ +void +reset_aberrant_coefficients(rrd_t *rrd, FILE *rrd_file, unsigned long ds_idx) +{ + unsigned long cdp_idx, rra_idx, i; + unsigned long cdp_start, rra_start; + rrd_value_t nan_buffer = DNAN; + + /* compute the offset for the cdp area */ + cdp_start = sizeof(stat_head_t) + + rrd->stat_head->ds_cnt * sizeof(ds_def_t) + + rrd->stat_head->rra_cnt * sizeof(rra_def_t) + + sizeof(live_head_t) + + rrd->stat_head->ds_cnt * sizeof(pdp_prep_t); + /* compute the offset for the first rra */ + rra_start = cdp_start + + (rrd->stat_head->ds_cnt) * (rrd->stat_head->rra_cnt) * sizeof(cdp_prep_t) + + rrd->stat_head->rra_cnt * sizeof(rra_ptr_t); + + /* loop over the RRAs */ + for (rra_idx = 0; rra_idx < rrd -> stat_head -> rra_cnt; rra_idx++) + { + cdp_idx = rra_idx * (rrd-> stat_head-> ds_cnt) + ds_idx; + switch (cf_conv(rrd -> rra_def[rra_idx].cf_nam)) + { + case CF_HWPREDICT: + init_hwpredict_cdp(&(rrd -> cdp_prep[cdp_idx])); + break; + case CF_SEASONAL: + case CF_DEVSEASONAL: + /* don't use init_seasonal because it will reset burn-in, which + * means different data sources will be calling for the smoother + * at different times. */ + rrd->cdp_prep[cdp_idx].scratch[CDP_hw_seasonal].u_val = DNAN; + rrd->cdp_prep[cdp_idx].scratch[CDP_hw_last_seasonal].u_val = DNAN; + /* move to first entry of data source for this rra */ + fseek(rrd_file,rra_start + ds_idx * sizeof(rrd_value_t),SEEK_SET); + /* entries for the same data source are not contiguous, + * temporal entries are contiguous */ + for (i = 0; i < rrd->rra_def[rra_idx].row_cnt; ++i) + { + if (fwrite(&nan_buffer,sizeof(rrd_value_t),1,rrd_file) != 1) + { + rrd_set_error( + "reset_aberrant_coefficients: write failed data source %lu rra %s", + ds_idx,rrd->rra_def[rra_idx].cf_nam); + return; + } + fseek(rrd_file,(rrd->stat_head->ds_cnt - 1) * + sizeof(rrd_value_t),SEEK_CUR); + } + break; + case CF_FAILURES: + erase_violations(rrd,cdp_idx,rra_idx); + break; + default: + break; + } + /* move offset to the next rra */ + rra_start += rrd->rra_def[rra_idx].row_cnt * rrd->stat_head->ds_cnt * + sizeof(rrd_value_t); + } + fseek(rrd_file,cdp_start,SEEK_SET); + if (fwrite( rrd -> cdp_prep, + sizeof(cdp_prep_t), + (rrd->stat_head->rra_cnt) * rrd->stat_head->ds_cnt, rrd_file) + != (rrd->stat_head->rra_cnt) * (rrd->stat_head->ds_cnt) ) + { + rrd_set_error("reset_aberrant_coefficients: cdp_prep write failed"); + return; + } +} + +void init_hwpredict_cdp(cdp_prep_t *cdp) +{ + cdp->scratch[CDP_hw_intercept].u_val = DNAN; + cdp->scratch[CDP_hw_last_intercept].u_val = DNAN; + cdp->scratch[CDP_hw_slope].u_val = DNAN; + cdp->scratch[CDP_hw_last_slope].u_val = DNAN; + cdp->scratch[CDP_null_count].u_cnt = 1; + cdp->scratch[CDP_last_null_count].u_cnt = 1; +} + +void init_seasonal_cdp(cdp_prep_t *cdp) +{ + cdp->scratch[CDP_hw_seasonal].u_val = DNAN; + cdp->scratch[CDP_hw_last_seasonal].u_val = DNAN; + cdp->scratch[CDP_init_seasonal].u_cnt = 1; +} + int update_aberrant_CF(rrd_t *rrd, rrd_value_t pdp_val, enum cf_en current_cf, unsigned long cdp_idx, unsigned long rra_idx, unsigned long ds_idx,