* [PATCH] kernel: add system_energy_efficiency syscall (nr 337)
@ 2026-09-20 10:07 林濬哲
2026-09-20 10:20 ` Greg KH
2026-09-20 10:59 ` 林濬哲
0 siblings, 2 replies; 3+ messages in thread
From: 林濬哲 @ 2026-09-20 10:07 UTC (permalink / raw)
To: linux-kernel
Cc: x86, linux-api, luto, tglx, mingo, bp, dave.hansen, hpa, m18667909625
Add a new syscall that reports GPU presence and system-wide
energy information:
- mode 0: returns the number of display devices found on the PCI bus
- mode 1: returns an energy efficiency metric; prefers the real GPU
power reported through hwmon, falls back to runtime PM status
weights, plus the online CPU count
- mode 2: returns the real-time GPU power in milliwatts read from
the hwmon power1_input channel exposed by GPU drivers
(amdgpu/nouveau/radeon/nvidia); returns 0 if not reported
Signed-off-by: 林濬哲 <m18667909625@163.com>
Assisted-by: AI coding assistant (disclosed per kernel AI guidelines)
---
arch/x86/entry/syscalls/syscall_64.tbl | 1 +
include/linux/syscalls.h | 2 +
kernel/sys.c | 138 +++++++++++++++++++++++++
3 files changed, 141 insertions(+)
diff --git a/arch/x86/entry/syscalls/syscall_64.tbl b/arch/x86/entry/syscalls/syscall_64.tbl
index d5b6045b0090..f99649dfaa38 100644
--- a/arch/x86/entry/syscalls/syscall_64.tbl
+++ b/arch/x86/entry/syscalls/syscall_64.tbl
@@ -346,6 +346,7 @@
334 common rseq sys_rseq
335 common uretprobe sys_uretprobe
336 common uprobe sys_uprobe
+337 common system_energy_efficiency sys_system_energy_efficiency
# don't use numbers 387 through 423, add new calls after the last
# 'common' entry
424 common pidfd_send_signal sys_pidfd_send_signal
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index 8413b624ad47..dfa9d31c20cd 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -1017,6 +1017,8 @@ asmlinkage long sys_uretprobe(void);
asmlinkage long sys_uprobe(void);
+asmlinkage long sys_system_energy_efficiency(int __user *mode, int __user *value);
+
/* pciconfig: alpha, arm, arm64, ia64, sparc */
asmlinkage long sys_pciconfig_read(unsigned long bus, unsigned long dfn,
unsigned long off, unsigned long len,
diff --git a/kernel/sys.c b/kernel/sys.c
index 35b538ba843c..bb1106085d7e 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -22,6 +22,7 @@
#include <linux/workqueue.h>
#include <linux/capability.h>
#include <linux/device.h>
+#include <linux/pci.h>
#include <linux/key.h>
#include <linux/times.h>
#include <linux/posix-timers.h>
@@ -181,6 +182,143 @@ int fs_overflowgid = DEFAULT_FS_OVERFLOWGID;
EXPORT_SYMBOL(fs_overflowuid);
EXPORT_SYMBOL(fs_overflowgid);
+
+/*
+ * Read the real power consumption reported by GPU drivers via hwmon,
+ * in milliwatts. The hwmon ABI exposes power1_input in microwatts;
+ * amdgpu/nouveau/radeon/nvidia provide this channel on supported
+ * hardware. Returns 0 if no driver reports a power reading.
+ */
+static long gpu_hwmon_power_mw(void)
+{
+ static const char * const gpu_drivers[] = {
+ "amdgpu", "nouveau", "radeon", "nvidia",
+ };
+ char buf[32];
+ char path[64];
+ loff_t pos;
+ long total_uw = 0;
+ long val;
+ int i, j, ret;
+
+ for (i = 0; i < 32; i++) {
+ bool is_gpu = false;
+ struct file *fp;
+
+ snprintf(path, sizeof(path), "/sys/class/hwmon/hwmon%d/name", i);
+ fp = filp_open(path, O_RDONLY, 0);
+ if (IS_ERR(fp))
+ continue;
+
+ pos = 0;
+ ret = kernel_read(fp, buf, sizeof(buf) - 1, &pos);
+ filp_close(fp, NULL);
+ if (ret <= 0)
+ continue;
+ buf[ret] = '\0';
+
+ for (j = 0; j < ARRAY_SIZE(gpu_drivers); j++) {
+ if (!strncmp(buf, gpu_drivers[j], strlen(gpu_drivers[j]))) {
+ is_gpu = true;
+ break;
+ }
+ }
+ if (!is_gpu)
+ continue;
+
+ snprintf(path, sizeof(path), "/sys/class/hwmon/hwmon%d/power1_input", i);
+ fp = filp_open(path, O_RDONLY, 0);
+ if (IS_ERR(fp))
+ continue;
+
+ pos = 0;
+ ret = kernel_read(fp, buf, sizeof(buf) - 1, &pos);
+ filp_close(fp, NULL);
+ if (ret <= 0)
+ continue;
+ buf[ret] = '\0';
+
+ if (kstrtol(buf, 10, &val))
+ continue;
+
+ total_uw += val;
+ }
+
+ return total_uw / 1000; /* microwatts -> milliwatts */
+}
+
+static int gpu_energy_estimate(int *gpus)
+{
+ static const int class_list[] = {
+ 0x030000, /* VGA compatible controller */
+ 0x030200, /* 3D controller (modern NVIDIA/AMD GPUs) */
+ 0x030100, /* XGA */
+ 0x030080, /* other display controller */
+ };
+ struct pci_dev *pdev;
+ int i, count = 0, energy = 0;
+
+ for (i = 0; i < ARRAY_SIZE(class_list); i++) {
+ pdev = NULL;
+ while ((pdev = pci_get_class(class_list[i], pdev)) != NULL) {
+ count++;
+ if (pdev->dev.power.runtime_status == RPM_ACTIVE)
+ energy += 100;
+ else
+ energy += 5;
+ }
+ }
+
+ if (gpus)
+ *gpus = count;
+
+ return energy;
+}
+
+SYSCALL_DEFINE2(system_energy_efficiency, int __user *, mode, int __user *, value)
+{
+ int mode_v, ret;
+ int gpu_num, gpu_energy;
+ long gpu_power_mw;
+
+ if (get_user(mode_v, mode))
+ return -EFAULT;
+
+ if (mode_v < 0 || mode_v > 2)
+ return -EINVAL;
+
+ gpu_energy = gpu_energy_estimate(&gpu_num);
+ gpu_power_mw = gpu_hwmon_power_mw();
+
+ switch (mode_v) {
+ case 0:
+ /* number of GPUs, 0 if the system has none */
+ ret = gpu_num;
+ break;
+ case 1:
+ /*
+ * Energy efficiency metric: prefer the real GPU power
+ * (mW) reported by the driver, fall back to runtime PM
+ * status weights if no power channel exists, then add
+ * the CPU part (online CPUs x 10)
+ */
+ ret = (int)(gpu_power_mw ? gpu_power_mw : gpu_energy) +
+ num_online_cpus() * 10;
+ break;
+ case 2:
+ /* real-time GPU power in mW, 0 if not reported */
+ ret = (int)gpu_power_mw;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (put_user(ret, value))
+ return -EFAULT;
+
+ return 0;
+}
+
static const struct ctl_table overflow_sysctl_table[] = {
{
.procname = "overflowuid",
--
2.54.0.windows.1
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] kernel: add system_energy_efficiency syscall (nr 337)
2026-09-20 10:07 [PATCH] kernel: add system_energy_efficiency syscall (nr 337) 林濬哲
@ 2026-09-20 10:20 ` Greg KH
2026-09-20 10:59 ` 林濬哲
1 sibling, 0 replies; 3+ messages in thread
From: Greg KH @ 2026-09-20 10:20 UTC (permalink / raw)
To: 林濬哲
Cc: linux-kernel, x86, linux-api, luto, tglx, mingo, bp, dave.hansen, hpa
On Sun, Sep 20, 2026 at 06:07:13PM +0800, 林濬哲 wrote:
> Add a new syscall that reports GPU presence and system-wide
> energy information:
>
> - mode 0: returns the number of display devices found on the PCI bus
> - mode 1: returns an energy efficiency metric; prefers the real GPU
> power reported through hwmon, falls back to runtime PM status
> weights, plus the online CPU count
> - mode 2: returns the real-time GPU power in milliwatts read from
> the hwmon power1_input channel exposed by GPU drivers
> (amdgpu/nouveau/radeon/nvidia); returns 0 if not reported
Cute, but you missed a bunch of other gpu drivers, AND all of this can
be done today from userspace, no syscall is needed, right?
thanks,
greg k-h
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] kernel: add system_energy_efficiency syscall (nr 337)
2026-09-20 10:07 [PATCH] kernel: add system_energy_efficiency syscall (nr 337) 林濬哲
2026-09-20 10:20 ` Greg KH
@ 2026-09-20 10:59 ` 林濬哲
1 sibling, 0 replies; 3+ messages in thread
From: 林濬哲 @ 2026-09-20 10:59 UTC (permalink / raw)
To: gregkh; +Cc: linux-kernel, m18667909625
Hi Greg,
Thanks for the quick review!
You are right: GPU power readings are already available from userspace
via /sys/class/hwmon/*/power1_input, and display devices can be
enumerated through /sys/bus/pci/devices. I do not have a use case that
requires gathering this data from within the kernel, so please drop
this patch.
Thanks again for taking the time to review it.
Best regards,
林濬哲
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-09-20 10:59 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-20 10:07 [PATCH] kernel: add system_energy_efficiency syscall (nr 337) 林濬哲
2026-09-20 10:20 ` Greg KH
2026-09-20 10:59 ` 林濬哲
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®