diff options
author | Vasilis Kalintiris <vasilis@netdata.cloud> | 2022-07-20 10:36:46 +0300 |
---|---|---|
committer | vkalintiris <vasilis@netdata.cloud> | 2022-09-29 15:59:39 +0300 |
commit | 5c77145d0df7e091d030476c480ab8d9cbceb89e (patch) | |
tree | 6d522795d42e485b52019ad59d2392139e139e55 | |
parent | 8be3acb5cbc1a9f3fd9cb0760ab350e9a2094658 (diff) |
Profile plugin.
-rw-r--r-- | .gitignore | 4 | ||||
-rw-r--r-- | Makefile.am | 6 | ||||
-rw-r--r-- | collectors/profile.plugin/plugin_profile.cc | 143 | ||||
-rw-r--r-- | collectors/profile.plugin/plugin_profile.h | 18 | ||||
-rw-r--r-- | daemon/main.c | 13 | ||||
-rw-r--r-- | daemon/signals.c | 2 | ||||
-rw-r--r-- | daemon/static_threads.c | 26 | ||||
-rw-r--r-- | daemon/static_threads_linux.c | 8 | ||||
-rw-r--r-- | daemon/static_threads_macos.c | 2 | ||||
-rw-r--r-- | libnetdata/log/log.c | 2 | ||||
-rw-r--r-- | ml/Config.cc | 2 | ||||
-rwxr-xr-x | multind/driver.py | 119 | ||||
-rwxr-xr-x | multind/genconf.py | 121 | ||||
-rw-r--r-- | multind/netdata.conf.tmpl | 44 | ||||
-rw-r--r-- | multind/stream.conf.tmpl | 15 |
15 files changed, 504 insertions, 21 deletions
diff --git a/.gitignore b/.gitignore index 275b5d0076..6d7eca5ff0 100644 --- a/.gitignore +++ b/.gitignore @@ -232,3 +232,7 @@ Session.*.vim # Judy stuff JudyLTables.c judyltablesgen + +# multind +multind/nd* +multind/*.yml diff --git a/Makefile.am b/Makefile.am index 34026e9888..9c27347368 100644 --- a/Makefile.am +++ b/Makefile.am @@ -203,6 +203,11 @@ APPS_PLUGIN_FILES = \ $(LIBNETDATA_FILES) \ $(NULL) +PROFILE_PLUGIN_FILES = \ + collectors/profile.plugin/plugin_profile.cc \ + collectors/profile.plugin/plugin_profile.h \ + $(NULL) + CHECKS_PLUGIN_FILES = \ collectors/checks.plugin/plugin_checks.c \ $(NULL) @@ -909,6 +914,7 @@ NETDATA_FILES = \ $(API_PLUGIN_FILES) \ $(EXPORTING_ENGINE_FILES) \ $(CHECKS_PLUGIN_FILES) \ + $(PROFILE_PLUGIN_FILES) \ $(HEALTH_PLUGIN_FILES) \ $(ML_FILES) \ $(ML_TESTS_FILES) \ diff --git a/collectors/profile.plugin/plugin_profile.cc b/collectors/profile.plugin/plugin_profile.cc new file mode 100644 index 0000000000..ff5faf9ccf --- /dev/null +++ b/collectors/profile.plugin/plugin_profile.cc @@ -0,0 +1,143 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "plugin_profile.h" + +#include <chrono> +#include <memory> +#include <vector> +#include <random> +#include <sstream> +#include <string> +#include <map> + +class Dimension { +public: + Dimension(RRDDIM *RD, size_t Index) : + RD(RD), Index(Index), NumUpdates(0) {} + + void update() { + collected_number CN = ++NumUpdates % 3 ? Index + 1 : Index; + rrddim_set_by_pointer(RD->rrdset, RD, CN); + } + +private: + RRDDIM *RD; + size_t Index; + size_t NumUpdates; +}; + +class Chart { + static size_t ChartIdx; + +public: + static std::shared_ptr<Chart> create(const char *Id, size_t UpdateEvery) { + RRDSET *RS = rrdset_create( + localhost, + "prof_type", + Id, // id + NULL, // name + "prof_family", + NULL, // ctx + Id, // title + "prof_units", + "prof_plugin", + "prof_module", + 41000 + ChartIdx++, + static_cast<int>(UpdateEvery), + RRDSET_TYPE_LINE + ); + if (!RS) + fatal("Could not create chart %s", Id); + + return std::make_shared<Chart>(RS); + } + +public: + Chart(RRDSET *RS) : RS(RS) {} + + void createDimension(const char *Name, size_t Index) { + RRDDIM *RD = rrddim_add( + RS, Name, NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE + ); + if (!RD) + fatal("Could not create dimension %s.%s", rrdset_id(RS), Name); + + Dimensions.push_back(std::make_shared<Dimension>(RD, Index)); + } + + void update(size_t NumIterations) { + if ((NumIterations % RS->update_every) != 0) + return; + + rrdset_next(RS); + + for (std::shared_ptr<Dimension> &D : Dimensions) + D->update(); + rrdset_done(RS); + } + +private: + RRDSET *RS; + std::vector<std::shared_ptr<Dimension>> Dimensions; +}; + +size_t Chart::ChartIdx = 0; + +static void profile_main_cleanup(void *ptr) +{ + struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr; + static_thread->enabled = NETDATA_MAIN_THREAD_EXITING; + + info("cleaning up..."); + + static_thread->enabled = NETDATA_MAIN_THREAD_EXITED; +} + +static std::vector<std::shared_ptr<Chart>> createCharts(size_t NumCharts, unsigned NumDimsPerChart, time_t UpdateEvery) { + std::vector<std::shared_ptr<Chart>> Charts; + Charts.reserve(NumCharts); + + constexpr size_t Len = 1024; + char Buf[Len]; + + for (size_t ChartIdx = 0; ChartIdx != NumCharts; ChartIdx++) { + snprintfz(Buf, Len, "chart_%zu", ChartIdx + 1); + std::shared_ptr<Chart> C = Chart::create(Buf, UpdateEvery); + + for (size_t DimIdx = 0; DimIdx != NumDimsPerChart; DimIdx++) { + snprintfz(Buf, Len, "dim_%zu", DimIdx + 1); + C->createDimension(Buf, DimIdx + 1); + } + + Charts.push_back(std::move(C)); + } + + return Charts; +} + +static void updateCharts(std::vector<std::shared_ptr<Chart>> &Charts, size_t NumIterations) { + for (std::shared_ptr<Chart> &C : Charts) + C->update(NumIterations); +} + +void *profile_main(void *ptr) +{ + netdata_thread_cleanup_push(profile_main_cleanup, ptr); + + size_t NumCharts = config_get_number(CONFIG_SECTION_GLOBAL, "profplug charts", 1); + size_t NumDimsPerChart = config_get_number(CONFIG_SECTION_GLOBAL, "profplug dimensions", 1); + + std::vector<std::shared_ptr<Chart>> Charts = createCharts(NumCharts, NumDimsPerChart, 1); + + heartbeat_t HB; + heartbeat_init(&HB); + size_t NumIterations = 0; + + while (!netdata_exit) { + heartbeat_next(&HB, USEC_PER_SEC); + updateCharts(Charts, ++NumIterations); + } + + netdata_thread_cleanup_pop(1); + return NULL; +} diff --git a/collectors/profile.plugin/plugin_profile.h b/collectors/profile.plugin/plugin_profile.h new file mode 100644 index 0000000000..e5629b9d94 --- /dev/null +++ b/collectors/profile.plugin/plugin_profile.h @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef PLUGIN_PROFILE_H +#define PLUGIN_PROFILE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "daemon/common.h" + +void *profile_main(void *ptr); + +#ifdef __cplusplus +}; +#endif + +#endif /* PLUGIN_PROFILE_H */ diff --git a/daemon/main.c b/daemon/main.c index 6d3ca585dd..1a82359bfd 100644 --- a/daemon/main.c +++ b/daemon/main.c @@ -392,13 +392,10 @@ static void security_init(){ #endif static void log_init(void) { - char filename[FILENAME_MAX + 1]; - snprintfz(filename, FILENAME_MAX, "%s/debug.log", netdata_configured_log_dir); - stdout_filename = config_get(CONFIG_SECTION_LOGS, "debug", filename); - - snprintfz(filename, FILENAME_MAX, "%s/error.log", netdata_configured_log_dir); - stderr_filename = config_get(CONFIG_SECTION_LOGS, "error", filename); + stdout_filename = config_get(CONFIG_SECTION_LOGS, "debug", "/dev/stdout"); + stderr_filename = config_get(CONFIG_SECTION_LOGS, "error", "/dev/stdout"); + char filename[FILENAME_MAX + 1]; snprintfz(filename, FILENAME_MAX, "%s/access.log", netdata_configured_log_dir); stdaccess_filename = config_get(CONFIG_SECTION_LOGS, "access", filename); @@ -1440,7 +1437,9 @@ int main(int argc, char **argv) { // initialize internal registry registry_init(); // fork the spawn server +#if 0 spawn_init(); +#endif /* * Libuv uv_spawn() uses SIGCHLD internally: * https://github.com/libuv/libuv/blob/cc51217a317e96510fbb284721d5e6bc2af31e33/src/unix/process.c#L485 @@ -1511,7 +1510,9 @@ int main(int argc, char **argv) { // ------------------------------------------------------------------------ // Initialize netdata agent command serving from cli and signals +#if 0 commands_init(); +#endif info("netdata initialization completed. Enjoy real-time performance monitoring!"); netdata_ready = 1; diff --git a/daemon/signals.c b/daemon/signals.c index b991d46bf1..60c679d81a 100644 --- a/daemon/signals.c +++ b/daemon/signals.c @@ -257,7 +257,9 @@ void signals_handle(void) { case NETDATA_SIGNAL_EXIT_CLEANLY: error_log_limit_unlimited(); info("SIGNAL: Received %s. Cleaning up to exit...", name); +#if 0 commands_exit(); +#endif netdata_cleanup_and_exit(0); exit(0); break; diff --git a/daemon/static_threads.c b/daemon/static_threads.c index 2575bd4ca6..7609eb3081 100644 --- a/daemon/static_threads.c +++ b/daemon/static_threads.c @@ -12,13 +12,14 @@ extern void *pluginsd_main(void *ptr); extern void *service_main(void *ptr); extern void *statsd_main(void *ptr); extern void *timex_main(void *ptr); +extern void *profile_main(void *ptr); const struct netdata_static_thread static_threads_common[] = { { .name = "PLUGIN[timex]", .config_section = CONFIG_SECTION_PLUGINS, .config_name = "timex", - .enabled = 1, + .enabled = 0, .thread = NULL, .init_routine = NULL, .start_routine = timex_main @@ -36,7 +37,7 @@ const struct netdata_static_thread static_threads_common[] = { .name = "PLUGIN[idlejitter]", .config_section = CONFIG_SECTION_PLUGINS, .config_name = "idlejitter", - .enabled = 1, + .enabled = 0, .thread = NULL, .init_routine = NULL, .start_routine = cpuidlejitter_main @@ -54,7 +55,7 @@ const struct netdata_static_thread static_threads_common[] = { .name = "GLOBAL_STATS", .config_section = NULL, .config_name = NULL, - .enabled = 1, + .enabled = 0, .thread = NULL, .init_routine = NULL, .start_routine = global_statistics_main @@ -63,7 +64,7 @@ const struct netdata_static_thread static_threads_common[] = { .name = "HEALTH", .config_section = NULL, .config_name = NULL, - .enabled = 1, + .enabled = 0, .thread = NULL, .init_routine = NULL, .start_routine = health_main @@ -72,7 +73,7 @@ const struct netdata_static_thread static_threads_common[] = { .name = "PLUGINSD", .config_section = NULL, .config_name = NULL, - .enabled = 1, + .enabled = 0, .thread = NULL, .init_routine = NULL, .start_routine = pluginsd_main @@ -90,7 +91,7 @@ const struct netdata_static_thread static_threads_common[] = { .name = "STATSD", .config_section = NULL, .config_name = NULL, - .enabled = 1, + .enabled = 0, .thread = NULL, .init_routine = NULL, .start_routine = statsd_main @@ -99,7 +100,7 @@ const struct netdata_static_thread static_threads_common[] = { .name = "EXPORTING", .config_section = NULL, .config_name = NULL, - .enabled = 1, + .enabled = 0, .thread = NULL, .init_routine = NULL, .start_routine = exporting_main @@ -122,13 +123,22 @@ const struct netdata_static_thread static_threads_common[] = { .init_routine = NULL, .start_routine = socket_listen_main_static_threaded }, + { + .name = "PROFILE", + .config_section = NULL, + .config_name = NULL, + .enabled = 1, + .thread = NULL, + .init_routine = NULL, + .start_routine = profile_main + }, #ifdef ENABLE_ACLK { .name = "ACLK_Main", .config_section = NULL, .config_name = NULL, - .enabled = 1, + .enabled = 0, .thread = NULL, .init_routine = NULL, .start_routine = aclk_main diff --git a/daemon/static_threads_linux.c b/daemon/static_threads_linux.c index 5f7a67768e..00bafcb7b7 100644 --- a/daemon/static_threads_linux.c +++ b/daemon/static_threads_linux.c @@ -13,7 +13,7 @@ const struct netdata_static_thread static_threads_linux[] = { .name = "PLUGIN[tc]", .config_section = CONFIG_SECTION_PLUGINS, .config_name = "tc", - .enabled = 1, + .enabled = 0, .thread = NULL, .init_routine = NULL, .start_routine = tc_main @@ -22,7 +22,7 @@ const struct netdata_static_thread static_threads_linux[] = { .name = "PLUGIN[diskspace]", .config_section = CONFIG_SECTION_PLUGINS, .config_name = "diskspace", - .enabled = 1, + .enabled = 0, .thread = NULL, .init_routine = NULL, .start_routine = diskspace_main @@ -31,7 +31,7 @@ const struct netdata_static_thread static_threads_linux[] = { .name = "PLUGIN[proc]", .config_section = CONFIG_SECTION_PLUGINS, .config_name = "proc", - .enabled = 1, + .enabled = 0, .thread = NULL, .init_routine = NULL, .start_routine = proc_main @@ -40,7 +40,7 @@ const struct netdata_static_thread static_threads_linux[] = { .name = "PLUGIN[cgroups]", .config_section = CONFIG_SECTION_PLUGINS, .config_name = "cgroups", - .enabled = 1, + .enabled = 0, .thread = NULL, .init_routine = NULL, .start_routine = cgroups_main diff --git a/daemon/static_threads_macos.c b/daemon/static_threads_macos.c index ae34a1363d..9991abac01 100644 --- a/daemon/static_threads_macos.c +++ b/daemon/static_threads_macos.c @@ -9,7 +9,7 @@ const struct netdata_static_thread static_threads_macos[] = { .name = "PLUGIN[macos]", .config_section = CONFIG_SECTION_PLUGINS, .config_name = "macos", - .enabled = 1, + .enabled = 0, .thread = NULL, .init_routine = NULL, .start_routine = macos_main diff --git a/libnetdata/log/log.c b/libnetdata/log/log.c index a209baefc9..f3c32acbb0 100644 --- a/libnetdata/log/log.c +++ b/libnetdata/log/log.c @@ -598,7 +598,7 @@ void open_all_log_files() { // error log throttling time_t error_log_throttle_period = 1200; -unsigned long error_log_errors_per_period = 200; +unsigned long error_log_errors_per_period = 999999; unsigned long error_log_errors_per_period_backup = 0; int error_log_limit(int reset) { diff --git a/ml/Config.cc b/ml/Config.cc index 63b570156a..3336de6b99 100644 --- a/ml/Config.cc +++ b/ml/Config.cc @@ -22,7 +22,7 @@ static T clamp(const T& Value, const T& Min, const T& Max) { void Config::readMLConfig(void) { const char *ConfigSectionML = CONFIG_SECTION_ML; - bool EnableAnomalyDetection = config_get_boolean(ConfigSectionML, "enabled", true); + bool EnableAnomalyDetection = config_get_boolean(ConfigSectionML, "enabled", false); /* * Read values diff --git a/multind/driver.py b/multind/driver.py new file mode 100755 index 0000000000..1d0071a70b --- /dev/null +++ b/multind/driver.py @@ -0,0 +1,119 @@ +#!/usr/bin/env python3 + +import os +import sys +import json + +import yaml + +from string import Template + +import genconf + +import click + +def to_yaml(child_agents, level_agents): + pass + + +class Agent: + def __init__(self, executable, uid, web_port, rm): + self.executable = executable + self.uid = uid + self.web_port = web_port + self.stream_ports = [] + self.rm = rm + + def link(self, agent): + self.stream_ports.append(agent.web_port) + + def genconf(self): + self.cfg = genconf.Config( + self.executable, + self.uid, + self.web_port, + self.stream_ports, + "dbengine", # mode + "no", # replication + self.rm, # rm + ) + self.cfg.generate() + print(self) + + def window(self): + return { + 'layout': 'even-horizontal', + 'panes': [ + f"{self.executable} -W keepopenfds -D -c {self.cfg.netdata_config_file}", + f"sleep 5 && cd {self.cfg.hostname}/var/log/netdata/ && less -N -S +F error.log" + ] + } + + def __repr__(self): + return f'Agent(uid={self.uid}, web_port={self.web_port}, stream_ports={self.stream_ports})' + + def __str__(self): + return f'Agent(uid={self.uid}, web_port={self.web_port}, stream_ports={self.stream_ports})' + +@click.command() +@click.option('--executable', required=True, type=str) +@click.option('--childs', required=True, type=int) +@click.option('--levels', required=True, type=int) +@click.option('--active-active', required=True, type=bool) +@click.option('--rm', required=True, type=bool) +def main(executable, childs, levels, active_active, rm): + child_agents = [ + Agent(executable, uid, 20000 + uid, rm) for uid in range(childs) + ] + + level_agents = [ + [ + Agent(executable, 100 * (level + 1), 20000 + 100 * (level + 1), rm), + Agent(executable, 100 * (level + 1) + 1, 20000 + 100 * (level + 1) + 1, rm) + ] for level in range(levels) + ] + + if not active_active: + level_agents = [[x[0]] for x in level_agents] + + for la in level_agents: + if len(la) == 2: + la[0].link(la[1]) + la[1].link(la[0]) + + if levels != 0: + for ca in child_agents: + for la in level_agents[0]: + ca.link(la) + + for (la, next_la) in zip(level_agents, level_agents[1:]): + for lower_level_agent in la: + for higher_level_agent in next_la: + lower_level_agent.link(higher_level_agent) + + for ca in child_agents: + ca.genconf() + + for la in level_agents: + for a in la: + a.genconf() + + d = { + 'name': 'streaming', + 'root': os.path.realpath(os.path.dirname(__file__)), + 'windows': [] + } + + for ca in child_agents: + d['windows'].append({ f'c{ca.uid}': ca.window() }) + + for li, la in enumerate(level_agents): + for ai, a in enumerate(la): + d['windows'].append({ f'l{li}{ai}': a.window() }) + + with open('tmux-session.yml', 'w') as outfile: + yaml.dump(d, outfile, default_flow_style=False) + + +if __name__ == '__main__': + main() diff --git a/multind/genconf.py b/multind/genconf.py new file mode 100755 index 0000000000..ebec37db62 --- /dev/null +++ b/multind/genconf.py @@ -0,0 +1,121 @@ +#!/usr/bin/env python3 + +import os +import sys +import json +import signal +import shutil +import subprocess +import time +import uuid + +from string import Template + +import click + +memory_modes = [ + "dbengine", "ram", "save", "map", "alloc", "none", +] + +def expand_template(src, dst, subs): + with open(src) as fp: + text = fp.read() + t = Template(text).substitute(subs) + + with open(dst, "w") as fp: + fp.write(t) + +class Config: + def __init__(self, executable, uid, web_port, stream_ports, + mode="dbengine", replication="no", rm="yes"): + self.options = { + "executable": executable, + "uid": uid, + "web-port": web_port, + "stream-ports": stream_ports, + "mode": mode, + "replication": replication, + "rm": rm, + } + + self.hostname = f"nd{uid}" + + self.rfs = os.path.join(os.getcwd(), self.hostname) + self.config_directory = os.path.join(self.rfs, "etc/netdata") + self.log_directory = os.path.join(self.rfs, "var/log/netdata") + self.cache_directory = os.path.join(self.rfs, "var/cache/netdata") + self.lib_directory = os.path.join(self.rfs, "var/lib/netdata") + + self.netdata_config_file = os.path.realpath(os.path.join(self.rfs, os.pardir, f"nd{uid}.conf")) + self.stream_config_file = os.path.join(self.config_directory, "stream.conf") + self.registry_id_file = os.path.join(self.lib_directory, 'registry', 'netdata.public.unique.id') + + self.netdata_opts = { + "hostname": self.hostname, + "config_directory": self.config_directory, + "log_directory": self.log_directory, + "cache_directory": self.cache_directory, + "lib_directory": self.lib_directory, + "memory_mode": mode, + "replication": replication, + "web_port": web_port, + } + + self.stream_opts = { + "destinations": " ".join(["tcp:localhost:" + str(port) for port in stream_ports]) + } + + def generate(self): + if self.options["rm"]: + try: + shutil.rmtree(self.rfs) + except: + pass + + os.makedirs(self.config_directory, exist_ok=True) + os.makedirs(self.log_directory, exist_ok=True) + os.makedirs(self.cache_directory, exist_ok=True) + os.makedirs(self.lib_directory, exist_ok=True) + os.makedirs(os.path.dirname(self.registry_id_file), exist_ok=True) + + expand_template("netdata.conf.tmpl", self.netdata_config_file, self.netdata_opts) + expand_template("stream.conf.tmpl", self.stream_config_file, self.stream_opts) + + with open(self.registry_id_file, "w") as fp: + fp.write(str(uuid.uuid3(uuid.NAMESPACE_DNS, self.hostname))) + + + def __str__(self): + d = { + "opts": self.options, + "netdata_opts": self.netdata_opts, + "stream_opts": self.stream_opts, + } + return json.dumps(d, indent=4) + +@click.command() +@click.option('--executable', required=True, type=str) +@click.option('--uid', required=True, type=int) +@click.option('--web-port', required=True, type=int) +@click.option('--stream-ports', required=True, type=int, multiple=True) +@click.option('--mode', required=False, type=click.Choice(memory_modes), default=memory_modes[0]) +@click.option('--replication', required=False, type=bool, default=False) +@click.option('--rm', required=False, type=bool, default=False) +def main(executable, uid, web_port, stream_ports, + mode, replication, rm): + + if replication: + replication = "yes" + else: + replication = "no" + + cfg = Config( + executable, uid, web_port, stream_ports, + mode, str(replication).lower(), rm + ) + print(cfg) + + cfg.generate() + +if __name__ == '__main__': + main() diff --git a/multind/netdata.conf.tmpl b/multind/netdata.conf.tmpl new file mode 100644 index 0000000000..fd938c1423 --- /dev/null +++ b/multind/netdata.conf.tmpl @@ -0,0 +1,44 @@ +[global] + hostname = $hostname + config directory = $config_directory + log directory = $log_directory + cache directory = $cache_directory + lib directory = $lib_directory + memory mode = $memory_mode + errors flood protection period = 9999 + errors to trigger flood protection = 999999 + +[health] + enabled = no + +[ml] + enabled = no + +[plugins] + enable running new plugins = no + timex = no + checks = no + idlejitter = no + tc = no + diskspace = no + proc = no + cgroups = no + statsd = no + slabinfo = no + go.d = no + charts.d = no + fping = no + ioping = no + python.d = no + apps = no + ebpf = no + macos = no + +[replication] + enabled = $replication + seconds to replicate on first connection = 3600 + max queries per second = 128 + log replication operations = yes + +[web] + default port = $web_port diff --git a/multind/stream.conf.tmpl b/multind/stream.conf.tmpl new file mode 100644 index 0000000000..13fef4a2c5 --- /dev/null +++ b/multind/stream.conf.tmpl @@ -0,0 +1,15 @@ +[stream] + enabled = yes + destination = $destinations + api key = 11111111-2222-3333-4444-555555555555 + timeout seconds = 60 + send charts matching = * + buffer size bytes = 1048576 + reconnect delay seconds = 5 + initial clock resync iterations = 60 + enable compression = yes + +[11111111-2222-3333-4444-555555555555] + enabled = yes + enable compression = yes + allow from = * |