feat: HWP scaling, C1E, closed-loop thermal governor for Intel CPUs

This commit is contained in:
2026-07-05 10:51:11 +02:00
parent 46c56b057b
commit 35e5aba23f
19 changed files with 903 additions and 9 deletions
+19
View File
@@ -200,6 +200,9 @@ namespace montauk::abi {
static constexpr uint64_t SYS_SDR_SETPARAM = 147; // (handle, param, value)
static constexpr uint64_t SYS_SDR_GETPARAM = 148; // (handle, param) -> value
// CPU power/thermal status
static constexpr uint64_t SYS_POWERINFO = 149; // (PowerInfo*) -> 0, -1 unsupported
// Tunable parameters (for SYS_SDR_SETPARAM / SYS_SDR_GETPARAM).
static constexpr int SDR_PARAM_FREQ = 0; // center frequency, Hz
static constexpr int SDR_PARAM_SAMPLE_RATE = 1; // sample rate, Hz
@@ -493,6 +496,22 @@ namespace montauk::abi {
uint32_t _pad;
};
// CPU power/thermal snapshot (returned by SYS_POWERINFO)
struct PowerInfo {
uint8_t hwpActive; // hardware P-state scaling enabled
uint8_t throttling; // thermal governor currently limiting frequency
uint8_t tempC; // package temperature, degrees C (0 = unknown)
uint8_t tjMaxC; // hardware throttle temperature
uint8_t highestPerf; // HWP performance range (ratio units)
uint8_t lowestPerf;
uint8_t curMaxPerf; // thermal governor's current ceiling
uint8_t epp; // energy/perf preference (0=perf, 255=power)
uint32_t baseMHz; // nominal base frequency (0 = unknown)
uint32_t maxMHz; // max turbo frequency
uint32_t effMHz; // measured average active frequency
uint32_t apIdleHint; // MWAIT hint used for AP deep idle
};
struct ProcInfo {
int32_t pid;
int32_t parentPid;
+1
View File
@@ -172,6 +172,7 @@ extern "C" {
#define MTK_SYS_SDR_READ 146
#define MTK_SYS_SDR_SETPARAM 147
#define MTK_SYS_SDR_GETPARAM 148
#define MTK_SYS_POWERINFO 149
/* @SYSCALLS-END */
#define MTK_SOCK_TCP 1
+152
View File
@@ -0,0 +1,152 @@
/*
* main.cpp
* power - CPU power/thermal status tool.
*
* Reads the kernel's power management snapshot (SYS_POWERINFO): package
* temperature, HWP frequency-scaling state, the thermal governor's
* current frequency ceiling, and the measured average active frequency.
* Useful for verifying that HWP and the thermal governor are doing their
* job on real hardware.
*
* Usage:
* power print the current snapshot
* power watch sample once per second until 60 s elapse
* power watch <secs> sample once per second for <secs> seconds
* Copyright (c) 2026 Daniel Hammer
*/
#include <montauk/syscall.h>
using namespace montauk;
static void put_u64(uint64_t n) {
char buf[24];
int i = 0;
if (n == 0) { putchar('0'); return; }
while (n) { buf[i++] = (char)('0' + (n % 10)); n /= 10; }
while (i) putchar(buf[--i]);
}
static void put_hex8(uint8_t v) {
static const char* digits = "0123456789ABCDEF";
print("0x");
putchar(digits[(v >> 4) & 0xF]);
putchar(digits[v & 0xF]);
}
static bool read_info(montauk::abi::PowerInfo& info) {
return syscall1(montauk::abi::SYS_POWERINFO, (uint64_t)&info) == 0;
}
static void print_snapshot(const montauk::abi::PowerInfo& info) {
print("CPU power/thermal status:\n");
print(" HWP: ");
if (info.hwpActive) {
print("active (EPP ");
put_hex8(info.epp);
print(", perf range ");
put_u64(info.lowestPerf);
print("-");
put_u64(info.highestPerf);
print(")\n");
} else {
print("not active\n");
}
print(" Frequency: base ");
put_u64(info.baseMHz);
print(" MHz, turbo ");
put_u64(info.maxMHz);
print(" MHz, avg active ");
put_u64(info.effMHz);
print(" MHz\n");
print(" Package: ");
if (info.tempC != 0) {
put_u64(info.tempC);
print(" C (hardware throttles at ");
put_u64(info.tjMaxC);
print(" C)\n");
} else {
print("temperature unavailable\n");
}
print(" Governor: ");
if (!info.hwpActive) {
print("inactive\n");
} else if (info.throttling) {
print("THROTTLING - ceiling ");
put_u64(info.curMaxPerf);
print(" of ");
put_u64(info.highestPerf);
print("\n");
} else {
print("not throttling (ceiling ");
put_u64(info.curMaxPerf);
print(")\n");
}
print(" AP idle: MWAIT hint ");
put_hex8((uint8_t)info.apIdleHint);
if (info.apIdleHint == 0) {
print(" (C1 only)");
}
print("\n");
}
static void print_watch_line(const montauk::abi::PowerInfo& info, uint64_t t) {
put_u64(t);
print("s ");
put_u64(info.tempC);
print(" C avg ");
put_u64(info.effMHz);
print(" MHz ceiling ");
put_u64(info.curMaxPerf);
print("/");
put_u64(info.highestPerf);
print(info.throttling ? " THROTTLING\n" : "\n");
}
static uint64_t parse_u64(const char* s, uint64_t fallback) {
uint64_t v = 0;
bool any = false;
while (*s == ' ') s++;
while (*s >= '0' && *s <= '9') { v = v * 10 + (uint64_t)(*s - '0'); s++; any = true; }
return any ? v : fallback;
}
extern "C" void _start() {
char args[64];
int alen = montauk::getargs(args, sizeof(args));
const char* rest = (alen > 0) ? args : "";
montauk::abi::PowerInfo info{};
if (!read_info(info)) {
print("power: no CPU power management available\n");
print("(non-Intel CPU or running under emulation)\n");
montauk::exit(1);
}
bool watch = rest[0] == 'w';
if (!watch) {
print_snapshot(info);
montauk::exit(0);
}
const char* p = rest;
while (*p && *p != ' ') p++;
uint64_t seconds = parse_u64(p, 60);
if (seconds == 0) seconds = 60;
print("time temp freq ceiling (1 sample/s, ");
put_u64(seconds);
print(" s)\n");
for (uint64_t t = 0; t < seconds; t++) {
if (!read_info(info)) break;
print_watch_line(info, t);
montauk::sleep_ms(1000);
}
montauk::exit(0);
}