proc_pressure.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include "plugin_proc.h"
  3. #define PLUGIN_PROC_MODULE_PRESSURE_NAME "/proc/pressure"
  4. #define CONFIG_SECTION_PLUGIN_PROC_PRESSURE "plugin:" PLUGIN_PROC_CONFIG_NAME ":" PLUGIN_PROC_MODULE_PRESSURE_NAME
  5. // linux calculates this every 2 seconds, see kernel/sched/psi.c PSI_FREQ
  6. #define MIN_PRESSURE_UPDATE_EVERY 2
  7. static struct pressure resources[PRESSURE_NUM_RESOURCES] = {
  8. {
  9. .some = { .id = "cpu_pressure", .title = "CPU Pressure" },
  10. },
  11. {
  12. .some = { .id = "memory_some_pressure", .title = "Memory Pressure" },
  13. .full = { .id = "memory_full_pressure", .title = "Memory Full Pressure" },
  14. },
  15. {
  16. .some = { .id = "io_some_pressure", .title = "I/O Pressure" },
  17. .full = { .id = "io_full_pressure", .title = "I/O Full Pressure" },
  18. },
  19. };
  20. static struct {
  21. procfile *pf;
  22. const char *name; // metric file name
  23. const char *family; // webui section name
  24. int section_priority;
  25. } resource_info[PRESSURE_NUM_RESOURCES] = {
  26. { .name = "cpu", .family = "cpu", .section_priority = NETDATA_CHART_PRIO_SYSTEM_CPU },
  27. { .name = "memory", .family = "ram", .section_priority = NETDATA_CHART_PRIO_SYSTEM_RAM },
  28. { .name = "io", .family = "disk", .section_priority = NETDATA_CHART_PRIO_SYSTEM_IO },
  29. };
  30. void update_pressure_chart(struct pressure_chart *chart) {
  31. rrddim_set_by_pointer(chart->st, chart->rd10, (collected_number)(chart->value10 * 100));
  32. rrddim_set_by_pointer(chart->st, chart->rd60, (collected_number) (chart->value60 * 100));
  33. rrddim_set_by_pointer(chart->st, chart->rd300, (collected_number) (chart->value300 * 100));
  34. rrdset_done(chart->st);
  35. }
  36. int do_proc_pressure(int update_every, usec_t dt) {
  37. int fail_count = 0;
  38. int i;
  39. static usec_t next_pressure_dt = 0;
  40. static char *base_path = NULL;
  41. update_every = (update_every < MIN_PRESSURE_UPDATE_EVERY) ? MIN_PRESSURE_UPDATE_EVERY : update_every;
  42. if (next_pressure_dt <= dt) {
  43. next_pressure_dt = update_every * USEC_PER_SEC;
  44. } else {
  45. next_pressure_dt -= dt;
  46. return 0;
  47. }
  48. if (unlikely(!base_path)) {
  49. base_path = config_get(CONFIG_SECTION_PLUGIN_PROC_PRESSURE, "base path of pressure metrics", "/proc/pressure");
  50. }
  51. for (i = 0; i < PRESSURE_NUM_RESOURCES; i++) {
  52. procfile *ff = resource_info[i].pf;
  53. int do_some = resources[i].some.enabled, do_full = resources[i].full.enabled;
  54. if (unlikely(!ff)) {
  55. char filename[FILENAME_MAX + 1];
  56. char config_key[CONFIG_MAX_NAME + 1];
  57. snprintfz(filename
  58. , FILENAME_MAX
  59. , "%s%s/%s"
  60. , netdata_configured_host_prefix
  61. , base_path
  62. , resource_info[i].name);
  63. snprintfz(config_key, CONFIG_MAX_NAME, "enable %s some pressure", resource_info[i].name);
  64. do_some = config_get_boolean(CONFIG_SECTION_PLUGIN_PROC_PRESSURE, config_key, CONFIG_BOOLEAN_YES);
  65. resources[i].some.enabled = do_some;
  66. if (resources[i].full.id) {
  67. snprintfz(config_key, CONFIG_MAX_NAME, "enable %s full pressure", resource_info[i].name);
  68. do_full = config_get_boolean(CONFIG_SECTION_PLUGIN_PROC_PRESSURE, config_key, CONFIG_BOOLEAN_YES);
  69. resources[i].full.enabled = do_full;
  70. }
  71. ff = procfile_open(filename, " =", PROCFILE_FLAG_DEFAULT);
  72. if (unlikely(!ff)) {
  73. error("Cannot read pressure information from %s.", filename);
  74. fail_count++;
  75. continue;
  76. }
  77. }
  78. ff = procfile_readall(ff);
  79. resource_info[i].pf = ff;
  80. if (unlikely(!ff)) {
  81. fail_count++;
  82. continue;
  83. }
  84. size_t lines = procfile_lines(ff);
  85. if (unlikely(lines < 1)) {
  86. error("%s has no lines.", procfile_filename(ff));
  87. fail_count++;
  88. continue;
  89. }
  90. struct pressure_chart *chart;
  91. if (do_some) {
  92. chart = &resources[i].some;
  93. if (unlikely(!chart->st)) {
  94. chart->st = rrdset_create_localhost(
  95. "system"
  96. , chart->id
  97. , NULL
  98. , resource_info[i].family
  99. , NULL
  100. , chart->title
  101. , "percentage"
  102. , PLUGIN_PROC_NAME
  103. , PLUGIN_PROC_MODULE_PRESSURE_NAME
  104. , resource_info[i].section_priority + 40
  105. , update_every
  106. , RRDSET_TYPE_LINE
  107. );
  108. chart->rd10 = rrddim_add(chart->st, "some 10", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
  109. chart->rd60 = rrddim_add(chart->st, "some 60", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
  110. chart->rd300 = rrddim_add(chart->st, "some 300", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
  111. } else {
  112. rrdset_next(chart->st);
  113. }
  114. chart->value10 = strtod(procfile_lineword(ff, 0, 2), NULL);
  115. chart->value60 = strtod(procfile_lineword(ff, 0, 4), NULL);
  116. chart->value300 = strtod(procfile_lineword(ff, 0, 6), NULL);
  117. update_pressure_chart(chart);
  118. }
  119. if (do_full && lines > 2) {
  120. chart = &resources[i].full;
  121. if (unlikely(!chart->st)) {
  122. chart->st = rrdset_create_localhost(
  123. "system"
  124. , chart->id
  125. , NULL
  126. , resource_info[i].family
  127. , NULL
  128. , chart->title
  129. , "percentage"
  130. , PLUGIN_PROC_NAME
  131. , PLUGIN_PROC_MODULE_PRESSURE_NAME
  132. , resource_info[i].section_priority + 45
  133. , update_every
  134. , RRDSET_TYPE_LINE
  135. );
  136. chart->rd10 = rrddim_add(chart->st, "full 10", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
  137. chart->rd60 = rrddim_add(chart->st, "full 60", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
  138. chart->rd300 = rrddim_add(chart->st, "full 300", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
  139. } else {
  140. rrdset_next(chart->st);
  141. }
  142. chart->value10 = strtod(procfile_lineword(ff, 1, 2), NULL);
  143. chart->value60 = strtod(procfile_lineword(ff, 1, 4), NULL);
  144. chart->value300 = strtod(procfile_lineword(ff, 1, 6), NULL);
  145. update_pressure_chart(chart);
  146. }
  147. }
  148. if (PRESSURE_NUM_RESOURCES == fail_count) {
  149. return 1;
  150. }
  151. return 0;
  152. }