sys_devices_virtual_powercap.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include "debugfs_plugin.h"
  3. struct zone_t {
  4. char *zone_chart_id;
  5. char *subzone_chart_id;
  6. char *name;
  7. char *path;
  8. unsigned long long max_energy_range_uj;
  9. unsigned long long energy_uj;
  10. struct zone_t *subzones;
  11. struct zone_t *prev, *next;
  12. };
  13. static struct zone_t *rapl_zones = NULL;
  14. static bool get_measurement(const char *path, unsigned long long *energy_uj) {
  15. return read_single_number_file(path, energy_uj) == 0;
  16. }
  17. static struct zone_t *get_rapl_zone(const char *control_type __maybe_unused, struct zone_t *parent __maybe_unused, const char *dirname) {
  18. char temp[FILENAME_MAX + 1];
  19. snprintfz(temp, FILENAME_MAX, "%s/%s", dirname, "name");
  20. char name[FILENAME_MAX + 1] = "";
  21. if (read_file(temp, name, sizeof(name) - 1) != 0)
  22. return NULL;
  23. char *trimmed = trim(name);
  24. if (unlikely(trimmed == NULL || trimmed[0] == 0))
  25. return NULL;
  26. snprintfz(temp, FILENAME_MAX, "%s/%s", dirname, "max_energy_range_uj");
  27. unsigned long long max_energy_range_uj = 0;
  28. if (unlikely(read_single_number_file(temp, &max_energy_range_uj) != 0)) {
  29. collector_error("Cannot read %s", temp);
  30. return NULL;
  31. }
  32. snprintfz(temp, FILENAME_MAX, "%s/%s", dirname, "energy_uj");
  33. unsigned long long energy_uj;
  34. if (unlikely(!get_measurement(temp, &energy_uj))) {
  35. collector_info("%s: Cannot read %s", trimmed, temp);
  36. return NULL;
  37. }
  38. struct zone_t *zone = callocz(1, sizeof(*zone));
  39. zone->name = strdupz(trimmed);
  40. zone->path = strdupz(temp);
  41. zone->max_energy_range_uj = max_energy_range_uj;
  42. zone->energy_uj = energy_uj;
  43. collector_info("Found zone: \"%s\"", zone->name);
  44. return zone;
  45. }
  46. static struct zone_t *look_for_rapl_zones(const char *control_type, struct zone_t *parent, const char *path, int depth) {
  47. if(depth > 2)
  48. return NULL;
  49. struct zone_t *base = NULL;
  50. DIR *dir = opendir(path);
  51. if (unlikely(dir == NULL))
  52. return NULL;
  53. struct dirent *de = NULL;
  54. while ((de = readdir(dir))) {
  55. if (de->d_type != DT_DIR || de->d_name[0] == '.')
  56. continue;
  57. if(strncmp(de->d_name, "intel-rapl:", 11) != 0)
  58. continue;
  59. char zone_path[FILENAME_MAX + 1];
  60. snprintfz(zone_path, FILENAME_MAX, "%s/%s", path, de->d_name);
  61. struct zone_t *zone = get_rapl_zone(control_type, parent, zone_path);
  62. if(zone) {
  63. DOUBLE_LINKED_LIST_APPEND_ITEM_UNSAFE(base, zone, prev, next);
  64. if(!parent)
  65. zone->subzones = look_for_rapl_zones(control_type, zone, zone_path, depth + 1);
  66. }
  67. }
  68. closedir(dir);
  69. return base;
  70. }
  71. static struct zone_t *get_main_rapl_zones(void) {
  72. struct zone_t *base = NULL;
  73. char dirname[FILENAME_MAX + 1];
  74. snprintfz(dirname, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/devices/virtual/powercap");
  75. DIR *dir = opendir(dirname);
  76. if (unlikely(dir == NULL))
  77. return 0;
  78. struct dirent *de = NULL;
  79. while ((de = readdir(dir))) {
  80. if (de->d_type != DT_DIR || de->d_name[0] == '.')
  81. continue;
  82. if(strncmp(de->d_name, "intel-rapl", 10) != 0)
  83. continue;
  84. char control_type_path[FILENAME_MAX + 1];
  85. snprintfz(control_type_path, FILENAME_MAX, "%s/%s", dirname, de->d_name);
  86. collector_info("Looking at control type \"%s\"", de->d_name);
  87. struct zone_t *zone = look_for_rapl_zones(de->d_name, NULL, control_type_path, 0);
  88. if(zone)
  89. DOUBLE_LINKED_LIST_APPEND_LIST_UNSAFE(base, zone, prev, next);
  90. }
  91. closedir(dir);
  92. return base;
  93. }
  94. int do_sys_devices_virtual_powercap(int update_every, const char *name __maybe_unused) {
  95. if (unlikely(!rapl_zones)) {
  96. rapl_zones = get_main_rapl_zones();
  97. if (unlikely(!rapl_zones)) {
  98. collector_info("Failed to find powercap zones.");
  99. return 1;
  100. }
  101. }
  102. for(struct zone_t *zone = rapl_zones; zone ; zone = zone->next) {
  103. if(!zone->zone_chart_id) {
  104. char id[1000 + 1];
  105. snprintf(id, 1000, "cpu.powercap_intel_rapl_zone_%s", zone->name);
  106. zone->zone_chart_id = strdupz(id);
  107. fprintf(stdout,
  108. "CHART '%s' '' 'Intel RAPL Zone Power Consumption' 'Watts' 'powercap' '%s' '%s' %d %d '' 'debugfs.plugin' 'intel_rapl'\n",
  109. zone->zone_chart_id,
  110. "cpu.powercap_intel_rapl_zone",
  111. debugfs_rrdset_type_name(RRDSET_TYPE_LINE),
  112. NETDATA_CHART_PRIO_POWERCAP,
  113. update_every);
  114. fprintf(stdout,
  115. "CLABEL 'zone' '%s' 1\n"
  116. "CLABEL_COMMIT\n",
  117. zone->name);
  118. fprintf(stdout,
  119. "DIMENSION 'power' '' %s 1 1000000 ''\n",
  120. debugfs_rrd_algorithm_name(RRD_ALGORITHM_INCREMENTAL));
  121. // for the sub-zones
  122. snprintf(id, 1000, "cpu.powercap_intel_rapl_subzones_%s", zone->name);
  123. zone->subzone_chart_id = strdupz(id);
  124. fprintf(stdout,
  125. "CHART '%s' '' 'Intel RAPL Subzones Power Consumption' 'Watts' 'powercap' '%s' '%s' %d %d '' 'debugfs.plugin' 'intel_rapl'\n",
  126. zone->subzone_chart_id,
  127. "cpu.powercap_intel_rapl_subzones",
  128. debugfs_rrdset_type_name(RRDSET_TYPE_LINE),
  129. NETDATA_CHART_PRIO_POWERCAP + 1,
  130. update_every);
  131. fprintf(stdout,
  132. "CLABEL 'zone' '%s' 1\n"
  133. "CLABEL_COMMIT\n",
  134. zone->name);
  135. for(struct zone_t *subzone = zone->subzones; subzone ; subzone = subzone->next) {
  136. fprintf(stdout,
  137. "DIMENSION '%s' '' %s 1 1000000 ''\n",
  138. subzone->name,
  139. debugfs_rrd_algorithm_name(RRD_ALGORITHM_INCREMENTAL));
  140. }
  141. }
  142. if(get_measurement(zone->path, &zone->energy_uj)) {
  143. fprintf(stdout,
  144. "BEGIN '%s'\n"
  145. "SET power = %llu\n"
  146. "END\n"
  147. , zone->zone_chart_id
  148. , zone->energy_uj);
  149. }
  150. if(zone->subzones) {
  151. fprintf(stdout,
  152. "BEGIN '%s'\n",
  153. zone->subzone_chart_id);
  154. for (struct zone_t *subzone = zone->subzones; subzone; subzone = subzone->next) {
  155. if(get_measurement(subzone->path, &subzone->energy_uj)) {
  156. fprintf(stdout,
  157. "SET '%s' = %llu\n",
  158. subzone->name,
  159. subzone->energy_uj);
  160. }
  161. }
  162. fprintf(stdout, "END\n");
  163. }
  164. }
  165. fflush(stdout);
  166. return 0;
  167. }