| 1 | // SPDX-License-Identifier: GPL-3.0-or-later |
| 2 | |
| 3 | #ifndef NETDATA_STORAGE_POINT_H |
| 4 | #define NETDATA_STORAGE_POINT_H |
| 5 | |
| 6 | #include "storage_number/storage_number.h" |
| 7 | |
| 8 | typedef struct storage_point { |
| 9 | NETDATA_DOUBLE min; // when count > 1, this is the minimum among them |
| 10 | NETDATA_DOUBLE max; // when count > 1, this is the maximum among them |
| 11 | NETDATA_DOUBLE sum; // the point sum - divided by count gives the average |
| 12 | |
| 13 | // end_time - start_time = point duration |
| 14 | time_t start_time_s; // the time the point starts |
| 15 | time_t end_time_s; // the time the point ends |
| 16 | |
| 17 | uint32_t count; // the number of original points aggregated |
| 18 | uint32_t anomaly_count; // the number of original points found anomalous |
| 19 | |
| 20 | SN_FLAGS flags; // flags stored with the point |
| 21 | } STORAGE_POINT; |
| 22 | |
| 23 | #define storage_point_unset(x) do { \ |
| 24 | (x).min = (x).max = (x).sum = NAN; \ |
| 25 | (x).count = 0; \ |
| 26 | (x).anomaly_count = 0; \ |
| 27 | (x).flags = SN_FLAG_NONE; \ |
| 28 | (x).start_time_s = 0; \ |
| 29 | (x).end_time_s = 0; \ |
| 30 | } while(0) |
| 31 | |
| 32 | #define storage_point_empty(x, start_s, end_s) do { \ |
| 33 | (x).min = (x).max = (x).sum = NAN; \ |
| 34 | (x).count = 1; \ |
| 35 | (x).anomaly_count = 0; \ |
| 36 | (x).flags = SN_FLAG_NONE; \ |
| 37 | (x).start_time_s = start_s; \ |
| 38 | (x).end_time_s = end_s; \ |
| 39 | } while(0) |
| 40 | |
| 41 | #define STORAGE_POINT_UNSET (STORAGE_POINT){ .min = NAN, .max = NAN, .sum = NAN, .count = 0, .anomaly_count = 0, .flags = SN_FLAG_NONE, .start_time_s = 0, .end_time_s = 0 } |
| 42 | |
| 43 | #define storage_point_is_unset(x) (!(x).count) |
| 44 | #define storage_point_is_gap(x) (!netdata_double_isnumber((x).sum)) |
| 45 | #define storage_point_is_zero(x) (!(x).count || (netdata_double_is_zero((x).min) && netdata_double_is_zero((x).max) && netdata_double_is_zero((x).sum) && (x).anomaly_count == 0)) |
| 46 | |
| 47 | #define storage_point_merge_to(dst, src) do { \ |
| 48 | if(storage_point_is_unset(dst)) \ |
| 49 | (dst) = (src); \ |
| 50 | \ |
| 51 | else if(!storage_point_is_unset(src) && \ |
| 52 | !storage_point_is_gap(src)) { \ |
| 53 | \ |
| 54 | if((src).start_time_s < (dst).start_time_s) \ |
| 55 | (dst).start_time_s = (src).start_time_s;\ |
| 56 | \ |
| 57 | if((src).end_time_s > (dst).end_time_s) \ |
| 58 | (dst).end_time_s = (src).end_time_s; \ |
| 59 | \ |
| 60 | if((src).min < (dst).min) \ |
| 61 | (dst).min = (src).min; \ |
| 62 | \ |
| 63 | if((src).max > (dst).max) \ |
| 64 | (dst).max = (src).max; \ |
| 65 | \ |
| 66 | (dst).sum += (src).sum; \ |
| 67 | \ |
| 68 | (dst).count += (src).count; \ |
| 69 | (dst).anomaly_count += (src).anomaly_count; \ |
| 70 | \ |
| 71 | (dst).flags |= (src).flags & SN_FLAG_RESET; \ |
| 72 | } \ |
| 73 | } while(0) |
| 74 | |
| 75 | #define storage_point_add_to(dst, src) do { \ |
| 76 | if(storage_point_is_unset(dst)) \ |
| 77 | (dst) = (src); \ |
| 78 | \ |
| 79 | else if(!storage_point_is_unset(src) && \ |
| 80 | !storage_point_is_gap(src)) { \ |
| 81 | \ |
| 82 | if((src).start_time_s < (dst).start_time_s) \ |
| 83 | (dst).start_time_s = (src).start_time_s;\ |
| 84 | \ |
| 85 | if((src).end_time_s > (dst).end_time_s) \ |
| 86 | (dst).end_time_s = (src).end_time_s; \ |
| 87 | \ |
| 88 | (dst).min += (src).min; \ |
| 89 | (dst).max += (src).max; \ |
| 90 | (dst).sum += (src).sum; \ |
| 91 | \ |
| 92 | (dst).count += (src).count; \ |
| 93 | (dst).anomaly_count += (src).anomaly_count; \ |
| 94 | \ |
| 95 | (dst).flags |= (src).flags & SN_FLAG_RESET; \ |
| 96 | } \ |
| 97 | } while(0) |
| 98 | |
| 99 | #define storage_point_make_positive(sp) do { \ |
| 100 | if(!storage_point_is_unset(sp) && \ |
| 101 | !storage_point_is_gap(sp)) { \ |
| 102 | \ |
| 103 | if(unlikely(signbit((sp).sum))) \ |
| 104 | (sp).sum = -(sp).sum; \ |
| 105 | \ |
| 106 | if(unlikely(signbit((sp).min))) \ |
| 107 | (sp).min = -(sp).min; \ |
| 108 | \ |
| 109 | if(unlikely(signbit((sp).max))) \ |
| 110 | (sp).max = -(sp).max; \ |
| 111 | \ |
| 112 | if(unlikely((sp).min > (sp).max)) { \ |
| 113 | NETDATA_DOUBLE t = (sp).min; \ |
| 114 | (sp).min = (sp).max; \ |
| 115 | (sp).max = t; \ |
| 116 | } \ |
| 117 | } \ |
| 118 | } while(0) |
| 119 | |
| 120 | #define storage_point_anomaly_rate(sp) \ |
| 121 | (NETDATA_DOUBLE)(storage_point_is_unset(sp) ? 0.0 : (NETDATA_DOUBLE)((sp).anomaly_count) * 100.0 / (NETDATA_DOUBLE)((sp).count)) |
| 122 | |
| 123 | #define storage_point_average_value(sp) \ |
| 124 | ((sp).count ? (sp).sum / (NETDATA_DOUBLE)((sp).count) : 0.0) |
| 125 | |
| 126 | |
| 127 | #endif //NETDATA_STORAGE_POINT_H |