plasma-applet-resources-monitor icon indicating copy to clipboard operation
plasma-applet-resources-monitor copied to clipboard

[FEAT] power (watt) graph

Open Rongronggg9 opened this issue 9 months ago • 10 comments

Is your feature request related to a problem? Please describe.

For laptop users, monitoring power consumption will be useful.

Describe the solution you'd like

A new graph, monitoring:

  1. intel-rapl driver, providing package-* (CPU package power), core, uncore, and psys (the power consumption of the whole device, available on modern laptops and Intel NUCs), etc
  2. amd_energy driver
  3. /sys/class/power_supply/BAT0/power_now (maybe TODO for the time being, as it has a polarity, which is hard to show in the graph)
  4. more power measurement sources (TODO?)

1 requires users to chmod a+r the corresponding sysfs files after boot. I don't have an AMD PC so I am not sure about 2.

Describe alternatives you've considered

No response

Additional context

https://github.com/amanusk/s-tui/blob/master/s_tui/sources/rapl_read.py https://github.com/kphanipavan/cpu-power-monitor/blob/main/package/contents/ui/main.qml https://github.com/atul-g/plasma-power-monitor/blob/main/package/contents/ui/main.qml https://www.kernel.org/doc/html/next/power/powercap/powercap.html https://web.eece.maine.edu/~vweaver/projects/rapl/rapl_support.html

Rongronggg9 avatar Sep 17 '23 17:09 Rongronggg9

Hello, Thanks for proposal and many resources.

I plan this for 3.x due to feature freeze for 2.x so currently i don't have ETA.

orblazer avatar Sep 18 '23 10:09 orblazer

Hello, The 3.0 starting to have an roadmap and date due to Plasma 6 release.

Also for that release i need yours advice if you want, on where and how i release it, you just have to answer at the poll here: https://github.com/orblazer/plasma-applet-resources-monitor/discussions/68.

Thanks.

orblazer avatar Feb 09 '24 03:02 orblazer

Hello, Could you check if you could retrieve the informations in System Monitor application ?

Steps for doing that :

  1. Create an new page in app
  2. search different power related sensors (currently i know gpu/gpu0/power for GPU consumption, power for unknown?)
  3. save the page with select sensors
  4. share the file of that page (stored in ~/.local/share/plasma-systemmonitor/)

Since in 3.0 is very more modular, i think this feature should be reported to 3.1 due to i missing some infos and way to done it properly.

orblazer avatar Mar 30 '24 20:03 orblazer

As far as I am concerned, only /sys/class/power_supply/BAT0/power_now can be retrieved directly from KDE.

[Face-95878370734704][Sensors]
highPrioritySensorIds=["power/941/chargeRate"]
totalSensors=[]

As for calculating power consumption from the intel-rapl driver in QML, please refer to https://github.com/kphanipavan/cpu-power-monitor/blob/main/package/contents/ui/main.qml. I've seen https://github.com/orblazer/plasma-applet-resources-monitor/blob/release-3.0/package/contents/ui/code/network.js does a similar calculation for netdev.

As for the amd_energy (as well as intel-rapl) driver, please refer to https://github.com/amanusk/s-tui/blob/master/s_tui/sources/rapl_read.py.

Rongronggg9 avatar Apr 01 '24 05:04 Rongronggg9

Thanks for the reply, Do you think an chart is useful for that ? Cause i think we can simply add it to CPU/GPU graphs in choose for the third line (with temperature).

Or if we do 1 new graph, i have multiple idea to represent it :

  • 1 chart for Total (maybe we need an special case for laptop and use /sys/class/power_supply/BAT0/power_now instead of cumulative RAPL + GPUs, due to consumption of screen, wifi, etc)
  • OR (can be be choose by user) :
    • 1 chart for RAPL consumption
    • 1 chart for GPUs (maybe adding all)

I think that way provide enough data and configuration for most users.

orblazer avatar Apr 01 '24 14:04 orblazer

Thanks for the reply,

Thanks for the wonderful plasmoid ;-)

Do you think an chart is useful for that ? Cause i think we can simply add it to CPU/GPU graphs in choose for the third line (with temperature).

That would be fine for core or package-* power, but not psys.

Or if we do 1 new graph, i have multiple idea to represent it :

  • 1 chart for Total (maybe we need an special case for laptop and use /sys/class/power_supply/BAT0/power_now instead of cumulative RAPL + GPUs, due to consumption of screen, wifi, etc)

You don't always need to calculate CPU package + GPU, as long as RAPL psys is available.

RAPL psys: 🔺Overall power consumption. 🔺Always accurate and has infinite refresh rate. 🔺Still able to measure overall power consumption even when charging. 🔺Also available on some desktop PCs, e.g. Intel NUC. 🔻Unable to measure battery charge rate. 🔻Only available on some recent PCs/laptops using Intel CPU.

