From b3f59597c47f108df1303eeb2702b487c08a188e Mon Sep 17 00:00:00 2001 From: thiagoftsm Date: Wed, 8 Mar 2023 14:49:35 +0000 Subject: eBPF new charts (user ring) (#14623) --- libnetdata/ebpf/ebpf.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++ libnetdata/ebpf/ebpf.h | 23 ++++++++++++++ 2 files changed, 108 insertions(+) (limited to 'libnetdata') diff --git a/libnetdata/ebpf/ebpf.c b/libnetdata/ebpf/ebpf.c index 7cad597858..ee3ce3e003 100644 --- a/libnetdata/ebpf/ebpf.c +++ b/libnetdata/ebpf/ebpf.c @@ -454,6 +454,91 @@ void ebpf_update_stats(ebpf_plugin_stats_t *report, ebpf_module_t *em) ebpf_stats_targets(report, em->targets); } +/** + * Update Kernel memory with memory + * + * This algorithm is an adaptation of https://elixir.bootlin.com/linux/v6.1.14/source/tools/bpf/bpftool/common.c#L402 + * to get 'memlock' data and update report. + * + * @param report the output structure + * @param map pointer to a map. + * @param action What action will be done with this map. + */ +void ebpf_update_kernel_memory(ebpf_plugin_stats_t *report, ebpf_local_maps_t *map, ebpf_stats_action_t action) +{ + char filename[FILENAME_MAX+1]; + snprintfz(filename, FILENAME_MAX, "/proc/self/fdinfo/%d", map->map_fd); + procfile *ff = procfile_open(filename, " \t", PROCFILE_FLAG_DEFAULT); + if(unlikely(!ff)) { + error("Cannot open %s", filename); + return; + } + + ff = procfile_readall(ff); + if(unlikely(!ff)) + return; + + unsigned long j, lines = procfile_lines(ff); + char *memlock = { "memlock" }; + for (j = 0; j < lines ; j++) { + char *cmp = procfile_lineword(ff, j,0); + if (!strncmp(memlock, cmp, 7)) { + uint64_t memsize = (uint64_t) str2l(procfile_lineword(ff, j,1)); + switch (action) { + case EBPF_ACTION_STAT_ADD: { + report->memlock_kern += memsize; + report->hash_tables += 1; +#ifdef NETDATA_DEV_MODE + info("Hash table %u: %s (FD = %d) is consuming %lu bytes totalizing %lu bytes", + report->hash_tables, map->name, map->map_fd, memsize, report->memlock_kern); +#endif + break; + } + case EBPF_ACTION_STAT_REMOVE: { + report->memlock_kern -= memsize; + report->hash_tables -= 1; +#ifdef NETDATA_DEV_MODE + info("Hash table %s (FD = %d) was removed releasing %lu bytes, now we have %u tables loaded totalizing %lu bytes.", + map->name, map->map_fd, memsize, report->hash_tables, report->memlock_kern); +#endif + break; + } + default: { + break; + } + } + break; + } + } + + procfile_close(ff); +} + +/** + * Update Kernel memory with memory + * + * This algorithm is an adaptation of https://elixir.bootlin.com/linux/v6.1.14/source/tools/bpf/bpftool/common.c#L402 + * to get 'memlock' data and update report. + * + * @param report the output structure + * @param map pointer to a map. Last map must fish with name = NULL + */ +void ebpf_update_kernel_memory_with_vector(ebpf_plugin_stats_t *report, ebpf_local_maps_t *maps) +{ + if (!maps) + return; + + ebpf_local_maps_t *map; + int i = 0; + for (map = &maps[i]; maps[i].name; i++, map = &maps[i]) { + int fd = map->map_fd; + if (fd == ND_EBPF_MAP_FD_NOT_INITIALIZED) + continue; + + ebpf_update_kernel_memory(report, map, EBPF_ACTION_STAT_ADD); + } +} + //---------------------------------------------------------------------------------------------------------------------- void ebpf_update_pid_table(ebpf_local_maps_t *pid, ebpf_module_t *em) diff --git a/libnetdata/ebpf/ebpf.h b/libnetdata/ebpf/ebpf.h index cf3fa7ccd9..5962b299a3 100644 --- a/libnetdata/ebpf/ebpf.h +++ b/libnetdata/ebpf/ebpf.h @@ -10,6 +10,7 @@ #include #endif #include // Necessary for stdtoul +#include "libnetdata/aral/aral.h" #define NETDATA_DEBUGFS "/sys/kernel/debug/tracing/" #define NETDATA_KALLSYMS "/proc/kallsyms" @@ -238,14 +239,27 @@ typedef struct ebpf_plugin_stats { uint32_t retprobes; // Number of kretprobes loaded uint32_t tracepoints; // Number of tracepoints used uint32_t trampolines; // Number of trampolines used + + uint64_t memlock_kern; // The same information reported by bpftool, but it is not accurated + // https://lore.kernel.org/linux-mm/20230112155326.26902-5-laoar.shao@gmail.com/T/ + uint32_t hash_tables; // Number of hash tables used on the system. } ebpf_plugin_stats_t; +typedef enum ebpf_stats_action { + EBPF_ACTION_STAT_ADD, + EBPF_ACTION_STAT_REMOVE, +} ebpf_stats_action_t; + typedef enum netdata_apps_integration_flags { NETDATA_EBPF_APPS_FLAG_NO, NETDATA_EBPF_APPS_FLAG_YES, NETDATA_EBPF_APPS_FLAG_CHART_CREATED } netdata_apps_integration_flags_t; +#define NETDATA_EBPF_CHART_MEM_LENGTH 48 +#define NETDATA_EBPF_STAT_DIMENSION_MEMORY "memory" +#define NETDATA_EBPF_STAT_DIMENSION_ARAL "aral" + typedef struct ebpf_module { const char *thread_name; const char *config_name; @@ -271,6 +285,10 @@ typedef struct ebpf_module { struct bpf_link **probe_links; struct bpf_object *objects; struct netdata_static_thread *thread; + + // charts + char memory_usage[NETDATA_EBPF_CHART_MEM_LENGTH]; + char memory_allocations[NETDATA_EBPF_CHART_MEM_LENGTH]; } ebpf_module_t; int ebpf_get_kernel_version(); @@ -368,4 +386,9 @@ struct btf *ebpf_load_btf_file(char *path, char *filename); int ebpf_is_function_inside_btf(struct btf *file, char *function); #endif +void ebpf_update_kernel_memory_with_vector(ebpf_plugin_stats_t *report, ebpf_local_maps_t *maps); +void ebpf_update_kernel_memory(ebpf_plugin_stats_t *report, ebpf_local_maps_t *map, ebpf_stats_action_t action); +void ebpf_statistic_create_aral_chart(char *name, ebpf_module_t *em); +void ebpf_send_data_aral_chart(ARAL *memory, ebpf_module_t *em); + #endif /* NETDATA_EBPF_H */ -- cgit v1.2.3