// SPDX-License-Identifier: GPL-3.0-or-later #include "debugfs_plugin.h" #define NETDATA_ORDER_FRAGMENTATION 11 static char *orders[NETDATA_ORDER_FRAGMENTATION] = { "order0", "order1", "order2", "order3", "order4", "order5", "order6", "order7", "order8", "order9", "order10" }; static struct netdata_extrafrag { char *node_zone; uint32_t hash; char *id; collected_number orders[NETDATA_ORDER_FRAGMENTATION]; struct netdata_extrafrag *next; } *netdata_extrafrags_root = NULL; static struct netdata_extrafrag *find_or_create_extrafrag(const char *name) { struct netdata_extrafrag *extrafrag; uint32_t hash = simple_hash(name); // search it, from beginning to the end for (extrafrag = netdata_extrafrags_root ; extrafrag ; extrafrag = extrafrag->next) { if (unlikely(hash == extrafrag->hash && !strcmp(name, extrafrag->node_zone))) { return extrafrag; } } extrafrag = callocz(1, sizeof(struct netdata_extrafrag)); extrafrag->node_zone = strdupz(name); extrafrag->hash = hash; if (netdata_extrafrags_root) { struct netdata_extrafrag *last_node; for (last_node = netdata_extrafrags_root; last_node->next ; last_node = last_node->next); last_node->next = extrafrag; } else netdata_extrafrags_root = extrafrag; return extrafrag; } static void extfrag_send_chart(char *chart_id, collected_number *values) { int i; fprintf(stdout, "BEGIN mem.fragmentation_index_%s\n", chart_id); for (i = 0; i < NETDATA_ORDER_FRAGMENTATION; i++) { fprintf(stdout, "SET %s = %lld\n", orders[i], values[i]); } fprintf(stdout, "END\n"); fflush(stdout); } int do_debugfs_extfrag(int update_every, const char *name) { static procfile *ff = NULL; static int chart_order = NETDATA_CHART_PRIO_MEM_FRAGMENTATION; if (unlikely(!ff)) { char filename[FILENAME_MAX + 1]; snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/kernel/debug/extfrag/extfrag_index"); ff = procfile_open(filename, " \t,", PROCFILE_FLAG_DEFAULT); if (unlikely(!ff)) return 1; } ff = procfile_readall(ff); if (unlikely(!ff)) return 1; size_t l, i, j, lines = procfile_lines(ff); for (l = 0; l < lines; l++) { char chart_id[64]; char zone_lowercase[32]; if (unlikely(procfile_linewords(ff, l) < 15)) continue; char *zone = procfile_lineword(ff, l, 3); strncpyz(zone_lowercase, zone, 31); debugfs2lower(zone_lowercase); char *id = procfile_lineword(ff, l, 1); snprintfz(chart_id, 63, "node_%s_%s", id, zone_lowercase); debugfs2lower(chart_id); struct netdata_extrafrag *extrafrag = find_or_create_extrafrag(chart_id); collected_number *line_orders = extrafrag->orders; for (i = 4, j = 0 ; i < 15; i++, j++) { NETDATA_DOUBLE value = str2ndd(procfile_lineword(ff, l, i), NULL); line_orders[j] = (collected_number) (value * 1000.0); } if (unlikely(!extrafrag->id)) { extrafrag->id = extrafrag->node_zone; fprintf( stdout, "CHART mem.fragmentation_index_%s '' 'Memory fragmentation index for each order' 'index' 'fragmentation' 'mem.fragmentation_index_%s' 'line' %d %d '' 'debugfs.plugin' '%s'\n", extrafrag->node_zone, zone_lowercase, chart_order++, // FIXME: the same zones must have the same order update_every, name); for (i = 0; i < NETDATA_ORDER_FRAGMENTATION; i++) { fprintf(stdout, "DIMENSION '%s' '%s' absolute 1 1000 ''\n", orders[i], orders[i]); } fprintf(stdout, "CLABEL 'numa_node' 'node%s' 1\n" "CLABEL_COMMIT\n", id); } extfrag_send_chart(chart_id, line_orders); } return 0; }