diff options
Diffstat (limited to 'collectors/slabinfo.plugin/slabinfo.c')
-rw-r--r-- | collectors/slabinfo.plugin/slabinfo.c | 393 |
1 files changed, 0 insertions, 393 deletions
diff --git a/collectors/slabinfo.plugin/slabinfo.c b/collectors/slabinfo.plugin/slabinfo.c deleted file mode 100644 index 9b9119a6e..000000000 --- a/collectors/slabinfo.plugin/slabinfo.c +++ /dev/null @@ -1,393 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "daemon/common.h" -#include "libnetdata/required_dummies.h" - -#define PLUGIN_SLABINFO_NAME "slabinfo.plugin" -#define PLUGIN_SLABINFO_PROCFILE "/proc/slabinfo" - -#define CHART_TYPE "mem" -#define CHART_FAMILY "slab" -#define CHART_PRIO 3000 - -// #define slabdebug(...) if (debug) { fprintf(stderr, __VA_ARGS__); } -#define slabdebug(args...) if (debug) { \ - fprintf(stderr, "slabinfo.plugin DEBUG (%04d@%-10.10s:%-15.15s)::", __LINE__, __FILE__, __FUNCTION__); \ - fprintf(stderr, ##args); \ - fprintf(stderr, "\n"); } - -int running = 1; -int debug = 0; -size_t lines_discovered = 0; -int redraw_chart = 0; - -// ---------------------------------------------------------------------------- - -// Slabinfo format : -// format 2.1 Was provided by 57ed3eda977a215f054102b460ab0eb5d8d112e6 (2.6.24-rc6) as: -// seq_puts(m, "# name <active_objs> <num_objs> <objsize> <objperslab> <pagesperslab>"); -// seq_puts(m, " : tunables <limit> <batchcount> <sharedfactor>"); -// seq_puts(m, " : slabdata <active_slabs> <num_slabs> <sharedavail>"); -// -// With max values: -// seq_printf(m, "%-17s %6lu %6lu %6u %4u %4d", -// cache_name(s), sinfo.active_objs, sinfo.num_objs, s->size, sinfo.objects_per_slab, (1 << sinfo.cache_order)); -// seq_printf(m, " : tunables %4u %4u %4u", -// sinfo.limit, sinfo.batchcount, sinfo.shared); -// seq_printf(m, " : slabdata %6lu %6lu %6lu", -// sinfo.active_slabs, sinfo.num_slabs, sinfo.shared_avail); -// -// If CONFIG_DEBUG_SLAB is set, it will also add columns from slabinfo_show_stats (for SLAB only): -// seq_printf(m, " : globalstat %7lu %6lu %5lu %4lu %4lu %4lu %4lu %4lu %4lu", -// allocs, high, grown, reaped, errors, max_freeable, node_allocs, node_frees, overflows); -// seq_printf(m, " : cpustat %6lu %6lu %6lu %6lu", -// allochit, allocmiss, freehit, freemiss); -// -// Implementation choices: -// - Iterates through a linked list of kmem_cache. -// - Name is a char* from struct kmem_cache (mm/slab.h). -// - max name size found is 24: -// grep -roP 'kmem_cache_create\(".+"'| awk '{split($0,a,"\""); print a[2],length(a[2]); }' | sort -k2 -n -// - Using uint64 everywhere, as types fits and allows to use standard helpers - -struct slabinfo { - // procfile fields - const char *name; - uint64_t active_objs; - uint64_t num_objs; - uint64_t obj_size; - uint64_t obj_per_slab; - uint64_t pages_per_slab; - uint64_t tune_limit; - uint64_t tune_batchcnt; - uint64_t tune_shared_factor; - uint64_t data_active_slabs; - uint64_t data_num_slabs; - uint64_t data_shared_avail; - - // Calculated fields - uint64_t mem_usage; - uint64_t mem_waste; - uint8_t obj_filling; - - uint32_t hash; - struct slabinfo *next; -} *slabinfo_root = NULL, *slabinfo_next = NULL, *slabinfo_last_used = NULL; - -// The code is very inspired from "proc_net_dev.c" and "perf_plugin.c" - -// Get the existing object, or create a new one -static struct slabinfo *get_slabstruct(const char *name) { - struct slabinfo *s; - - slabdebug("--> Requested slabstruct %s", name); - - uint32_t hash = simple_hash(name); - - // Search it, from the next to the end - for (s = slabinfo_next; s; s = s->next) { - if ((hash = s->hash) && !strcmp(name, s->name)) { - slabdebug("<-- Found existing slabstruct after %s", slabinfo_last_used->name); - // Prepare the next run - slabinfo_next = s->next; - slabinfo_last_used = s; - return s; - } - } - - // Search it from the beginning to the last position we used - for (s = slabinfo_root; s != slabinfo_last_used; s = s->next) { - if (hash == s->hash && !strcmp(name, s->name)) { - slabdebug("<-- Found existing slabstruct after root %s", slabinfo_root->name); - slabinfo_next = s->next; - slabinfo_last_used = s; - return s; - } - } - - // Create a new one - s = callocz(1, sizeof(struct slabinfo)); - s->name = strdupz(name); - s->hash = hash; - - // Add it to the current position - if (slabinfo_root) { - slabdebug("<-- Creating new slabstruct after %s", slabinfo_last_used->name); - s->next = slabinfo_last_used->next; - slabinfo_last_used->next = s; - slabinfo_last_used = s; - } - else { - slabdebug("<-- Creating new slabstruct as root"); - slabinfo_root = slabinfo_last_used = s; - } - - return s; -} - - -// Read a full pass of slabinfo to update the structs -struct slabinfo *read_file_slabinfo() { - - slabdebug("-> Reading procfile %s", PLUGIN_SLABINFO_PROCFILE); - - static procfile *ff = NULL; - static long slab_pagesize = 0; - - if (unlikely(!slab_pagesize)) { - slab_pagesize = sysconf(_SC_PAGESIZE); - slabdebug(" Discovered pagesize: %ld", slab_pagesize); - } - - if(unlikely(!ff)) { - ff = procfile_reopen(ff, PLUGIN_SLABINFO_PROCFILE, " ,:" , PROCFILE_FLAG_DEFAULT); - if(unlikely(!ff)) { - collector_error("<- Cannot open file '%s", PLUGIN_SLABINFO_PROCFILE); - exit(1); - } - } - - ff = procfile_readall(ff); - if(unlikely(!ff)) { - collector_error("<- Cannot read file '%s'", PLUGIN_SLABINFO_PROCFILE); - exit(0); - } - - - // Iterate on all lines to populate / update the slabinfo struct - size_t lines = procfile_lines(ff), l; - if (unlikely(lines != lines_discovered)) { - lines_discovered = lines; - redraw_chart = 1; - } - - slabdebug(" Read %lu lines from procfile", (unsigned long)lines); - for(l = 2; l < lines; l++) { - if (unlikely(procfile_linewords(ff, l) < 14)) { - slabdebug(" Line %zu has only %zu words, skipping", l, procfile_linewords(ff,l)); - continue; - } - - char *name = procfile_lineword(ff, l, 0); - struct slabinfo *s = get_slabstruct(name); - - s->active_objs = str2uint64_t(procfile_lineword(ff, l, 1), NULL); - s->num_objs = str2uint64_t(procfile_lineword(ff, l, 2), NULL); - s->obj_size = str2uint64_t(procfile_lineword(ff, l, 3), NULL); - s->obj_per_slab = str2uint64_t(procfile_lineword(ff, l, 4), NULL); - s->pages_per_slab = str2uint64_t(procfile_lineword(ff, l, 5), NULL); - - s->tune_limit = str2uint64_t(procfile_lineword(ff, l, 7), NULL); - s->tune_batchcnt = str2uint64_t(procfile_lineword(ff, l, 8), NULL); - s->tune_shared_factor = str2uint64_t(procfile_lineword(ff, l, 9), NULL); - - s->data_active_slabs = str2uint64_t(procfile_lineword(ff, l, 11), NULL); - s->data_num_slabs = str2uint64_t(procfile_lineword(ff, l, 12), NULL); - s->data_shared_avail = str2uint64_t(procfile_lineword(ff, l, 13), NULL); - - uint32_t memperslab = s->pages_per_slab * slab_pagesize; - // Internal fragmentation: loss per slab, due to objects not being a multiple of pagesize - //uint32_t lossperslab = memperslab - s->obj_per_slab * s->obj_size; - - // Total usage = slabs * pages per slab * page size - s->mem_usage = (uint64_t)(s->data_num_slabs * memperslab); - - // Wasted memory (filling): slabs allocated but not filled: sum total slab - sum total objects - s->mem_waste = s->mem_usage - (uint64_t)(s->active_objs * s->obj_size); - //if (s->data_num_slabs > 1) - // s->mem_waste += s->data_num_slabs * lossperslab; - - - // Slab filling efficiency - if (s->num_objs > 0) - s->obj_filling = 100 * s->active_objs / s->num_objs; - else - s->obj_filling = 0; - - slabdebug(" Updated slab %s: %"PRIu64" %"PRIu64" %"PRIu64" %"PRIu64" %"PRIu64" / %"PRIu64" %"PRIu64" %"PRIu64" / %"PRIu64" %"PRIu64" %"PRIu64" / %"PRIu64" %"PRIu64" %hhu", - name, s->active_objs, s->num_objs, s->obj_size, s->obj_per_slab, s->pages_per_slab, - s->tune_limit, s->tune_batchcnt, s->tune_shared_factor, - s->data_active_slabs, s->data_num_slabs, s->data_shared_avail, - s->mem_usage, s->mem_waste, s->obj_filling); - } - - return slabinfo_root; -} - - - -unsigned int do_slab_stats(int update_every) { - - static unsigned int loops = 0; - struct slabinfo *sactive = NULL, *s = NULL; - - // Main processing loop - while (running) { - - sactive = read_file_slabinfo(); - - // Init Charts - if (unlikely(redraw_chart)) { - redraw_chart = 0; - // Memory Usage - printf("CHART %s.%s '' 'Memory Usage' 'B' '%s' '' line %d %d %s\n" - , CHART_TYPE - , "slabmemory" - , CHART_FAMILY - , CHART_PRIO - , update_every - , PLUGIN_SLABINFO_NAME - ); - for (s = sactive; s; s = s->next) { - printf("DIMENSION %s '' absolute 1 1\n", s->name); - } - - // Slab active usage (filling) - printf("CHART %s.%s '' 'Object Filling' '%%' '%s' '' line %d %d %s\n" - , CHART_TYPE - , "slabfilling" - , CHART_FAMILY - , CHART_PRIO + 1 - , update_every - , PLUGIN_SLABINFO_NAME - ); - for (s = sactive; s; s = s->next) { - printf("DIMENSION %s '' absolute 1 1\n", s->name); - } - - // Memory waste - printf("CHART %s.%s '' 'Memory waste' 'B' '%s' '' line %d %d %s\n" - , CHART_TYPE - , "slabwaste" - , CHART_FAMILY - , CHART_PRIO + 2 - , update_every - , PLUGIN_SLABINFO_NAME - ); - for (s = sactive; s; s = s->next) { - printf("DIMENSION %s '' absolute 1 1\n", s->name); - } - } - - - // - // Memory usage - // - printf("BEGIN %s.%s\n" - , CHART_TYPE - , "slabmemory" - ); - for (s = sactive; s; s = s->next) { - printf("SET %s = %"PRIu64"\n" - , s->name - , s->mem_usage - ); - } - printf("END\n"); - - // - // Slab active usage - // - printf("BEGIN %s.%s\n" - , CHART_TYPE - , "slabfilling" - ); - for (s = sactive; s; s = s->next) { - printf("SET %s = %u\n" - , s->name - , s->obj_filling - ); - } - printf("END\n"); - - // - // Memory waste - // - printf("BEGIN %s.%s\n" - , CHART_TYPE - , "slabwaste" - ); - for (s = sactive; s; s = s->next) { - printf("SET %s = %"PRIu64"\n" - , s->name - , s->mem_waste - ); - } - printf("END\n"); - - - loops++; - - sleep(update_every); - } - - return loops; -} - - - - -// ---------------------------------------------------------------------------- -// main - -void usage(void) { - fprintf(stderr, "%s\n", program_name); - exit(1); -} - -int main(int argc, char **argv) { - clocks_init(); - nd_log_initialize_for_external_plugins("slabinfo.plugin"); - - program_name = argv[0]; - program_version = "0.1"; - - int update_every = 1, i, n, freq = 0; - - for (i = 1; i < argc; i++) { - // Frequency parsing - if(isdigit(*argv[i]) && !freq) { - n = (int) str2l(argv[i]); - if (n > 0) { - if (n >= UPDATE_EVERY_MAX) { - collector_error("Invalid interval value: %s", argv[i]); - exit(1); - } - freq = n; - } - } - else if (strcmp("debug", argv[i]) == 0) { - debug = 1; - continue; - } - else { - fprintf(stderr, - "netdata slabinfo.plugin %s\n" - "This program is a data collector plugin for netdata.\n" - "\n" - "Available command line options:\n" - "\n" - " COLLECTION_FREQUENCY data collection frequency in seconds\n" - " minimum: %d\n" - "\n" - " debug enable verbose output\n" - " default: disabled\n" - "\n", - program_version, - update_every - ); - exit(1); - } - } - - if(freq >= update_every) - update_every = freq; - else if(freq) - collector_error("update frequency %d seconds is too small for slabinfo. Using %d.", freq, update_every); - - - // Call the main function. Time drift to be added - do_slab_stats(update_every); - - return 0; -} |