sys_devices_system_node.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include "plugin_proc.h"
  3. struct node {
  4. char *name;
  5. char *numastat_filename;
  6. procfile *numastat_ff;
  7. RRDSET *numastat_st;
  8. struct node *next;
  9. };
  10. static struct node *numa_root = NULL;
  11. static int find_all_nodes() {
  12. int numa_node_count = 0;
  13. char name[FILENAME_MAX + 1];
  14. snprintfz(name, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/devices/system/node");
  15. char *dirname = config_get("plugin:proc:/sys/devices/system/node", "directory to monitor", name);
  16. DIR *dir = opendir(dirname);
  17. if(!dir) {
  18. error("Cannot read NUMA node directory '%s'", dirname);
  19. return 0;
  20. }
  21. struct dirent *de = NULL;
  22. while((de = readdir(dir))) {
  23. if(de->d_type != DT_DIR)
  24. continue;
  25. if(strncmp(de->d_name, "node", 4) != 0)
  26. continue;
  27. if(!isdigit(de->d_name[4]))
  28. continue;
  29. numa_node_count++;
  30. struct node *m = callocz(1, sizeof(struct node));
  31. m->name = strdupz(de->d_name);
  32. struct stat st;
  33. snprintfz(name, FILENAME_MAX, "%s/%s/numastat", dirname, de->d_name);
  34. if(stat(name, &st) == -1) {
  35. freez(m->name);
  36. freez(m);
  37. continue;
  38. }
  39. m->numastat_filename = strdupz(name);
  40. m->next = numa_root;
  41. numa_root = m;
  42. }
  43. closedir(dir);
  44. return numa_node_count;
  45. }
  46. int do_proc_sys_devices_system_node(int update_every, usec_t dt) {
  47. (void)dt;
  48. static uint32_t hash_local_node = 0, hash_numa_foreign = 0, hash_interleave_hit = 0, hash_other_node = 0, hash_numa_hit = 0, hash_numa_miss = 0;
  49. static int do_numastat = -1, numa_node_count = 0;
  50. struct node *m;
  51. if(unlikely(numa_root == NULL)) {
  52. numa_node_count = find_all_nodes();
  53. if(unlikely(numa_root == NULL))
  54. return 1;
  55. }
  56. if(unlikely(do_numastat == -1)) {
  57. do_numastat = config_get_boolean_ondemand("plugin:proc:/sys/devices/system/node", "enable per-node numa metrics", CONFIG_BOOLEAN_AUTO);
  58. hash_local_node = simple_hash("local_node");
  59. hash_numa_foreign = simple_hash("numa_foreign");
  60. hash_interleave_hit = simple_hash("interleave_hit");
  61. hash_other_node = simple_hash("other_node");
  62. hash_numa_hit = simple_hash("numa_hit");
  63. hash_numa_miss = simple_hash("numa_miss");
  64. }
  65. if(do_numastat == CONFIG_BOOLEAN_YES || (do_numastat == CONFIG_BOOLEAN_AUTO &&
  66. (numa_node_count >= 2 || netdata_zero_metrics_enabled == CONFIG_BOOLEAN_YES))) {
  67. for(m = numa_root; m; m = m->next) {
  68. if(m->numastat_filename) {
  69. if(unlikely(!m->numastat_ff)) {
  70. m->numastat_ff = procfile_open(m->numastat_filename, " ", PROCFILE_FLAG_DEFAULT);
  71. if(unlikely(!m->numastat_ff))
  72. continue;
  73. }
  74. m->numastat_ff = procfile_readall(m->numastat_ff);
  75. if(unlikely(!m->numastat_ff || procfile_lines(m->numastat_ff) < 1 || procfile_linewords(m->numastat_ff, 0) < 1))
  76. continue;
  77. if(unlikely(!m->numastat_st)) {
  78. m->numastat_st = rrdset_create_localhost(
  79. "mem"
  80. , m->name
  81. , NULL
  82. , "numa"
  83. , NULL
  84. , "NUMA events"
  85. , "events/s"
  86. , PLUGIN_PROC_NAME
  87. , "/sys/devices/system/node"
  88. , NETDATA_CHART_PRIO_MEM_NUMA_NODES
  89. , update_every
  90. , RRDSET_TYPE_LINE
  91. );
  92. rrdset_flag_set(m->numastat_st, RRDSET_FLAG_DETAIL);
  93. rrddim_add(m->numastat_st, "numa_hit", "hit", 1, 1, RRD_ALGORITHM_INCREMENTAL);
  94. rrddim_add(m->numastat_st, "numa_miss", "miss", 1, 1, RRD_ALGORITHM_INCREMENTAL);
  95. rrddim_add(m->numastat_st, "local_node", "local", 1, 1, RRD_ALGORITHM_INCREMENTAL);
  96. rrddim_add(m->numastat_st, "numa_foreign", "foreign", 1, 1, RRD_ALGORITHM_INCREMENTAL);
  97. rrddim_add(m->numastat_st, "interleave_hit", "interleave", 1, 1, RRD_ALGORITHM_INCREMENTAL);
  98. rrddim_add(m->numastat_st, "other_node", "other", 1, 1, RRD_ALGORITHM_INCREMENTAL);
  99. }
  100. else rrdset_next(m->numastat_st);
  101. size_t lines = procfile_lines(m->numastat_ff), l;
  102. for(l = 0; l < lines; l++) {
  103. size_t words = procfile_linewords(m->numastat_ff, l);
  104. if(unlikely(words < 2)) {
  105. if(unlikely(words))
  106. error("Cannot read %s numastat line %zu. Expected 2 params, read %zu.", m->name, l, words);
  107. continue;
  108. }
  109. char *name = procfile_lineword(m->numastat_ff, l, 0);
  110. char *value = procfile_lineword(m->numastat_ff, l, 1);
  111. if (unlikely(!name || !*name || !value || !*value))
  112. continue;
  113. uint32_t hash = simple_hash(name);
  114. if(likely(
  115. (hash == hash_numa_hit && !strcmp(name, "numa_hit"))
  116. || (hash == hash_numa_miss && !strcmp(name, "numa_miss"))
  117. || (hash == hash_local_node && !strcmp(name, "local_node"))
  118. || (hash == hash_numa_foreign && !strcmp(name, "numa_foreign"))
  119. || (hash == hash_interleave_hit && !strcmp(name, "interleave_hit"))
  120. || (hash == hash_other_node && !strcmp(name, "other_node"))
  121. ))
  122. rrddim_set(m->numastat_st, name, (collected_number)str2kernel_uint_t(value));
  123. }
  124. rrdset_done(m->numastat_st);
  125. }
  126. }
  127. }
  128. return 0;
  129. }