diff options
-rw-r--r-- | CMakeLists.txt | 7 | ||||
-rw-r--r-- | Makefile.am | 18 | ||||
-rw-r--r-- | collectors/all.h | 18 | ||||
-rw-r--r-- | configure.ac | 23 | ||||
-rw-r--r-- | daemon/global_statistics.c | 34 | ||||
-rw-r--r-- | daemon/global_statistics.h | 1 | ||||
-rw-r--r-- | daemon/main.c | 5 | ||||
-rw-r--r-- | database/rrd.h | 18 | ||||
-rw-r--r-- | database/rrdcontext.c | 9 | ||||
-rw-r--r-- | database/rrddim.c | 12 | ||||
-rw-r--r-- | database/rrdhost.c | 20 | ||||
-rw-r--r-- | database/rrdset.c | 18 | ||||
-rw-r--r-- | ml/ADCharts.cc | 496 | ||||
-rw-r--r-- | ml/ADCharts.h | 10 | ||||
-rw-r--r-- | ml/Chart.cc | 0 | ||||
-rw-r--r-- | ml/Chart.h | 128 | ||||
-rw-r--r-- | ml/Config.cc | 6 | ||||
-rw-r--r-- | ml/Config.h | 1 | ||||
-rw-r--r-- | ml/Dimension.cc | 309 | ||||
-rw-r--r-- | ml/Dimension.h | 178 | ||||
-rw-r--r-- | ml/Host.cc | 393 | ||||
-rw-r--r-- | ml/Host.h | 97 | ||||
-rw-r--r-- | ml/Mutex.h | 36 | ||||
-rw-r--r-- | ml/Query.h | 2 | ||||
-rw-r--r-- | ml/Queue.h | 59 | ||||
-rw-r--r-- | ml/README.md | 76 | ||||
-rw-r--r-- | ml/SamplesBuffer.cc | 52 | ||||
-rw-r--r-- | ml/SamplesBuffer.h | 3 | ||||
-rw-r--r-- | ml/SamplesBufferTests.cc | 146 | ||||
-rw-r--r-- | ml/Stats.h | 46 | ||||
-rw-r--r-- | ml/ml-dummy.c | 51 | ||||
-rw-r--r-- | ml/ml-private.h | 13 | ||||
-rw-r--r-- | ml/ml.cc | 108 | ||||
-rw-r--r-- | ml/ml.h | 28 | ||||
-rwxr-xr-x | netdata-installer.sh | 2 |
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; + |