Create sensor for all RAPLs. - energy - measure energy usage
 (HTM) git clone git://bitreich.org/energy  git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/energy
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) Tags
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit e7b10a359ff7396defb7e36dfe9f78b3c9d73b13
 (DIR) parent 3b9da8cb1c2fcacd4570f25d02194124e526caa2
 (HTM) Author: Troels Henriksen <athas@sigkill.dk>
       Date:   Thu, 24 Aug 2023 16:59:46 +0200
       
       Create sensor for all RAPLs.
       
       Diffstat:
         M energy.c                            |      79 +++++++++++++++++++++++--------
       
       1 file changed, 59 insertions(+), 20 deletions(-)
       ---
 (DIR) diff --git a/energy.c b/energy.c
       @@ -16,14 +16,27 @@
        //
        // https://www.kernel.org/doc/html/latest/power/power_supply_class.html
        
       +#include <assert.h>
       +#include <dirent.h>
        #include <errno.h>
       +#include <stdarg.h>
        #include <stdio.h>
        #include <stdlib.h>
        #include <string.h>
       -#include <sys/wait.h>
        #include <sys/stat.h>
       +#include <sys/wait.h>
        #include <unistd.h>
       -#include <assert.h>
       +
       +// Allocates and returns a string of appropriate size.
       +static char* strprintf(const char *s, ...) {
       +  va_list vl;
       +  va_start(vl, s);
       +  size_t needed = 1 + (size_t)vsnprintf(NULL, 0, s, vl);
       +  char *buffer = (char*) malloc(needed);
       +  va_start(vl, s); // Must re-init.
       +  vsnprintf(buffer, needed, s, vl);
       +  return buffer;
       +}
        
        struct sensor {
          const char *name;
       @@ -45,9 +58,6 @@ void add_sensor(struct sensor s) {
          sensors[num_sensors++] = s;
        }
        
       -const char *rapl_energy_uj =
       -  "/sys/class/powercap/intel-rapl/intel-rapl:0/energy_uj";
       -
        long long_from_file(const char *fname) {
          FILE *f = fopen(fname, "r");
          if (f == NULL) {
       @@ -64,32 +74,61 @@ long long_from_file(const char *fname) {
          }
        }
        
       +struct rapl {
       +  long counter;
       +  char* energy_uj;
       +};
       +
        void sensor_rapl_start(void* data) {
       -  *(long*)data = long_from_file(rapl_energy_uj);
       +  struct rapl* rapl = (struct rapl*)data;
       +  rapl->counter = long_from_file(rapl->energy_uj);
        }
        
        void sensor_rapl_end(void* data) {
       -  *(long*)data = long_from_file(rapl_energy_uj) - *(long*)data;
       +  struct rapl* rapl = (struct rapl*)data;
       +  rapl->counter = long_from_file(rapl->energy_uj) - rapl->counter;
        }
        
        double sensor_rapl_usage(void* data) {
       +  struct rapl* rapl = (struct rapl*)data;
          // Convert microjoules to joules.
       -  return (double)*(long*)data / 1e6;
       +  return (double)rapl->counter / 1e6;
        }
        
       -void sensor_rapl(void) {
       -  FILE *f = fopen(rapl_energy_uj, "r");
       -  if (f == NULL) {
       -    fprintf(stderr, "%s: %s\n", rapl_energy_uj, strerror(errno));
       -  } else {
       -    fclose(f);
       -    long* start = malloc(sizeof(long));
       -    add_sensor((struct sensor) { .name = "RAPL0",
       -                                 .data = start,
       -                                 .start = sensor_rapl_start,
       -                                 .end = sensor_rapl_end,
       -                                 .usage = sensor_rapl_usage});
       +void sensor_rapl() {
       +  const char* rapl_path = "/sys/class/powercap/intel-rapl";
       +  DIR* d = opendir(rapl_path);
       +
       +  if (d == NULL) {
       +    return;
          }
       +
       +  struct dirent* dirent;
       +
       +  while ((dirent = readdir(d)) != NULL) {
       +    if (dirent->d_type == DT_DIR) {
       +      char* rapl_energy_uj = strprintf("%s/%s/energy_uj", rapl_path, dirent->d_name);
       +      errno = 0;
       +      FILE *f = fopen(rapl_energy_uj, "r");
       +      if (f == NULL) {
       +        if (errno != ENOENT) {
       +          fprintf(stderr, "%s: %s\n", rapl_energy_uj, strerror(errno));
       +        }
       +        free(rapl_energy_uj);
       +      } else {
       +        fclose(f);
       +        struct rapl *rapl = malloc(sizeof(struct rapl));
       +        rapl->energy_uj = rapl_energy_uj;
       +        add_sensor((struct sensor) { .name = strdup(dirent->d_name),
       +                                     .data = rapl,
       +                                     .start = sensor_rapl_start,
       +                                     .end = sensor_rapl_end,
       +                                     .usage = sensor_rapl_usage});
       +      }
       +    }
       +  }
       +
       +  closedir(d);
        }
        
        const char *battery_status =