summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt7
-rw-r--r--Makefile.am18
-rw-r--r--collectors/all.h18
-rw-r--r--configure.ac23
-rw-r--r--daemon/global_statistics.c34
-rw-r--r--daemon/global_statistics.h1
-rw-r--r--daemon/main.c5
-rw-r--r--database/rrd.h18
-rw-r--r--database/rrdcontext.c9
-rw-r--r--database/rrddim.c12
-rw-r--r--database/rrdhost.c20
-rw-r--r--database/rrdset.c18
-rw-r--r--ml/ADCharts.cc496
-rw-r--r--ml/ADCharts.h10
-rw-r--r--ml/Chart.cc0
-rw-r--r--ml/Chart.h128
-rw-r--r--ml/Config.cc6
-rw-r--r--ml/Config.h1
-rw-r--r--ml/Dimension.cc309
-rw-r--r--ml/Dimension.h178
-rw-r--r--ml/Host.cc393
-rw-r--r--ml/Host.h97
-rw-r--r--ml/Mutex.h36
-rw-r--r--ml/Query.h2
-rw-r--r--ml/Queue.h59
-rw-r--r--ml/README.md76
-rw-r--r--ml/SamplesBuffer.cc52
-rw-r--r--ml/SamplesBuffer.h3
-rw-r--r--ml/SamplesBufferTests.cc146
-rw-r--r--ml/Stats.h46
-rw-r--r--ml/ml-dummy.c51
-rw-r--r--ml/ml-private.h13
-rw-r--r--ml/ml.cc108
-rw-r--r--ml/ml.h28
-rwxr-xr-xnetdata-installer.sh2
35 files changed, 1608 insertions, 815 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c12e9c81b9..292a03d58c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1030,12 +1030,17 @@ set(ML_FILES
IF(ENABLE_ML)
message(STATUS "ML: enabled")
list(APPEND ML_FILES
+ ml/ADCharts.h
+ ml/ADCharts.cc
+ ml/Chart.h
+ ml/Chart.cc
ml/Config.h
ml/Config.cc
- ml/Dimension.cc
ml/Dimension.h
+ ml/Dimension.cc
ml/Host.h
ml/Host.cc
+ ml/Mutex.h
ml/Query.h
ml/KMeans.h
ml/KMeans.cc
diff --git a/Makefile.am b/Makefile.am
index e88b1b59f0..e900755999 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -236,10 +236,15 @@ ML_FILES += \
ml/ADCharts.cc \
ml/Config.h \
ml/Config.cc \
+ ml/Chart.cc \
+ ml/Chart.h \
+ ml/Stats.h \
ml/Dimension.cc \
ml/Dimension.h \
ml/Host.h \
ml/Host.cc \
+ ml/Mutex.h \
+ ml/Queue.h \
ml/Query.h \
ml/KMeans.h \
ml/KMeans.cc \
@@ -262,13 +267,6 @@ ml/ml.$(OBJEXT) : CXXFLAGS += -Wno-psabi
endif
-
-if ENABLE_ML_TESTS
-ML_TESTS_FILES = \
- ml/SamplesBufferTests.cc \
- $(NULL)
-endif
-
IDLEJITTER_PLUGIN_FILES = \
collectors/idlejitter.plugin/plugin_idlejitter.c \
$(NULL)
@@ -920,7 +918,6 @@ NETDATA_FILES = \
$(EXPORTING_ENGINE_FILES) \
$(HEALTH_PLUGIN_FILES) \
$(ML_FILES) \
- $(ML_TESTS_FILES) \
$(IDLEJITTER_PLUGIN_FILES) \
$(PLUGINSD_PLUGIN_FILES) \
$(REGISTRY_PLUGIN_FILES) \
@@ -1008,11 +1005,6 @@ if ENABLE_ACLK
$(NULL)
endif
-if ENABLE_ML_TESTS
- netdata_LDADD += $(OPTIONAL_ML_TESTS_LIBS) \
- $(NULL)
-endif
-
netdata_LINK = $(CXXLD) $(CXXFLAGS) $(LDFLAGS) -o $@
sbin_PROGRAMS += netdatacli
diff --git a/collectors/all.h b/collectors/all.h
index 85a7ac8b27..8774eb702a 100644
--- a/collectors/all.h
+++ b/collectors/all.h
@@ -363,5 +363,23 @@
#define NETDATA_CHART_PRIO_NETDATA_TIMEX 132030
#define NETDATA_CHART_PRIO_NETDATA_TC_TIME 1000100
+// NETDATA ML CHARTS
+
+// [ml] charts
+#define ML_CHART_PRIO_DIMENSIONS 39181
+#define ML_CHART_PRIO_ANOMALY_RATE 39182
+#define ML_CHART_PRIO_DETECTOR_EVENTS 39183
+
+// [netdata.ml] charts
+#define NETDATA_ML_CHART_PRIO_MACHINE_LEARNING_STATUS 890001
+#define NETDATA_ML_CHART_PRIO_METRIC_TYPES 890002
+#define NETDATA_ML_CHART_PRIO_TRAINING_STATUS 890003
+
+#define NETDATA_ML_CHART_PRIO_PREDICTION_USAGE 890004
+#define NETDATA_ML_CHART_PRIO_TRAINING_USAGE 890005
+
+#define NETDATA_ML_CHART_PRIO_QUEUE_STATS 890006
+#define NETDATA_ML_CHART_PRIO_TRAINING_TIME_STATS 890007
+#define NETDATA_ML_CHART_PRIO_TRAINING_RESULTS 890008
#endif //NETDATA_ALL_H
diff --git a/configure.ac b/configure.ac
index 53e673c2a6..2670bc9ce0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -208,12 +208,6 @@ AC_ARG_ENABLE(
[enable_ml="detect"]
)
AC_ARG_ENABLE(
- [ml_tests],
- [AS_HELP_STRING([--enable-ml-tests], [Enable anomaly detection tests @<:@no@:>@])],
- [enable_ml_tests="yes"],
- [enable_ml_tests="no"]
-)
-AC_ARG_ENABLE(
[aclk_ssl_debug],
[AS_HELP_STRING([--enable-aclk-ssl-debug], [Enables possibility for SSL key logging @<:@default no@:>@])],
[aclk_ssl_debug="yes"],
@@ -1180,19 +1174,6 @@ if test "${build_ml}" = "yes"; then
OPTIONAL_ML_LIBS=""
fi
-# Decide if we should build ML tests.
-if test "${build_ml}" = "yes" -a "${enable_ml_tests}" = "yes" -a "${have_gtest}" = "yes"; then
- build_ml_tests="yes"
-else
- build_ml_tests="no"
-fi
-
-AM_CONDITIONAL([ENABLE_ML_TESTS], [test "${build_ml_tests}" = "yes"])
-if test "${build_ml_tests}" = "yes"; then
- AC_DEFINE([ENABLE_ML_TESTS], [1], [anomaly detection tests])
- OPTIONAL_ML_TESTS_CFLAGS="${OPTIONAL_GTEST_CFLAGS}"
- OPTIONAL_ML_TESTS_LIBS="${OPTIONAL_GTEST_LIBS}"
-fi
# -----------------------------------------------------------------------------
# ebpf.plugin
@@ -1612,7 +1593,7 @@ CFLAGS="${originalCFLAGS} ${OPTIONAL_LTO_CFLAGS} ${OPTIONAL_PROTOBUF_CFLAGS} ${O
${OPTIONAL_LIBCAP_CFLAGS} ${OPTIONAL_IPMIMONITORING_CFLAGS} ${OPTIONAL_CUPS_CFLAGS} ${OPTIONAL_XENSTAT_FLAGS} \
${OPTIONAL_KINESIS_CFLAGS} ${OPTIONAL_PUBSUB_CFLAGS} ${OPTIONAL_PROMETHEUS_REMOTE_WRITE_CFLAGS} \
${OPTIONAL_MONGOC_CFLAGS} ${LWS_CFLAGS} ${OPTIONAL_JSONC_STATIC_CFLAGS} ${OPTIONAL_BPF_CFLAGS} ${JUDY_CFLAGS} \
- ${OPTIONAL_ACLK_CFLAGS} ${OPTIONAL_ML_CFLAGS} ${OPTIONAL_ML_TESTS_CFLAGS} ${OPTIONAL_OS_DEP_CFLAGS}"
+ ${OPTIONAL_ACLK_CFLAGS} ${OPTIONAL_ML_CFLAGS} ${OPTIONAL_OS_DEP_CFLAGS}"
CXXFLAGS="${CFLAGS} ${CXX11FLAG}"
@@ -1666,8 +1647,6 @@ AC_SUBST([OPTIONAL_GTEST_CFLAGS])
AC_SUBST([OPTIONAL_GTEST_LIBS])
AC_SUBST([OPTIONAL_ML_CFLAGS])
AC_SUBST([OPTIONAL_ML_LIBS])
-AC_SUBST([OPTIONAL_ML_TESTS_CFLAGS])
-AC_SUBST([OPTIONAL_ML_TESTS_LIBS])
# -----------------------------------------------------------------------------
# Check if cmocka is available - needed for unit testing
diff --git a/daemon/global_statistics.c b/daemon/global_statistics.c
index a4e9d321ff..e369fb2b87 100644
--- a/daemon/global_statistics.c
+++ b/daemon/global_statistics.c
@@ -52,6 +52,7 @@ static struct global_statistics {
uint64_t ml_queries_made;
uint64_t ml_db_points_read;
uint64_t ml_result_points_generated;
+ uint64_t ml_models_consulted;
uint64_t exporters_queries_made;
uint64_t exporters_db_points_read;
@@ -88,6 +89,10 @@ void global_statistics_ml_query_completed(size_t points_read) {
__atomic_fetch_add(&global_statistics.ml_db_points_read, points_read, __ATOMIC_RELAXED);
}
+void global_statistics_ml_models_consulted(size_t models_consulted) {
+ __atomic_fetch_add(&global_statistics.ml_models_consulted, models_consulted, __ATOMIC_RELAXED);
+}
+
void global_statistics_exporters_query_completed(size_t points_read) {
__atomic_fetch_add(&global_statistics.exporters_queries_made, 1, __ATOMIC_RELAXED);
__atomic_fetch_add(&global_statistics.exporters_db_points_read, points_read, __ATOMIC_RELAXED);
@@ -193,6 +198,7 @@ static inline void global_statistics_copy(struct global_statistics *gs, uint8_t
gs->ml_queries_made = __atomic_load_n(&global_statistics.ml_queries_made, __ATOMIC_RELAXED);
gs->ml_db_points_read = __atomic_load_n(&global_statistics.ml_db_points_read, __ATOMIC_RELAXED);
gs->ml_result_points_generated = __atomic_load_n(&global_statistics.ml_result_points_generated, __ATOMIC_RELAXED);
+ gs->ml_models_consulted = __atomic_load_n(&global_statistics.ml_models_consulted, __ATOMIC_RELAXED);
gs->exporters_queries_made = __atomic_load_n(&global_statistics.exporters_queries_made, __ATOMIC_RELAXED);
gs->exporters_db_points_read = __atomic_load_n(&global_statistics.exporters_db_points_read, __ATOMIC_RELAXED);
@@ -653,6 +659,34 @@ static void global_statistics_charts(void) {
rrdset_done(st_points_stored);
}
+
+ {
+ static RRDSET *st = NULL;
+ static RRDDIM *rd = NULL;
+
+ if (unlikely(!st)) {
+ st = rrdset_create_localhost(
+ "netdata" // type
+ , "ml_models_consulted" // id
+ , NULL // name
+ , "ml" // family
+ , NULL // context
+ , "KMeans models used for prediction" // title
+ , "models" // units
+ , "netdata" // plugin
+ , "ml" // module
+ , 131004 // priority
+ , localhost->rrd_update_every // update_every
+ , RRDSET_TYPE_STACKED // chart_type
+ );
+
+ rd = rrddim_add(st, "num_models_consulted", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+ }
+
+ rrddim_set_by_pointer(st, rd, (collected_number) gs.ml_models_consulted);
+
+ rrdset_done(st);
+ }
}
// ----------------------------------------------------------------------------
diff --git a/daemon/global_statistics.h b/daemon/global_statistics.h
index f7d6775cf5..c7f53781aa 100644
--- a/daemon/global_statistics.h
+++ b/daemon/global_statistics.h
@@ -9,6 +9,7 @@
// global statistics
void global_statistics_ml_query_completed(size_t points_read);
+void global_statistics_ml_models_consulted(size_t models_consulted);
void global_statistics_exporters_query_completed(size_t points_read);
void global_statistics_backfill_query_completed(size_t points_read);
void global_statistics_rrdr_query_completed(size_t queries, uint64_t db_points_read, uint64_t result_points_generated, QUERY_SOURCE query_source);
diff --git a/daemon/main.c b/daemon/main.c
index 97f3e85fa6..941412697f 100644
--- a/daemon/main.c
+++ b/daemon/main.c
@@ -1027,11 +1027,6 @@ int main(int argc, char **argv) {
else if(strcmp(optarg, "escapetest") == 0) {
return command_argument_sanitization_tests();
}
-#ifdef ENABLE_ML_TESTS
- else if(strcmp(optarg, "mltest") == 0) {
- return test_ml(argc, argv);
- }
-#endif
#ifdef ENABLE_DBENGINE
else if(strcmp(optarg, "mctest") == 0) {
unittest_running = true;
diff --git a/database/rrd.h b/database/rrd.h
index 0796ff9012..f0d66a02ee 100644
--- a/database/rrd.h
+++ b/database/rrd.h
@@ -30,8 +30,9 @@ typedef struct rrdhost_acquired RRDHOST_ACQUIRED;
typedef struct rrdset_acquired RRDSET_ACQUIRED;
typedef struct rrddim_acquired RRDDIM_ACQUIRED;
-typedef void *ml_host_t;
-typedef void *ml_dimension_t;
+typedef struct ml_host ml_host_t;
+typedef struct ml_chart ml_chart_t;
+typedef struct ml_dimension ml_dimension_t;
typedef enum {
QUERY_SOURCE_UNKNOWN,
@@ -296,7 +297,7 @@ struct rrddim {
// ------------------------------------------------------------------------
// operational state members
- ml_dimension_t ml_dimension; // machine learning data about this dimension
+ ml_dimension_t *ml_dimension; // machine learning data about this dimension
// ------------------------------------------------------------------------
// linking to siblings and parents
@@ -595,6 +596,8 @@ struct rrdset {
DICTIONARY *rrddimvar_root_index; // dimension variables
// we use this dictionary to manage their allocation
+ ml_chart_t *ml_chart;
+
// ------------------------------------------------------------------------
// operational state members
@@ -1028,7 +1031,7 @@ struct rrdhost {
// ------------------------------------------------------------------------
// ML handle
- ml_host_t ml_host;
+ ml_host_t *ml_host;
// ------------------------------------------------------------------------
// Support for host-level labels
@@ -1301,9 +1304,12 @@ void rrdset_isnot_obsolete(RRDSET *st);
time_t rrddim_first_entry_t(RRDDIM *rd);
time_t rrddim_first_entry_t_of_tier(RRDDIM *rd, size_t tier);
time_t rrddim_last_entry_t(RRDDIM *rd);
-time_t rrdset_last_entry_t(RRDSET *st);
-time_t rrdset_first_entry_t_of_tier(RRDSET *st, size_t tier);
+time_t rrddim_last_entry_t_of_tier(RRDDIM *rd, size_t tier);
+
time_t rrdset_first_entry_t(RRDSET *st);
+time_t rrdset_first_entry_t_of_tier(RRDSET *st, size_t tier);
+time_t rrdset_last_entry_t(RRDSET *st);
+
time_t rrdhost_last_entry_t(RRDHOST *h);
// ----------------------------------------------------------------------------
diff --git a/database/rrdcontext.c b/database/rrdcontext.c
index 3413d1ea82..2df42ef47b 100644
--- a/database/rrdcontext.c
+++ b/database/rrdcontext.c
@@ -750,11 +750,6 @@ static void rrdinstance_free(RRDINSTANCE *ri) {
}
static void rrdinstance_insert_callback(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *rrdcontext) {
- static STRING *ml_anomaly_rates_id = NULL;
-
- if(unlikely(!ml_anomaly_rates_id))
- ml_anomaly_rates_id = string_strdupz(ML_ANOMALY_RATES_CHART_ID);
-
RRDINSTANCE *ri = value;
// link it to its parent
@@ -781,10 +776,6 @@ static void rrdinstance_insert_callback(const DICTIONARY_ITEM *item __maybe_unus
ri->flags &= ~RRD_FLAG_HIDDEN; // no need of atomics at the constructor
}
- // we need this when loading from SQL
- if(unlikely(ri->id == ml_anomaly_rates_id))
- ri->flags |= RRD_FLAG_HIDDEN; // no need of atomics at the constructor
-
rrdmetrics_create_in_rrdinstance(ri);
// signal the react callback to do the job
diff --git a/database/rrddim.c b/database/rrddim.c
index 2d909a7015..07f6c5d9d7 100644
--- a/database/rrddim.c
+++ b/database/rrddim.c
@@ -172,7 +172,7 @@ static void rrddim_insert_callback(const DICTIONARY_ITEM *item __maybe_unused, v
rrdset_flag_set(st, RRDSET_FLAG_SYNC_CLOCK);
rrdset_flag_clear(st, RRDSET_FLAG_UPSTREAM_EXPOSED);
- ml_new_dimension(rd);
+ ml_dimension_new(rd);
ctr->react_action = RRDDIM_REACT_NEW;
@@ -191,7 +191,7 @@ static void rrddim_delete_callback(const DICTIONARY_ITEM *item __maybe_unused, v
rrdcontext_removed_rrddim(rd);
- ml_delete_dimension(rd);
+ ml_dimension_delete(rd);
debug(D_RRD_CALLS, "rrddim_free() %s.%s", rrdset_name(st), rrddim_name(rd));
@@ -420,7 +420,13 @@ inline int rrddim_set_divisor(RRDSET *st, RRDDIM *rd, collected_number divisor)
// ----------------------------------------------------------------------------
-// get the timestamp of the last entry in the round-robin database
+time_t rrddim_last_entry_t_of_tier(RRDDIM *rd, size_t tier) {
+ if(unlikely(tier > storage_tiers || !rd->tiers[tier]))
+ return 0;
+
+ return rd->tiers[tier]->query_ops->latest_time(rd->tiers[tier]->db_metric_handle);
+}
+
time_t rrddim_last_entry_t(RRDDIM *rd) {
time_t latest = rd->tiers[0]->query_ops->latest_time(rd->tiers[0]->db_metric_handle);
diff --git a/database/rrdhost.c b/database/rrdhost.c
index 5ba13d47be..cc94df3e3b 100644
--- a/database/rrdhost.c
+++ b/database/rrdhost.c
@@ -517,9 +517,10 @@ int is_legacy = 1;
rrd_hosts_available++;
rrdhost_load_rrdcontext_data(host);
- if (!archived)
- ml_new_host(host);
- else
+ if (!archived) {
+ ml_host_new(host);
+ ml_start_anomaly_detection_threads(host);
+ } else
rrdhost_flag_set(host, RRDHOST_FLAG_ARCHIVED);
@@ -629,7 +630,10 @@ void rrdhost_update(RRDHOST *host
host->rrdpush_replication_step = rrdpush_replication_step;
rrd_hosts_available++;
- ml_new_host(host);
+
+ ml_host_new(host);
+ ml_start_anomaly_detection_threads(host);
+
rrdhost_load_rrdcontext_data(host);
info("Host %s is not in archived mode anymore", rrdhost_hostname(host));
}
@@ -1088,10 +1092,6 @@ void rrdhost_free(RRDHOST *host, bool force) {
rrd_check_wrlock(); // make sure the RRDs are write locked
- rrdhost_wrlock(host);
- ml_delete_host(host);
- rrdhost_unlock(host);
-
// ------------------------------------------------------------------------
// clean up streaming
@@ -1126,6 +1126,10 @@ void rrdhost_free(RRDHOST *host, bool force) {
rrdcalc_rrdhost_index_destroy(host);
rrdcalctemplate_index_destroy(host);
+ // cleanup ML resources
+ ml_stop_anomaly_detection_threads(host);
+ ml_host_delete(host);
+
freez(host->exporting_flags);
health_alarm_log_free(host);
diff --git a/database/rrdset.c b/database/rrdset.c
index 6eb3c7105f..8a1cd6d90b 100644
--- a/database/rrdset.c
+++ b/database/rrdset.c
@@ -178,6 +178,8 @@ static void rrdset_insert_callback(const DICTIONARY_ITEM *item __maybe_unused, v
st->red = NAN;
ctr->react_action = RRDSET_REACT_NEW;
+
+ ml_chart_new(st);
}
// the destructor - the dictionary is write locked while this runs
@@ -232,6 +234,9 @@ static void rrdset_delete_callback(const DICTIONARY_ITEM *item __maybe_unused, v
// 7. destroy the chart labels
rrdlabels_destroy(st->rrdlabels); // destroy the labels, after letting the contexts know
+ // 8. destroy the ml handle
+ ml_chart_delete(st);
+
rrdset_memory_file_free(st); // remove files of db mode save and map
// ------------------------------------------------------------------------
@@ -1253,6 +1258,8 @@ static inline size_t rrdset_done_interpolate(
last_ut = next_store_ut;
+ ml_chart_update_begin(st);
+
struct rda_item *rda;
size_t dim_id;
for(dim_id = 0, rda = rda_base ; dim_id < rda_slots ; ++dim_id, ++rda) {
@@ -1332,8 +1339,11 @@ static inline size_t rrdset_done_interpolate(
break;
}
+ time_t current_time = (time_t) (next_store_ut / USEC_PER_SEC);
+
if(unlikely(!store_this_entry)) {
- (void) ml_is_anomalous(rd, 0, false);
+ (void) ml_is_anomalous(rd, current_time, 0, false);
+
rrddim_store_metric(rd, next_store_ut, NAN, SN_FLAG_NONE);
rrdcontext_collected_rrddim(rd);
continue;
@@ -1342,7 +1352,7 @@ static inline size_t rrdset_done_interpolate(
if(likely(rd->updated && rd->collections_counter > 1 && iterations < st->gap_when_lost_iterations_above)) {
uint32_t dim_storage_flags = storage_flags;
- if (ml_is_anomalous(rd, new_value, true)) {
+ if (ml_is_anomalous(rd, current_time, new_value, true)) {
// clear anomaly bit: 0 -> is anomalous, 1 -> not anomalous
dim_storage_flags &= ~((storage_number)SN_FLAG_NOT_ANOMALOUS);
}
@@ -1352,7 +1362,7 @@ static inline size_t rrdset_done_interpolate(
rd->last_stored_value = new_value;
}
else {
- (void) ml_is_anomalous(rd, 0, false);
+ (void) ml_is_anomalous(rd, current_time, 0, false);
rrdset_debug(st, "%s: STORE[%ld] = NON EXISTING ", rrddim_name(rd), current_entry);
@@ -1364,6 +1374,8 @@ static inline size_t rrdset_done_interpolate(
stored_entries++;
}
+ ml_chart_update_end(st);
+
// reset the storage flags for the next point, if any;
storage_flags = SN_DEFAULT_FLAGS;
diff --git a/ml/ADCharts.cc b/ml/ADCharts.cc
index 00c593c0c4..49816f8f4b 100644
--- a/ml/ADCharts.cc
+++ b/ml/ADCharts.cc
@@ -3,55 +3,182 @@
#include "ADCharts.h"
#include "Config.h"
-void ml::updateDimensionsChart(RRDHOST *RH,
- collected_number NumTrainedDimensions,
- collected_number NumNormalDimensions,
- collected_number NumAnomalousDimensions) {
- static thread_local RRDSET *RS = nullptr;
- static thread_local RRDDIM *NumTotalDimensionsRD = nullptr;
- static thread_local RRDDIM *NumTrainedDimensionsRD = nullptr;
- static thread_local RRDDIM *NumNormalDimensionsRD = nullptr;
- static thread_local RRDDIM *NumAnomalousDimensionsRD = nullptr;
-
- if (!RS) {
- std::stringstream IdSS, NameSS;
+void ml::updateDimensionsChart(RRDHOST *RH, const MachineLearningStats &MLS) {
+ /*
+ * Machine learning status
+ */
+ {
+ static thread_local RRDSET *MachineLearningStatusRS = nullptr;
+
+ static thread_local RRDDIM *Enabled = nullptr;
+ static thread_local RRDDIM *DisabledUE = nullptr;
+ static thread_local RRDDIM *DisabledSP = nullptr;
+
+ if (!MachineLearningStatusRS) {
+ std::stringstream IdSS, NameSS;
+
+ IdSS << "machine_learning_status_for_" << localhost->machine_guid;
+ NameSS << "machine_learning_status_for_" << localhost->hostname;
+
+ MachineLearningStatusRS = rrdset_create_localhost(
+ "netdata", // type
+ IdSS.str().c_str(), // id
+ NameSS.str().c_str(), // name
+ "ml", // family
+ "netdata.machine_learning_status", // ctx
+ "Machine learning status", // title
+ "dimensions", // units
+ "netdata", // plugin
+ "ml", // module
+ NETDATA_ML_CHART_PRIO_MACHINE_LEARNING_STATUS, // priority
+ RH->rrd_update_every, // update_every
+ RRDSET_TYPE_LINE // chart_type
+ );
+ rrdset_flag_set(MachineLearningStatusRS , RRDSET_FLAG_ANOMALY_DETECTION);
+
+ Enabled = rrddim_add(MachineLearningStatusRS, "enabled", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ DisabledUE = rrddim_add(MachineLearningStatusRS, "disabled-ue", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ DisabledSP = rrddim_add(MachineLearningStatusRS, "disabled-sp", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ }
+
+ rrddim_set_by_pointer(MachineLearningStatusRS, Enabled, MLS.NumMachineLearningStatusEnabled);
+ rrddim_set_by_pointer(MachineLearningStatusRS, DisabledUE, MLS.NumMachineLearningStatusDisabledUE);
+ rrddim_set_by_pointer(MachineLearningStatusRS, DisabledSP, MLS.NumMachineLearningStatusDisabledSP);
+
+ rrdset_done(MachineLearningStatusRS);
+ }
- IdSS << "dimensions_on_" << localhost->machine_guid;
- NameSS << "dimensions_on_" << localhost->hostname;
+ /*
+ * Metric type
+ */
+ {
+ static thread_local RRDSET *MetricTypesRS = nullptr;
+
+ static thread_local RRDDIM *Constant = nullptr;
+ static thread_local RRDDIM *Variable = nullptr;
+
+ if (!MetricTypesRS) {
+ std::stringstream IdSS, NameSS;
+
+ IdSS << "metric_types_for_" << localhost->machine_guid;
+ NameSS << "metric_types_for_" << localhost->hostname;
+
+ MetricTypesRS = rrdset_create_localhost(
+ "netdata", // type
+ IdSS.str().c_str(), // id
+ NameSS.str().c_str(), // name
+ "ml", // family
+ "netdata.metric_types", // ctx
+ "Dimensions by metric type", // title
+ "dimensions", // units
+ "netdata", // plugin
+ "ml", // module
+ NETDATA_ML_CHART_PRIO_METRIC_TYPES, // priority
+ RH->rrd_update_every, // update_every
+ RRDSET_TYPE_LINE // chart_type
+ );
+ rrdset_flag_set(MetricTypesRS, RRDSET_FLAG_ANOMALY_DETECTION);
+
+ Constant = rrddim_add(MetricTypesRS, "constant", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ Variable = rrddim_add(MetricTypesRS, "variable", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ }
+
+ rrddim_set_by_pointer(MetricTypesRS, Constant, MLS.NumMetricTypeConstant);
+ rrddim_set_by_pointer(MetricTypesRS, Variable, MLS.NumMetricTypeVariable);
+
+ rrdset_done(MetricTypesRS);
+ }
- RS = rrdset_create(
- RH,
- "anomaly_detection", // type
- IdSS.str().c_str(), // id
- NameSS.str().c_str(), // name
- "dimensions", // family
- "anomaly_detection.dimensions", // ctx
- "Anomaly detection dimensions", // title
- "dimensions", // units
- "netdata", // plugin
- "ml", // module
- 39183, // priority
- RH->rrd_update_every, // update_every
- RRDSET_TYPE_LINE // chart_type
- );
- rrdset_flag_set(RS, RRDSET_FLAG_ANOMALY_DETECTION);
-
- NumTotalDimensionsRD = rrddim_add(RS, "total", NULL,
- 1, 1, RRD_ALGORITHM_ABSOLUTE);
- NumTrainedDimensionsRD = rrddim_add(RS, "trained", NULL,
- 1, 1, RRD_ALGORITHM_ABSOLUTE);
- NumNormalDimensionsRD = rrddim_add(RS, "normal", NULL,
- 1, 1, RRD_ALGORITHM_ABSOLUTE);
- NumAnomalousDimensionsRD = rrddim_add(RS, "anomalous", NULL,
- 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ /*
+ * Training status
+ */
+ {
+ static thread_local RRDSET *TrainingStatusRS = nullptr;
+
+ static thread_local RRDDIM *Untrained = nullptr;
+ static thread_local RRDDIM *PendingWithoutModel = nullptr;
+ static thread_local RRDDIM *Trained = nullptr;
+ static thread_local RRDDIM *PendingWithModel = nullptr;
+
+ if (!TrainingStatusRS) {
+ std::stringstream IdSS, NameSS;
+
+ IdSS << "training_status_for_" << localhost->machine_guid;
+ NameSS << "training_status_for_" << localhost->hostname;
+
+ TrainingStatusRS = rrdset_create_localhost(
+ "netdata", // type
+ IdSS.str().c_str(), // id
+ NameSS.str().c_str(), // name
+ "ml", // family
+ "netdata.training_status", // ctx
+ "Training status of dimensions", // title
+ "dimensions", // units
+ "netdata", // plugin
+ "ml", // module
+ NETDATA_ML_CHART_PRIO_TRAINING_STATUS, // priority
+ RH->rrd_update_every, // update_every
+ RRDSET_TYPE_LINE // chart_type
+ );
+
+ rrdset_flag_set(TrainingStatusRS, RRDSET_FLAG_ANOMALY_DETECTION);
+
+ Untrained = rrddim_add(TrainingStatusRS, "untrained", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ PendingWithoutModel = rrddim_add(TrainingStatusRS, "pending-without-model", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ Trained = rrddim_add(TrainingStatusRS, "trained", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ PendingWithModel = rrddim_add(TrainingStatusRS, "pending-with-model", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+ }
+
+ rrddim_set_by_pointer(TrainingStatusRS, Untrained, MLS.NumTrainingStatusUntrained);
+ rrddim_set_by_pointer(TrainingStatusRS, PendingWithoutModel, MLS.NumTrainingStatusPendingWithoutModel);
+ rrddim_set_by_pointer(TrainingStatusRS, Trained, MLS.NumTrainingStatusTrained);
+ rrddim_set_by_pointer(TrainingStatusRS, PendingWithModel, MLS.NumTrainingStatusPendingWithModel);
+
+ rrdset_done(TrainingStatusRS);
}
- rrddim_set_by_pointer(RS, NumTotalDimensionsRD, NumNormalDimensions + NumAnomalousDimensions);
- rrddim_set_by_pointer(RS, NumTrainedDimensionsRD, NumTrainedDimensions);
- rrddim_set_by_pointer(RS, NumNormalDimensionsRD, NumNormalDimensions);
- rrddim_set_by_pointer(RS, NumAnomalousDimensionsRD, NumAnomalousDimensions);
+ /*
+ * Prediction status
+ */
+ {
+ static thread_local RRDSET *PredictionRS = nullptr;
+
+ static thread_local RRDDIM *Anomalous = nullptr;
+ static thread_local RRDDIM *Normal = nullptr;
+
+ if (!PredictionRS) {
+ std::stringstream IdSS, NameSS;
+
+ IdSS << "dimensions_on_" << localhost->machine_guid;
+ NameSS << "dimensions_on_" << localhost->hostname;
+