/sys/class/power_supply/BAT0/power_now: 🔺Able to measure battery charge rate. 🔸Available on most laptops, but not PCs. 🔸Has polarity. 🔻Accuracy depends on the design. May completely be noise on some laptop. 🔻Low refresh rate. 🔻Only able to measure overall power consumption when discharging and when the laptop is well-designed.

CPU package + GPU: 🔺Always available. 🔺Always accurate and has infinite refresh rate. 🔺Still able to measure CPU + GPU power consumption even when charging. 🔻Unable to measure battery charge rate. 🔻Unable to measure overall power consumption.

  • OR (can be be choose by user) :
    • 1 chart for RAPL consumption
    • 1 chart for GPUs (maybe adding all)

That's fine too. But IMHO it would be better if all the additional charts can be customizable, i.e., selecting among the above options (CPU core/uncore/package-*, RAPL psys, battery, CPU + GPU, GPU, etc).

Rongronggg9 avatar Apr 01 '24 17:04 Rongronggg9

OH thanks for a lot of informations !

After digging more into intel-rapl it's seem to provide almost everything that graph can need (except battery charging state, and GPUs consumption), so this is my current state of thinking about that feature :

  • adding an action to right click ONLY when that graph is present (for fix permission)
  • write "PERM" in red, when files can't be reads
  • in settings:
    • call it : Power usage
    • mark it as "experimental" for now (with ref to that issue)
    • adding an warning message about the risk of granting read permission. (cf. https://platypusattack.com/)
    • adding an warning message when file is not readable (+ button to grant permission)
    • options for first chart : Total (sum cpu+dram+GPUs, this should use psys+GPUs if available) / CPU
    • options for second chart : None / GPUs (only if some GPUs power is available)
    • options for third line (no chart cause value is very low, and disabled if first is set to total) : None / Memory
    • option to showing charging status (only if battery present) - this should show 🗲 at suffix to first line

Currently i have to answer to this following questions :

  1. What we need for uplimit (user value, automatic) ?
  2. It is useful to have an third chart ?
  3. Do we need support for choosing specific GPU ?
  4. It is useful to have some "threshold" ? If yes, only first chart or second too ?
  5. It is useful to add "Battery" graph too (except the percentage what the interest) ? If yes, do we need support for multiple batteries ?

Note: if i have the time, this could be implement to 3.0 release, but no guarantee on that ETA.

orblazer avatar Apr 02 '24 03:04 orblazer

  • adding an warning message about the risk of granting read permission. (cf. platypusattack.com)

Working around the vulnerability is possible. IMO adding a random number to it should be able to prevent side-channel attacks. This requires plasma-applet-resources-monitor to be able to read energy_uj by executing a program.

Disclaimer: I am not a security specialist. Thus, this is not a suggestion that plasma-applet-resources-monitor should be bundled with the below program. Instead, I suggest writing an FAQ and link to the issue for those who really care about side-channel attacks.

For example:

/* SPDX-License-Identifier: MIT */

#include <sys/random.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <ctype.h>
#include <inttypes.h>

#define RAND_BYTES 2
#define RAND_FLAGS 0

#define RAND_TARGET 1024  //

#define USAGE "Usage: %s [-m] <num>[:<num>[:<num>[...]]]\n"
#define print_usage() {             \
    fprintf(stderr, USAGE, prog);   \
    exit(EXIT_FAILURE);             \
}

#define err_exit(msg) {             \
    fprintf(stderr, msg);           \
    exit(EXIT_FAILURE);             \
}
#define perr_exit(msg) {            \
    perror(msg);                    \
    exit(EXIT_FAILURE);             \
}

#define RAPL_TEMPLATE "/sys/class/powercap/intel-rapl:%s/energy_uj"
#define RAPL_MMIO_TEMPLATE "/sys/class/powercap/intel-rapl-mmio:%s/energy_uj"

#if (RAND_BYTES < 1 || RAND_BYTES > 4)
#error "1 <= RAND_BTYES <= 4"
#endif

char* prog = NULL;

int64_t gen_rand() {
    int64_t rand = 0;

    /* Generate rand */
    ssize_t rand_bytes = getrandom(&rand, RAND_BYTES, RAND_FLAGS);
    if (rand_bytes != RAND_BYTES)
        err_exit("getrandom() failed");

    /* Scale rand */
    return rand % (RAND_TARGET * 2) - RAND_TARGET;
}

int64_t read_randomized(const char* path) {
    int64_t num = 0;
    FILE* file = fopen(path, "r");
    if (file == NULL)
        perr_exit("Error opening file");
    fscanf(file, "%" PRId64, &num);
    fclose(file);
    num += gen_rand();
    if (num < 0)
        num = 0;
    return num;
}

/* Check the format of the positional argument: "/d+(:/d+)*" */
bool check_path_part(const char* part) {
    char c;
    bool last_is_num = false;
    for (int i = 0; (c = part[i]) != '\0'; ++i) {
        if (i >= 128)
            err_exit("the positional argument is too long");
        if (isdigit(c)) {
            last_is_num = true;
        } else if (c == ':') {
            if (!last_is_num)
                return false;
            last_is_num = false;
        } else {
            return false;
        }
    }
    if (last_is_num)
        return true;
    return false;
}

