ienergy.c - energy - measure energy usage Err bitreich.org 70 hgit clone git://bitreich.org/energy git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/energy URL:git://bitreich.org/energy git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/energy bitreich.org 70 1Log /scm/energy/log.gph bitreich.org 70 1Files /scm/energy/files.gph bitreich.org 70 1Refs /scm/energy/refs.gph bitreich.org 70 1Tags /scm/energy/tag bitreich.org 70 1README /scm/energy/file/README.md.gph bitreich.org 70 1LICENSE /scm/energy/file/LICENSE.gph bitreich.org 70 i--- Err bitreich.org 70 ienergy.c (5734B) Err bitreich.org 70 i--- Err bitreich.org 70 i 1 // Like time(1), but for power consumption. Err bitreich.org 70 i 2 // Err bitreich.org 70 i 3 // Using the Linux RAPL interface provided in /sys, prints the energy Err bitreich.org 70 i 4 // used by the CPU while running the given command. Note that this is Err bitreich.org 70 i 5 // total system energy consumption; not just the energy consumed by Err bitreich.org 70 i 6 // the indicated command. Run this on an otherwise quiet system if Err bitreich.org 70 i 7 // you want to see power consumption of a single command. Err bitreich.org 70 i 8 // Err bitreich.org 70 i 9 // Probably needs to run with root permissions. Err bitreich.org 70 i 10 // Err bitreich.org 70 i 11 // Copyright Troels Henriksen Err bitreich.org 70 i 12 // Err bitreich.org 70 i 13 // See LICENSE file for licensing information. Err bitreich.org 70 i 14 Err bitreich.org 70 i 15 // Useful resources for sensors: Err bitreich.org 70 i 16 // Err bitreich.org 70 i 17 // https://www.kernel.org/doc/html/latest/power/power_supply_class.html Err bitreich.org 70 i 18 Err bitreich.org 70 i 19 #include Err bitreich.org 70 i 20 #include Err bitreich.org 70 i 21 #include Err bitreich.org 70 i 22 #include Err bitreich.org 70 i 23 #include Err bitreich.org 70 i 24 #include Err bitreich.org 70 i 25 #include Err bitreich.org 70 i 26 #include Err bitreich.org 70 i 27 #include Err bitreich.org 70 i 28 #include Err bitreich.org 70 i 29 Err bitreich.org 70 i 30 // Allocates and returns a string of appropriate size. Err bitreich.org 70 i 31 static char* strprintf(const char *s, ...) { Err bitreich.org 70 i 32 va_list vl; Err bitreich.org 70 i 33 va_start(vl, s); Err bitreich.org 70 i 34 size_t needed = 1 + (size_t)vsnprintf(NULL, 0, s, vl); Err bitreich.org 70 i 35 char *buffer = (char*) malloc(needed); Err bitreich.org 70 i 36 va_start(vl, s); // Must re-init. Err bitreich.org 70 i 37 vsnprintf(buffer, needed, s, vl); Err bitreich.org 70 i 38 return buffer; Err bitreich.org 70 i 39 } Err bitreich.org 70 i 40 Err bitreich.org 70 i 41 struct sensor { Err bitreich.org 70 i 42 const char *name; Err bitreich.org 70 i 43 void* data; Err bitreich.org 70 i 44 void (*start)(void*); Err bitreich.org 70 i 45 void (*end)(void*); Err bitreich.org 70 i 46 double (*usage)(void*); // Should return joules Err bitreich.org 70 i 47 }; Err bitreich.org 70 i 48 Err bitreich.org 70 i 49 int num_sensors = 0; Err bitreich.org 70 i 50 int cap_sensors = 0; Err bitreich.org 70 i 51 struct sensor *sensors = NULL; Err bitreich.org 70 i 52 Err bitreich.org 70 i 53 void add_sensor(struct sensor s) { Err bitreich.org 70 i 54 if (num_sensors == cap_sensors) { Err bitreich.org 70 i 55 cap_sensors += 10; Err bitreich.org 70 i 56 sensors = realloc(sensors, cap_sensors * sizeof(struct sensor)); Err bitreich.org 70 i 57 } Err bitreich.org 70 i 58 sensors[num_sensors++] = s; Err bitreich.org 70 i 59 } Err bitreich.org 70 i 60 Err bitreich.org 70 i 61 long long_from_file(const char *fname) { Err bitreich.org 70 i 62 FILE *f = fopen(fname, "r"); Err bitreich.org 70 i 63 if (f == NULL) { Err bitreich.org 70 i 64 fprintf(stderr, "%s: %s\n", fname, strerror(errno)); Err bitreich.org 70 i 65 return -1; Err bitreich.org 70 i 66 } else { Err bitreich.org 70 i 67 long x; Err bitreich.org 70 i 68 if (fscanf(f, "%ld", &x) < 0) { Err bitreich.org 70 i 69 fprintf(stderr, "%s: %s\n", fname, strerror(errno)); Err bitreich.org 70 i 70 return -1; Err bitreich.org 70 i 71 } Err bitreich.org 70 i 72 fclose(f); Err bitreich.org 70 i 73 return x; Err bitreich.org 70 i 74 } Err bitreich.org 70 i 75 } Err bitreich.org 70 i 76 Err bitreich.org 70 i 77 struct rapl { Err bitreich.org 70 i 78 long counter; Err bitreich.org 70 i 79 char* energy_uj; Err bitreich.org 70 i 80 }; Err bitreich.org 70 i 81 Err bitreich.org 70 i 82 void sensor_rapl_start(void* data) { Err bitreich.org 70 i 83 struct rapl* rapl = (struct rapl*)data; Err bitreich.org 70 i 84 rapl->counter = long_from_file(rapl->energy_uj); Err bitreich.org 70 i 85 } Err bitreich.org 70 i 86 Err bitreich.org 70 i 87 void sensor_rapl_end(void* data) { Err bitreich.org 70 i 88 struct rapl* rapl = (struct rapl*)data; Err bitreich.org 70 i 89 rapl->counter = long_from_file(rapl->energy_uj) - rapl->counter; Err bitreich.org 70 i 90 } Err bitreich.org 70 i 91 Err bitreich.org 70 i 92 double sensor_rapl_usage(void* data) { Err bitreich.org 70 i 93 struct rapl* rapl = (struct rapl*)data; Err bitreich.org 70 i 94 // Convert microjoules to joules. Err bitreich.org 70 i 95 return (double)rapl->counter / 1e6; Err bitreich.org 70 i 96 } Err bitreich.org 70 i 97 Err bitreich.org 70 i 98 void sensor_rapl() { Err bitreich.org 70 i 99 const char* rapl_path = "/sys/class/powercap/intel-rapl"; Err bitreich.org 70 i 100 DIR* d = opendir(rapl_path); Err bitreich.org 70 i 101 Err bitreich.org 70 i 102 if (d == NULL) { Err bitreich.org 70 i 103 return; Err bitreich.org 70 i 104 } Err bitreich.org 70 i 105 Err bitreich.org 70 i 106 struct dirent* dirent; Err bitreich.org 70 i 107 Err bitreich.org 70 i 108 while ((dirent = readdir(d)) != NULL) { Err bitreich.org 70 i 109 if (dirent->d_type == DT_DIR) { Err bitreich.org 70 i 110 char* rapl_energy_uj = strprintf("%s/%s/energy_uj", rapl_path, dirent->d_name); Err bitreich.org 70 i 111 errno = 0; Err bitreich.org 70 i 112 FILE *f = fopen(rapl_energy_uj, "r"); Err bitreich.org 70 i 113 if (f == NULL) { Err bitreich.org 70 i 114 if (errno != ENOENT) { Err bitreich.org 70 i 115 fprintf(stderr, "%s: %s\n", rapl_energy_uj, strerror(errno)); Err bitreich.org 70 i 116 } Err bitreich.org 70 i 117 free(rapl_energy_uj); Err bitreich.org 70 i 118 } else { Err bitreich.org 70 i 119 fclose(f); Err bitreich.org 70 i 120 struct rapl *rapl = malloc(sizeof(struct rapl)); Err bitreich.org 70 i 121 rapl->energy_uj = rapl_energy_uj; Err bitreich.org 70 i 122 add_sensor((struct sensor) { .name = strdup(dirent->d_name), Err bitreich.org 70 i 123 .data = rapl, Err bitreich.org 70 i 124 .start = sensor_rapl_start, Err bitreich.org 70 i 125 .end = sensor_rapl_end, Err bitreich.org 70 i 126 .usage = sensor_rapl_usage}); Err bitreich.org 70 i 127 } Err bitreich.org 70 i 128 } Err bitreich.org 70 i 129 } Err bitreich.org 70 i 130 Err bitreich.org 70 i 131 closedir(d); Err bitreich.org 70 i 132 } Err bitreich.org 70 i 133 Err bitreich.org 70 i 134 const char *battery_status = Err bitreich.org 70 i 135 "/sys/class/power_supply/BAT0/status"; Err bitreich.org 70 i 136 Err bitreich.org 70 i 137 const char *battery_energy = Err bitreich.org 70 i 138 "/sys/class/power_supply/BAT0/energy_now"; Err bitreich.org 70 i 139 Err bitreich.org 70 i 140 void sensor_battery_start(void* data) { Err bitreich.org 70 i 141 *(long*)data = long_from_file(battery_energy); Err bitreich.org 70 i 142 } Err bitreich.org 70 i 143 Err bitreich.org 70 i 144 void sensor_battery_end(void* data) { Err bitreich.org 70 i 145 *(long*)data = *(long*)data - long_from_file(battery_energy); Err bitreich.org 70 i 146 } Err bitreich.org 70 i 147 Err bitreich.org 70 i 148 double sensor_battery_usage(void* data) { Err bitreich.org 70 i 149 // Convert micro-Wh to joules. Err bitreich.org 70 i 150 return ((double)*(long*)data) / 1e6 * 3600; Err bitreich.org 70 i 151 } Err bitreich.org 70 i 152 Err bitreich.org 70 i 153 void sensor_battery(void) { Err bitreich.org 70 i 154 FILE *f = fopen(battery_status, "r"); Err bitreich.org 70 i 155 if (f == NULL) { Err bitreich.org 70 i 156 if (errno != ENOENT) { Err bitreich.org 70 i 157 // Don't complain just because this system does not have a Err bitreich.org 70 i 158 // battery. Err bitreich.org 70 i 159 fprintf(stderr, "%s: %s\n", battery_status, strerror(errno)); Err bitreich.org 70 i 160 } Err bitreich.org 70 i 161 } else { Err bitreich.org 70 i 162 char buf[128]; Err bitreich.org 70 i 163 if (fread(buf, 1, sizeof(buf), f) < 1) { Err bitreich.org 70 i 164 fprintf(stderr, "%s: %s\n", battery_status, strerror(errno)); Err bitreich.org 70 i 165 return; Err bitreich.org 70 i 166 } Err bitreich.org 70 i 167 const char discharging[] = "Discharging"; Err bitreich.org 70 i 168 // Measurement of battery discharge is only meaningful if the Err bitreich.org 70 i 169 // battery is actually discharging. Err bitreich.org 70 i 170 if (memcmp(buf, discharging, sizeof(discharging)-1) == 0) { Err bitreich.org 70 i 171 long* start = malloc(sizeof(long)); Err bitreich.org 70 i 172 add_sensor((struct sensor) { .name = "BAT0", Err bitreich.org 70 i 173 .data = start, Err bitreich.org 70 i 174 .start = sensor_battery_start, Err bitreich.org 70 i 175 .end = sensor_battery_end, Err bitreich.org 70 i 176 .usage = sensor_battery_usage}); Err bitreich.org 70 i 177 Err bitreich.org 70 i 178 } Err bitreich.org 70 i 179 } Err bitreich.org 70 i 180 } Err bitreich.org 70 i 181 Err bitreich.org 70 i 182 int main(int argc, char** argv) { Err bitreich.org 70 i 183 if (argc < 2) { Err bitreich.org 70 i 184 printf("Usage: %s [args...]\n", argv[0]); Err bitreich.org 70 i 185 return 1; Err bitreich.org 70 i 186 } Err bitreich.org 70 i 187 Err bitreich.org 70 i 188 sensor_rapl(); Err bitreich.org 70 i 189 sensor_battery(); Err bitreich.org 70 i 190 Err bitreich.org 70 i 191 if (num_sensors == 0) { Err bitreich.org 70 i 192 fprintf(stderr, "%s: no sensors found; not running command.\n", argv[0]); Err bitreich.org 70 i 193 exit(1); Err bitreich.org 70 i 194 } Err bitreich.org 70 i 195 Err bitreich.org 70 i 196 for (int i = 0; i < num_sensors; i++) { Err bitreich.org 70 i 197 sensors[i].start(sensors[i].data); Err bitreich.org 70 i 198 } Err bitreich.org 70 i 199 Err bitreich.org 70 i 200 int pid; Err bitreich.org 70 i 201 if ((pid = fork()) == 0) { Err bitreich.org 70 i 202 execvp(argv[1], argv+1); Err bitreich.org 70 i 203 fprintf(stderr, "%s: %s\n", argv[1], strerror(errno)); Err bitreich.org 70 i 204 exit(1); Err bitreich.org 70 i 205 } Err bitreich.org 70 i 206 Err bitreich.org 70 i 207 int status; Err bitreich.org 70 i 208 waitpid(pid, &status, 0); Err bitreich.org 70 i 209 Err bitreich.org 70 i 210 for (int i = 0; i < num_sensors; i++) { Err bitreich.org 70 i 211 sensors[i].end(sensors[i].data); Err bitreich.org 70 i 212 } Err bitreich.org 70 i 213 Err bitreich.org 70 i 214 for (int i = 0; i < num_sensors; i++) { Err bitreich.org 70 i 215 fprintf(stderr, "%-8s %6.2f J\n", sensors[i].name, sensors[i].usage(sensors[i].data)); Err bitreich.org 70 i 216 } Err bitreich.org 70 i 217 } Err bitreich.org 70 .