Files
MontaukOS/programs/src/power/main.cpp
T

153 lines
4.0 KiB
C++

/*
* 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);
}