You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在PowerShell中获取CPU功耗?及Open Hardware Monitor源码疑问

在PowerShell里获取CPU功耗的实用方法

我整理了几种靠谱的方式,你可以根据自己的系统和CPU情况来选:

1. 用CIM/WMI直接查询

这是最方便的方式,Windows 10及以上系统基本都支持。直接用Get-CimInstance调用系统内置的性能数据类就行:

# 查看每个CPU核心的功耗
Get-CimInstance Win32_PerfFormattedData_Counters_ProcessorInformation | Select-Object Name, PowerWatts

如果想要总功耗,加个求和就行:

$totalPower = (Get-CimInstance Win32_PerfFormattedData_Counters_ProcessorInformation | Measure-Object PowerWatts -Sum).Sum
Write-Host "当前CPU总功耗: $totalPower Watts"

注意哦,要是你的CPU比较老或者没带功耗传感器,可能会返回0或者空值,这时候就得换别的方法了。

2. 调用性能计数器

和上面的原理差不多,直接用PowerShell的性能计数器命令读取:

# 获取所有核心的功耗数据
Get-Counter "\Processor Information(*)\Processor Power Watts" | Select-Object -ExpandProperty CounterSamples | Select-Object InstanceName, CookedValue

同样算总功耗的话:

$counterData = Get-Counter "\Processor Information(*)\Processor Power Watts" | Select-Object -ExpandProperty CounterSamples
$totalPower = ($counterData | Measure-Object CookedValue -Sum).Sum
Write-Host "当前CPU总功耗: $([math]::Round($totalPower, 2)) Watts"

3. 读取MSR寄存器(需要管理员权限)

如果上面两种方法都不行,那可以试试直接读CPU的MSR寄存器——这得有管理员权限,而且只适用于支持RAPL技术的Intel/AMD CPU。我给你一段PowerShell里调用C#代码的示例,直接复制运行就行:

# 必须以管理员身份运行!
Add-Type @"
using System;
using System.Runtime.InteropServices;

public class MSRReader {
    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern IntPtr CreateFile(string lpFileName, uint dwDesiredAccess, uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition, uint dwFlagsAndAttributes, IntPtr hTemplateFile);

    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern bool DeviceIoControl(IntPtr hDevice, uint dwIoControlCode, IntPtr lpInBuffer, uint nInBufferSize, IntPtr lpOutBuffer, uint nOutBufferSize, out uint lpBytesReturned, IntPtr lpOverlapped);

    public static ulong ReadMSR(uint registerAddress) {
        IntPtr hMsr = CreateFile(@"\\.\cpu0", 0x80000000 | 0x40000000, 0, IntPtr.Zero, 3, 0, IntPtr.Zero);
        if (hMsr == IntPtr.Zero) throw new System.ComponentModel.Win32Exception();

        uint bytesReturned;
        IntPtr outBuffer = Marshal.AllocHGlobal(8);
        try {
            if (!DeviceIoControl(hMsr, 0x80002008, ref registerAddress, 4, outBuffer, 8, out bytesReturned, IntPtr.Zero)) {
                throw new System.ComponentModel.Win32Exception();
            }
            return Marshal.ReadUInt64(outBuffer);
        } finally {
            Marshal.FreeHGlobal(outBuffer);
            CloseHandle(hMsr);
        }
    }

    [DllImport("kernel32.dll")]
    public static extern bool CloseHandle(IntPtr hObject);
}
"@

# 读取Intel RAPL相关寄存器(AMD的话寄存器地址不一样,得查文档)
$powerUnit = [MSRReader]::ReadMSR(0x606)
$energyStatus = [MSRReader]::ReadMSR(0x611)

# 计算累计能量,要得到功耗得间隔几秒读两次算差值哦
$powerMultiplier = [math]::Pow(0.5, ($powerUnit -band 0x1F))
$energyMultiplier = [math]::Pow(0.5, (($powerUnit -shr 8) -band 0x1F))
$totalEnergy = $energyStatus * $energyMultiplier
Write-Host "CPU累计消耗能量: $([math]::Round($totalEnergy, 2)) Joules"

提醒下,AMD的寄存器地址和Intel不一样,要是用AMD CPU,得查对应的官方文档改寄存器编号。


Open Hardware Monitor源码里功耗实现的查找技巧

你找不到相关代码,大概率是因为OHM不是直接读"功耗"数值,而是通过累计能量+时间差算出来的,而且代码分散在不同的CPU模块里:

1. 找对核心文件

  • Intel CPU:功耗逻辑在OpenHardwareMonitor/Hardware/CPU/IntelCPU.cs里,搜RAPL这个关键词就能找到——RAPL是Intel用来监控功耗的技术,OHM就是靠它读MSR寄存器拿累计能量,再算功耗。
  • AMD CPU:对应的文件是OpenHardwareMonitor/Hardware/CPU/AMDCPU.cs,搜PowerSensor或者相关寄存器的关键词就行。

2. 关键逻辑梳理

OHM里的功耗传感器是基于ISensor接口创建的,类型是SensorType.Power。拿Intel的代码举例子:

  • Initialize方法里,会创建Package、Core这些不同维度的功耗传感器;
  • Update方法里,会两次读取MSR寄存器的累计能量值,用两次的差值除以时间间隔,就得到了实时功耗。
    大概的代码片段是这样的(简化过):
private void InitializeRapl() {
    this.raplPackagePower = CreateSensor(SensorType.Power, "Package", 0);
    // 初始化其他功耗传感器...
}

public override void Update() {
    ulong currentEnergy = ReadMsr(MSR_PKG_ENERGY_STATUS);
    double timeDelta = (DateTime.UtcNow - lastUpdateTime).TotalSeconds;
    double power = (currentEnergy - lastEnergyValue) * energyMultiplier / timeDelta;
    this.raplPackagePower.Value = power;
    // 更新上次的时间和能量值...
}

3. 快速定位的小技巧

直接在源码里全局搜索SensorType.Power,找到所有创建功耗传感器的地方,然后顺着调用链找更新逻辑就行;或者搜RAPLMSR_PKG_ENERGY_STATUS这些和功耗相关的关键词,一下子就能定位到核心代码了。


内容的提问来源于stack exchange,提问作者lel

火山引擎 最新活动