Skip to content

Commit

Permalink
Allow to measure the power consumption
Browse files Browse the repository at this point in the history
  • Loading branch information
kitsunyan committed Jan 14, 2019
1 parent 1df60ea commit 0b180b6
Show file tree
Hide file tree
Showing 6 changed files with 155 additions and 3 deletions.
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@ all: \

intel_undervolt_headers = \
config.h \
measure.h \
modes.h \
undervolt.h \
util.h

intel_undervolt_sources = \
config.c \
measure.c \
main.c \
modes.c \
undervolt.c \
Expand Down
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,18 @@ is subtracted from max temperature level. For example, `tjoffset -20`. If max te
is set to 100, the resulting limit will be set to `100 - 20 = 80°C`. Note that offsets
higher than 15°C are allowed only on Skylake and newer.

## Usage

### Applying Configuration

Run `intel-undervolt read` to read current values and `intel-undervolt apply` to apply configured
values. You can apply your configuration automatically enabling `intel-undervolt.service`.

### Measuring the Power Consumption

`intel_rapl` module is required to measure the power consumption. Run `intel-undervolt measure` to
display power consumption in interactive mode.

### Daemon Mode

Sometimes power and temperature limits could be reset by EC, BIOS, or something else. This behavior
Expand Down
4 changes: 4 additions & 0 deletions main.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include "measure.h"
#include "modes.h"

#include <stdio.h>
Expand All @@ -9,13 +10,16 @@ int main(int argc, char ** argv) {
return read_apply_mode(false) ? 0 : 1;
} else if (argc == 2 && !strcmp(argv[1], "apply")) {
return read_apply_mode(true) ? 0 : 1;
} else if (argc == 2 && !strcmp(argv[1], "measure")) {
return measure_mode();
} else if (argc == 2 && !strcmp(argv[1], "daemon")) {
return daemon_mode() ? 0 : 1;
} else {
fprintf(stderr,
"Usage: intel-undervolt COMMAND\n"
" read Read and display current values\n"
" apply Apply values from config file\n"
" measure Measure power consumption\n"
" daemon Run in daemon mode\n");
return argc == 1 ? 0 : 1;
}
Expand Down
133 changes: 133 additions & 0 deletions measure.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
#include "measure.h"

#include <dirent.h>
#include <fcntl.h>
#include <signal.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>

#define POWERCAP "/sys/class/powercap"
#define BUFSZ 80

typedef struct {
void * next;
char * name;
char * dir;
int64_t last;
struct timespec time;
} rapl_list_t;

static void print_next(rapl_list_t * ilst, int maxname, char * buf) {
if (!ilst) {
/* clear the screen */
printf("\033[H\033[J");
fflush(0);
return;
}
print_next(ilst->next, maxname, buf);

sprintf(buf, POWERCAP "/%s/energy_uj", ilst->dir);
int fd = open(buf, O_RDONLY);
if (fd >= 0) {
int count = read(fd, buf, BUFSZ - 1);
if (count > 0) {
buf[buf[count - 1] == '\n' ? count - 1 : count] = '\0';
int64_t val = (int64_t) atoll(buf);
struct timespec tnow;
clock_gettime(CLOCK_MONOTONIC, &tnow);
if (ilst->last > 0) {
struct timespec tdiff;
tdiff.tv_sec = tnow.tv_sec - ilst->time.tv_sec;
tdiff.tv_nsec = tnow.tv_nsec - ilst->time.tv_nsec;
while (tdiff.tv_nsec < 0) {
tdiff.tv_nsec += 1000000000;
tdiff.tv_sec--;
}
int64_t diff = (int64_t) (tdiff.tv_sec * 1000000000 +
tdiff.tv_nsec);
double dval = (double) (val - ilst->last) * 1000 / diff;
int len = strlen(ilst->name);
write(0, ilst->name, len);
write(0, ":", 1);
int i;
for (i = len - 1; i < maxname; i++) {
write(0, " ", 1);
}
printf("%7.03f W\n", ilst->name, dval);
}
ilst->last = val;
ilst->time = tnow;
}
close(fd);
}
}

static bool interrupted;

static void sigint_handler(int sig) {
interrupted = true;
}

int measure_mode() {
char buf[BUFSZ];
rapl_list_t * glst = NULL;
int maxname = 0;

DIR * dir = opendir(POWERCAP);
if (dir == NULL) {
fprintf(stderr, "Failed to open powercap directory\n");
return 1;
}
struct dirent * dirent;
while (dirent = readdir(dir)) {
if (strstr(dirent->d_name, ":") && strlen(dirent->d_name) <= 30) {
sprintf(buf, POWERCAP "/%s/name", dirent->d_name);
int fd = open(buf, O_RDONLY);
if (fd >= 0) {
int count = read(fd, buf, BUFSZ - 1);
if (count > 1) {
int nlen = buf[count - 1] == '\n' ? count - 2 : count - 1;
buf[nlen + 1] = '\0';
rapl_list_t * nlst = malloc(sizeof(rapl_list_t));
nlst->next = glst;
glst = nlst;
nlst->name = malloc(nlen + 1);
memcpy(nlst->name, buf, nlen + 1);
int dlen = strlen(dirent->d_name);
nlst->dir = malloc(dlen + 1);
memcpy(nlst->dir, dirent->d_name, dlen + 1);
nlst->last = 0;
maxname = nlen > maxname ? nlen : maxname;
}
close(fd);
}
}
}
closedir(dir);

interrupted = false;
struct sigaction act;
memset(&act, 0, sizeof(struct sigaction));
act.sa_handler = sigint_handler;
sigaction(SIGINT, &act, NULL);

while (!interrupted) {
print_next(glst, maxname, buf);
sleep(1);
}

while (glst) {
rapl_list_t * nlst = glst->next;
free(glst->name);
free(glst->dir);
free(glst);
glst = nlst;
}

return 0;
}
6 changes: 6 additions & 0 deletions measure.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#ifndef __MEASURE_H__
#define __MEASURE_H__

int measure_mode();

#endif
6 changes: 3 additions & 3 deletions undervolt.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,10 @@ typedef struct {
bool success;
bool * nl;
bool nll;
} undervolt_ctx;
} undervolt_ctx_t;

static void undervolt_it(uv_list_t * uv, void * data) {
undervolt_ctx * ctx = data;
undervolt_ctx_t * ctx = data;

static int mask = 0x800;
uint64_t uvint = ((uint64_t) (mask - absf(uv->value) * 1.024f + 0.5f)
Expand Down Expand Up @@ -83,7 +83,7 @@ static void undervolt_it(uv_list_t * uv, void * data) {

bool undervolt(config_t * config, bool * nl, bool write) {
if (config->uv) {
undervolt_ctx ctx;
undervolt_ctx_t ctx;
ctx.config = config;
ctx.write = write;
ctx.success = true;
Expand Down

0 comments on commit 0b180b6

Please sign in to comment.