int main(int argc, char* argv[]) {
    int opt = 0;
    bool mmio_flag = false;
    char full_path[256] = {0};

    prog = argv[0];

    /* Check options */
    while ((opt = getopt(argc, argv, "m")) != -1) {
        switch (opt) {
            case 'm':
                mmio_flag = true;
                break;
            default:
                print_usage();
        }
    }

    /* Check positional arguments */
    if (argc < 2 || argc > 3 || optind != argc - 1)
        print_usage();
    if (!check_path_part(argv[optind]))
        print_usage();

    /* Format path and perform randomized read */
    sprintf(
        full_path,
         mmio_flag ? RAPL_MMIO_TEMPLATE : RAPL_TEMPLATE,
        argv[optind]
    );
    printf("%" PRId64 "\n", read_randomized(full_path));
    return 0;
}
  1. Compile and setgid the helper

[!TIP] Writing an equivalent helper in other languages should be easy. However, setgid does not apply shebang scripts, so I wrote it in C here.

gcc rapl_helper.c -O3 -Wall -Werror -o rapl_helper
sudo groupadd -r rapl_helper
sudo install -o root -g rapl_helper -Dsm2755 rapl_helper /usr/local/bin
  1. Set owner group (at every boot, e.g., via a systems service)
chgrp rapl_helper /sys/class/powercap/intel-rapl{,-mmio}:*/energy_uj
chmod g+r /sys/class/powercap/intel-rapl{,-mmio}:*/energy_uj
  1. Now an unprivileged user can read energy_uj with a random number added
rapl_helper 0     # package 0
rapl_helper 0:0   # core
rapl_helper 0:1   # uncore
rapl_helper 0:2   # dram
rapl_helper 1     # psys
rapl_helper -m 0  # package 0 (via MMIO)

Currently i have to answer to this following questions :

  1. What we need for uplimit (user value, automatic) ?

A user-defined value should be enough for laptop users, as the volatility of the power consumption on a laptop is low. In contrast, desktop users may want it to be automatic.

  1. It is useful to have an third chart ?

IMHO it is not so useful. The memory consumption of DRAM is low, as well as its volatility. Monitoring it may not be so meaningful.

  1. Do we need support for choosing specific GPU ?

I don't have much idea about the question as I don't have multiple GPUs installed.

  1. It is useful to have some "threshold" ? If yes, only first chart or second too ?

The threshold to what? Did you mean only display a chart when the threshold is reached? I think it is useful for the GPU chart (i.e., the second chart).

  1. It is useful to add "Battery" graph too (except the percentage what the interest) ? If yes, do we need support for multiple batteries ?

I agree that a battery percentage graph will be useful. However, it needs a much slower refresh rate than other graphs, so it cannot be updated simultaneously with other charts.

Rongronggg9 avatar Apr 14 '24 14:04 Rongronggg9

Thanks for informations.

Working around the vulnerability is possible. IMO adding a random number to it should be able to prevent side-channel attacks. This requires plasma-applet-resources-monitor to be able to read energy_uj by executing a program.

Disclaimer: I am not a security specialist. Thus, this is not a suggestion that plasma-applet-resources-monitor should be bundled with the below program. Instead, I suggest writing an FAQ and link to the issue for those who really care about side-channel attacks. ...

Yes i think an warn and link to FAQ on readme to explain the security risk should be enough from that kind of project.

  1. Do we need support for choosing specific GPU ?

I don't have much idea about the question as I don't have multiple GPUs installed.

I think i can support only 1 GPU first and modify it later.

  1. It is useful to have some "threshold" ? If yes, only first chart or second too ?

The threshold to what? Did you mean only display a chart when the threshold is reached? I think it is useful for the GPU chart (i.e., the second chart).

The threshold is only an color warning/critical, but after time of reflection, i think that make no sense to warn on power usage.

  1. It is useful to add "Battery" graph too (except the percentage what the interest) ? If yes, do we need support for multiple batteries ?

I agree that a battery percentage graph will be useful. However, it needs a much slower refresh rate than other graphs, so it cannot be updated simultaneously with other charts.

Ok so you think to have different update interval AND history amount for that particular chart ? Even with that i think the change could be too short or small to see some relevant change, due to size of the graph when you put it in taskbar.

orblazer avatar Apr 15 '24 03:04 orblazer

Ok so you think to have different update interval AND history amount for that particular chart ? Even with that i think the change could be too short or small to see some relevant change, due to size of the graph when you put it in taskbar.

The refesh rate of battery percentage and power_now varies on different devices. Sometimes it is much larger than the optimal update interval for CPU usage, etc. But I think we can mark it TODO :)

Rongronggg9 avatar Apr 15 '24 06:04 Rongronggg9