// SPDX-License-Identifier: GPL-3.0-or-later
#include "daemon/common.h"
#include "database/KolmogorovSmirnovDist.h"
#define MAX_POINTS 10000
int enable_metric_correlations = CONFIG_BOOLEAN_YES;
int metric_correlations_version = 1;
WEIGHTS_METHOD default_metric_correlations_method = WEIGHTS_METHOD_MC_KS2;
typedef struct weights_stats {
NETDATA_DOUBLE max_base_high_ratio;
size_t db_points;
size_t result_points;
size_t db_queries;
size_t db_points_per_tier[RRD_STORAGE_TIERS];
size_t binary_searches;
} WEIGHTS_STATS;
// ----------------------------------------------------------------------------
// parse and render metric correlations methods
static struct {
const char *name;
WEIGHTS_METHOD value;
} weights_methods[] = {
{ "ks2" , WEIGHTS_METHOD_MC_KS2}
, { "volume" , WEIGHTS_METHOD_MC_VOLUME}
, { "anomaly-rate" , WEIGHTS_METHOD_ANOMALY_RATE}
, { NULL , 0 }
};
WEIGHTS_METHOD weights_string_to_method(const char *method) {
for(int i = 0; weights_methods[i].name ;i++)
if(strcmp(method, weights_methods[i].name) == 0)
return weights_methods[i].value;
return default_metric_correlations_method;
}
const char *weights_method_to_string(WEIGHTS_METHOD method) {
for(int i = 0; weights_methods[i].name ;i++)
if(weights_methods[i].value == method)
return weights_methods[i].name;
return "unknown";
}
// ----------------------------------------------------------------------------
// The results per dimension are aggregated into a dictionary
typedef enum {
RESULT_IS_BASE_HIGH_RATIO = (1 << 0),
RESULT_IS_PERCENTAGE_OF_TIME = (1 << 1),
} RESULT_FLAGS;
struct register_result {
RESULT_FLAGS flags;
RRDCONTEXT_ACQUIRED *rca;
RRDINSTANCE_ACQUIRED *ria;
RRDMETRIC_ACQUIRED *rma;
NETDATA_DOUBLE value;
};
static DICTIONARY *register_result_init() {
DICTIONARY *results = dictionary_create(DICT_OPTION_SINGLE_THREADED);
return results;
}
static void register_result_destroy(DICTIONARY *results) {
dictionary_destroy(results);
}
static void register_result(DICTIONARY *results,
RRDCONTEXT_ACQUIRED *rca,
RRDINSTANCE_ACQUIRED *ria,
RRDMETRIC_ACQUIRED *rma,
NETDATA_DOUBLE value,
RESULT_FLAGS flags,
WEIGHTS_STATS *stats,
bool register_zero) {
if(!netdata_double_isnumber(value)) return;
// make it positive
NETDATA_DOUBLE v = fabsndd(value);
// no need to store zero scored values
if(unlikely(fpclassify(v) == FP_ZERO && !register_zero))
return;
// keep track of the max of the baseline / highlight ratio
if(flags & RESULT_IS_BASE_HIGH_RATIO && v > stats->max_base_high_ratio)
stats->max_base_high_ratio = v;
struct register_result t = {
.flags = flags,
.rca = rca,
.ria