From ded325d32ace6d3df7ecb5f8ad7f3ed1d79045f0 Mon Sep 17 00:00:00 2001 From: Adel Noureddine Date: Wed, 1 Oct 2025 10:03:27 +0200 Subject: [PATCH 1/4] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5f47e8c..097cf56 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ Power Monitor for Windows is a command line tool that read CPU's power consumption through RAPL's MSRs, and provides the power consumption of the CPU every second. Power Monitor for Windows depends on the [Windows RAPL driver by Hubblo](https://github.com/hubblo-org/windows-rapl-driver), and therefore require installing the driver first, and runs on Intel or AMD CPUs (since Ryzen). +The easiest way to install the driver is to install the windows version of [Scaphandre](https://github.com/hubblo-org/scaphandre) tool from [this link directly](https://github.com/hubblo-org/scaphandre/releases/download/v1.0.0/scaphandre_v1.0.0_installer.exe) (release 1.0.0). Power Monitor for Windows was initially developed as part of [JoularJX](https://github.com/joular/joularjx), but is now its separate project. @@ -26,4 +27,5 @@ Power Monitor for Windows is licensed under the GNU GPL 3 license only (GPL-3.0- Copyright (c) 2024, Adel Noureddine, Université de Pau et des Pays de l'Adour. All rights reserved. This program and the accompanying materials are made available under the terms of the GNU General Public License v3.0 only (GPL-3.0-only) which accompanies this distribution, and is available at: https://www.gnu.org/licenses/gpl-3.0.en.html -Author : Adel Noureddine \ No newline at end of file + +Author : Adel Noureddine From 8734d5f7c2b9fe77d23da5347cfe382abbc6dfbe Mon Sep 17 00:00:00 2001 From: Adel Noureddine Date: Wed, 1 Oct 2025 13:39:55 +0200 Subject: [PATCH 2/4] Update README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 097cf56..e42c357 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,8 @@ The easiest way to install the driver is to install the windows version of [Scap Power Monitor for Windows was initially developed as part of [JoularJX](https://github.com/joular/joularjx), but is now its separate project. +An experimental rewrite in Rust of Power Monitor for Windows, is available at ou new repo [WinPowerMonitorRS](https://github.com/joular/WinPowerMonitorRS), and can be used instead of this C++ version. + ## :bulb: Usage Just run the program in command line, or run the executable. @@ -29,3 +31,4 @@ All rights reserved. This program and the accompanying materials are made availa Author : Adel Noureddine + From a2038a235584b39d9253c3dfdbe332cafa80fe0b Mon Sep 17 00:00:00 2001 From: Adel Noureddine Date: Wed, 1 Oct 2025 14:03:26 +0200 Subject: [PATCH 3/4] New rewrite in Rust --- .github/workflows/build.yml | 20 ++ .gitignore | 5 +- Cargo.toml | 17 ++ Old_C++_version/.gitignore | 2 + Main.cpp => Old_C++_version/Main.cpp | 0 .../PowerMonitor.sln | 0 .../PowerMonitor.vcxproj | 0 .../PowerMonitor.vcxproj.user | 0 Old_C++_version/README.md | 32 +++ .../compiled-binary}/PowerMonitor.exe | Bin .../hubbloRAPL.cpp | 0 hubbloRAPL.h => Old_C++_version/hubbloRAPL.h | 0 README.md | 14 +- src/hubblo_rapl.rs | 189 ++++++++++++++++++ src/main.rs | 45 +++++ 15 files changed, 313 insertions(+), 11 deletions(-) create mode 100644 .github/workflows/build.yml create mode 100644 Cargo.toml create mode 100644 Old_C++_version/.gitignore rename Main.cpp => Old_C++_version/Main.cpp (100%) rename PowerMonitor.sln => Old_C++_version/PowerMonitor.sln (100%) rename PowerMonitor.vcxproj => Old_C++_version/PowerMonitor.vcxproj (100%) rename PowerMonitor.vcxproj.user => Old_C++_version/PowerMonitor.vcxproj.user (100%) create mode 100644 Old_C++_version/README.md rename {compiled-binary => Old_C++_version/compiled-binary}/PowerMonitor.exe (100%) rename hubbloRAPL.cpp => Old_C++_version/hubbloRAPL.cpp (100%) rename hubbloRAPL.h => Old_C++_version/hubbloRAPL.h (100%) create mode 100644 src/hubblo_rapl.rs create mode 100644 src/main.rs diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..47f8be7 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,20 @@ +name: Build and release + +on: + push: + branches: [ "main", "develop" ] + pull_request: + branches: [ "main", "develop" ] + +jobs: + build: + runs-on: windows-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Rust compiler and Cargo + run: rustup update + + - name: Build + run: cargo build --release \ No newline at end of file diff --git a/.gitignore b/.gitignore index c03028d..b169f3d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ -.vs/ -x64/ \ No newline at end of file +/target +.idea +Cargo.lock \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..a132faa --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "WinPowerMonitorRS" +version = "0.1.0" +authors = ["Adel Noureddine"] +edition = "2024" +license = "GPL-3.0-only" +description = "Power Monitor for Windows is a command line tool that read CPU's power consumption through RAPL's MSRs, and provides the power consumption of the CPU every second" +repository = "https://github.com/joular/WinPowerMonitorRS" + +[dependencies] +windows = { version = "0.62.1", features = [ + "Win32_Foundation", + "Win32_Storage_FileSystem", + "Win32_System_IO", + "Win32_Security", +] } +ctrlc = "3.5.0" diff --git a/Old_C++_version/.gitignore b/Old_C++_version/.gitignore new file mode 100644 index 0000000..c03028d --- /dev/null +++ b/Old_C++_version/.gitignore @@ -0,0 +1,2 @@ +.vs/ +x64/ \ No newline at end of file diff --git a/Main.cpp b/Old_C++_version/Main.cpp similarity index 100% rename from Main.cpp rename to Old_C++_version/Main.cpp diff --git a/PowerMonitor.sln b/Old_C++_version/PowerMonitor.sln similarity index 100% rename from PowerMonitor.sln rename to Old_C++_version/PowerMonitor.sln diff --git a/PowerMonitor.vcxproj b/Old_C++_version/PowerMonitor.vcxproj similarity index 100% rename from PowerMonitor.vcxproj rename to Old_C++_version/PowerMonitor.vcxproj diff --git a/PowerMonitor.vcxproj.user b/Old_C++_version/PowerMonitor.vcxproj.user similarity index 100% rename from PowerMonitor.vcxproj.user rename to Old_C++_version/PowerMonitor.vcxproj.user diff --git a/Old_C++_version/README.md b/Old_C++_version/README.md new file mode 100644 index 0000000..28b28cb --- /dev/null +++ b/Old_C++_version/README.md @@ -0,0 +1,32 @@ +# Joular Project Power Monitor for Windows + +Power Monitor for Windows is a command line tool that read CPU's power consumption through RAPL's MSRs, and provides the power consumption of the CPU every second. + +Power Monitor for Windows depends on the [Windows RAPL driver by Hubblo](https://github.com/hubblo-org/windows-rapl-driver), and therefore require installing the driver first, and runs on Intel or AMD CPUs (since Ryzen). +The easiest way to install the driver is to install the windows version of [Scaphandre](https://github.com/hubblo-org/scaphandre) tool from [this link directly](https://github.com/hubblo-org/scaphandre/releases/download/v1.0.0/scaphandre_v1.0.0_installer.exe) (release 1.0.0). + +Power Monitor for Windows was initially developed as part of [JoularJX](https://github.com/joular/joularjx), but is now its separate project. + +## :bulb: Usage + +Just run the program in command line, or run the executable. +It'll print on the command line the power consumption of the CPU every second. + +## :floppy_disk: Compilation + +To compile the Power Monitor for Windows, open the project in Visual Studio and compile there. +Or open, Developer Command Prompt for VS (or Developer PowerShell for VS), and compile with this command: +``` +msbuild.exe PowerMonitor.sln /property:Configuration=Release +``` + +## :newspaper: License + +Power Monitor for Windows is licensed under the GNU GPL 3 license only (GPL-3.0-only). + +Copyright (c) 2024, Adel Noureddine, Université de Pau et des Pays de l'Adour. +All rights reserved. This program and the accompanying materials are made available under the terms of the GNU General Public License v3.0 only (GPL-3.0-only) which accompanies this distribution, and is available at: https://www.gnu.org/licenses/gpl-3.0.en.html + + +Author : Adel Noureddine + diff --git a/compiled-binary/PowerMonitor.exe b/Old_C++_version/compiled-binary/PowerMonitor.exe similarity index 100% rename from compiled-binary/PowerMonitor.exe rename to Old_C++_version/compiled-binary/PowerMonitor.exe diff --git a/hubbloRAPL.cpp b/Old_C++_version/hubbloRAPL.cpp similarity index 100% rename from hubbloRAPL.cpp rename to Old_C++_version/hubbloRAPL.cpp diff --git a/hubbloRAPL.h b/Old_C++_version/hubbloRAPL.h similarity index 100% rename from hubbloRAPL.h rename to Old_C++_version/hubbloRAPL.h diff --git a/README.md b/README.md index e42c357..3fb907d 100644 --- a/README.md +++ b/README.md @@ -7,8 +7,6 @@ The easiest way to install the driver is to install the windows version of [Scap Power Monitor for Windows was initially developed as part of [JoularJX](https://github.com/joular/joularjx), but is now its separate project. -An experimental rewrite in Rust of Power Monitor for Windows, is available at ou new repo [WinPowerMonitorRS](https://github.com/joular/WinPowerMonitorRS), and can be used instead of this C++ version. - ## :bulb: Usage Just run the program in command line, or run the executable. @@ -16,19 +14,17 @@ It'll print on the command line the power consumption of the CPU every second. ## :floppy_disk: Compilation -To compile the Power Monitor for Windows, open the project in Visual Studio and compile there. -Or open, Developer Command Prompt for VS (or Developer PowerShell for VS), and compile with this command: +To compile the Power Monitor for Windows, compile it with the Rust compiler and Cargo: + ``` -msbuild.exe PowerMonitor.sln /property:Configuration=Release +cargo build --release ``` ## :newspaper: License Power Monitor for Windows is licensed under the GNU GPL 3 license only (GPL-3.0-only). -Copyright (c) 2024, Adel Noureddine, Université de Pau et des Pays de l'Adour. +Copyright (c) 2025, Adel Noureddine, Université Paris Nanterre. All rights reserved. This program and the accompanying materials are made available under the terms of the GNU General Public License v3.0 only (GPL-3.0-only) which accompanies this distribution, and is available at: https://www.gnu.org/licenses/gpl-3.0.en.html - -Author : Adel Noureddine - +Author : Adel Noureddine \ No newline at end of file diff --git a/src/hubblo_rapl.rs b/src/hubblo_rapl.rs new file mode 100644 index 0000000..2bf4943 --- /dev/null +++ b/src/hubblo_rapl.rs @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2025, Adel Noureddine, Université Paris Nanterre. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the + * GNU General Public License v3.0 only (GPL-3.0-only) + * which accompanies this distribution, and is available at + * https://www.gnu.org/licenses/gpl-3.0.en.html + * + * Author : Adel Noureddine + */ + +use windows::core::*; +use windows::Win32::Foundation::*; +use windows::Win32::Storage::FileSystem::*; +use windows::Win32::System::IO::DeviceIoControl; + +// RAPL MSR addresses +const MSR_RAPL_POWER_UNIT: u64 = 0x606; +const MSR_PKG_ENERGY_STATUS: u64 = 0x611; +const MSR_DRAM_ENERGY_STATUS: u64 = 0x619; +const MSR_PLATFORM_ENERGY_STATUS: u64 = 0x64d; + +// CTL_CODE macro implementation +const fn ctl_code(device_type: u32, function: u32, method: u32, access: u32) -> u32 { + (device_type << 16) | (access << 14) | (function << 2) | method +} + +const FILE_DEVICE_UNKNOWN: u32 = 0x00000022; +const METHOD_BUFFERED: u32 = 0; +const FILE_READ_DATA: u32 = 0x0001; +const FILE_WRITE_DATA: u32 = 0x0002; + +pub struct RaplDriver { + handle: HANDLE, + power_unit: f64, + energy_unit: f64, + time_unit: f64, + psys: bool, + pkg: bool, + dram: bool, +} + +impl RaplDriver { + pub fn new() -> Result { + let driver_path = w!("\\\\.\\ScaphandreDriver"); + + let handle = unsafe { + CreateFileW( + driver_path, + FILE_GENERIC_READ.0 | FILE_GENERIC_WRITE.0, + FILE_SHARE_READ | FILE_SHARE_WRITE, + None, + OPEN_EXISTING, + FILE_FLAG_OVERLAPPED, + None, + )? + }; + + if handle == INVALID_HANDLE_VALUE { + return Err(Error::from_thread()); + } + + let mut driver = RaplDriver { + handle, + power_unit: 0.0, + energy_unit: 0.0, + time_unit: 0.0, + psys: false, + pkg: false, + dram: false, + }; + + driver.get_energy_units()?; + driver.check_supported_platform()?; + + Ok(driver) + } + + fn get_rapl_ctl_code() -> u32 { + ctl_code( + FILE_DEVICE_UNKNOWN, + MSR_RAPL_POWER_UNIT as u32, + METHOD_BUFFERED, + FILE_READ_DATA | FILE_WRITE_DATA, + ) + } + + fn get_data_from_driver(&self, msr: u64) -> Result { + let mut reply_data: u64 = 0; + let mut bytes_returned: u32 = 0; + + let ctl_code = Self::get_rapl_ctl_code(); + + unsafe { + DeviceIoControl( + self.handle, + ctl_code, + Some(&msr as *const u64 as *const _), + std::mem::size_of::() as u32, + Some(&mut reply_data as *mut u64 as *mut _), + std::mem::size_of::() as u32, + Some(&mut bytes_returned), + None, + )?; + } + + Ok(reply_data) + } + + fn get_energy_units(&mut self) -> Result<()> { + let reply_data = self.get_data_from_driver(MSR_RAPL_POWER_UNIT)?; + + // Time Units + const TIME_MASK: u64 = 0xF0000; + let time_val = reply_data & TIME_MASK; + self.time_unit = 1.0 / 2.0_f64.powi((time_val >> 16) as i32); + + // Energy Units + const ENERGY_MASK: u64 = 0x1F00; + let energy_val = reply_data & ENERGY_MASK; + self.energy_unit = 1.0 / 2.0_f64.powi((energy_val >> 8) as i32); + + // Power Units + const POWER_MASK: u64 = 0xF; + let power_val = reply_data & POWER_MASK; + self.power_unit = 1.0 / 2.0_f64.powi(power_val as i32); + + Ok(()) + } + + fn check_supported_platform(&mut self) -> Result<()> { + // Check for PSYS (Platform) support + if let Ok(reply_data) = self.get_data_from_driver(MSR_PLATFORM_ENERGY_STATUS) { + if reply_data != 0 { + self.psys = true; + return Ok(()); + } + } + + // If PSYS not supported, check PKG and DRAM + if let Ok(reply_data) = self.get_data_from_driver(MSR_PKG_ENERGY_STATUS) { + if reply_data != 0 { + self.pkg = true; + } + } + + if let Ok(reply_data) = self.get_data_from_driver(MSR_DRAM_ENERGY_STATUS) { + if reply_data != 0 { + self.dram = true; + } + } + + Ok(()) + } + + pub fn get_rapl_energy(&self) -> Result { + if self.psys { + let reply_data = self.get_data_from_driver(MSR_PLATFORM_ENERGY_STATUS)?; + let raw_psys_energy = (reply_data & 0xFFFFFFFF) as u32; + let psys_energy = raw_psys_energy as f64 * self.energy_unit; + return Ok(psys_energy); + } + + if self.pkg { + let reply_data = self.get_data_from_driver(MSR_PKG_ENERGY_STATUS)?; + let raw_pkg_energy = (reply_data & 0xFFFFFFFF) as u32; + let pkg_energy = raw_pkg_energy as f64 * self.energy_unit; + + if self.dram { + let reply_data = self.get_data_from_driver(MSR_DRAM_ENERGY_STATUS)?; + let raw_dram_energy = (reply_data & 0xFFFFFFFF) as u32; + let dram_energy = raw_dram_energy as f64 * self.energy_unit; + return Ok(pkg_energy + dram_energy); + } + + return Ok(pkg_energy); + } + + Ok(0.0) + } +} + +impl Drop for RaplDriver { + fn drop(&mut self) { + unsafe { + let _ = CloseHandle(self.handle); + } + } +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..904b4c9 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2025, Adel Noureddine, Université Paris Nanterre. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the + * GNU General Public License v3.0 only (GPL-3.0-only) + * which accompanies this distribution, and is available at + * https://www.gnu.org/licenses/gpl-3.0.en.html + * + * Author : Adel Noureddine + */ + +mod hubblo_rapl; + +use std::{thread, time}; +use std::sync::{Arc, atomic::{AtomicBool, Ordering}}; + +use hubblo_rapl::RaplDriver; + +fn main() { + let running = Arc::new(AtomicBool::new(true)); + let r = running.clone(); + ctrlc::set_handler(move || { + // Change value to stop main loop + r.store(false, Ordering::SeqCst); + }).expect("Error setting Ctrl-C"); + + let mut before_energy: f64 = 0.0; + let driver = RaplDriver::new().expect("Driver failed"); + let mut first_run = true; + + while running.load(Ordering::SeqCst) { + let after_energy = driver.get_rapl_energy().unwrap_or(0.0); + let energy = after_energy - before_energy; + before_energy = after_energy; + + if first_run { + first_run = false; + thread::sleep(time::Duration::from_secs(1)); + continue; + } + + println!("{:.3}", energy); + thread::sleep(time::Duration::from_secs(1)); + } +} \ No newline at end of file From 9dcdd5160089b6c24a8e293e616e61c48e47c00c Mon Sep 17 00:00:00 2001 From: Adel Noureddine Date: Fri, 3 Oct 2025 13:40:41 +0200 Subject: [PATCH 4/4] Remove DRAM. Add support for AMD --- Cargo.toml | 2 +- src/hubblo_rapl.rs | 125 +++++++++++++++++++++++++++++++++++---------- 2 files changed, 98 insertions(+), 29 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a132faa..b28ddd6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "WinPowerMonitorRS" +name = "WinPowerMonitor" version = "0.1.0" authors = ["Adel Noureddine"] edition = "2024" diff --git a/src/hubblo_rapl.rs b/src/hubblo_rapl.rs index 2bf4943..2a5393b 100644 --- a/src/hubblo_rapl.rs +++ b/src/hubblo_rapl.rs @@ -14,11 +14,15 @@ use windows::Win32::Foundation::*; use windows::Win32::Storage::FileSystem::*; use windows::Win32::System::IO::DeviceIoControl; -// RAPL MSR addresses -const MSR_RAPL_POWER_UNIT: u64 = 0x606; -const MSR_PKG_ENERGY_STATUS: u64 = 0x611; -const MSR_DRAM_ENERGY_STATUS: u64 = 0x619; -const MSR_PLATFORM_ENERGY_STATUS: u64 = 0x64d; +// RAPL MSR addresses for Intel +const MSR_INTEL_RAPL_POWER_UNIT: u64 = 0x606; +const MSR_INTEL_PKG_ENERGY_STATUS: u64 = 0x611; +const MSR_INTEL_DRAM_ENERGY_STATUS: u64 = 0x619; +const MSR_INTEL_PLATFORM_ENERGY_STATUS: u64 = 0x64d; + +// RAPL MSR addresses for AMD +const MSR_AMD_RAPL_POWER_UNIT: u64 = 0xc0010299; +const MSR_AMD_PKG_ENERGY_STATUS: u64 = 0xc001029b; // CTL_CODE macro implementation const fn ctl_code(device_type: u32, function: u32, method: u32, access: u32) -> u32 { @@ -30,11 +34,18 @@ const METHOD_BUFFERED: u32 = 0; const FILE_READ_DATA: u32 = 0x0001; const FILE_WRITE_DATA: u32 = 0x0002; +#[derive(Debug, Clone, Copy)] +enum CpuVendor { + Intel, + AMD, +} + pub struct RaplDriver { handle: HANDLE, power_unit: f64, energy_unit: f64, time_unit: f64, + vendor: CpuVendor, psys: bool, pkg: bool, dram: bool, @@ -65,21 +76,28 @@ impl RaplDriver { power_unit: 0.0, energy_unit: 0.0, time_unit: 0.0, + vendor: CpuVendor::Intel, // Default to Intel, will be detected psys: false, pkg: false, dram: false, }; + driver.detect_cpu_vendor()?; driver.get_energy_units()?; driver.check_supported_platform()?; Ok(driver) } - fn get_rapl_ctl_code() -> u32 { + fn get_rapl_ctl_code(&self) -> u32 { + let msr = match self.vendor { + CpuVendor::Intel => MSR_INTEL_RAPL_POWER_UNIT, + CpuVendor::AMD => MSR_AMD_RAPL_POWER_UNIT, + }; + ctl_code( FILE_DEVICE_UNKNOWN, - MSR_RAPL_POWER_UNIT as u32, + msr as u32, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA, ) @@ -89,7 +107,7 @@ impl RaplDriver { let mut reply_data: u64 = 0; let mut bytes_returned: u32 = 0; - let ctl_code = Self::get_rapl_ctl_code(); + let ctl_code = self.get_rapl_ctl_code(); unsafe { DeviceIoControl( @@ -107,8 +125,29 @@ impl RaplDriver { Ok(reply_data) } + fn detect_cpu_vendor(&mut self) -> Result<()> { + // Try Intel first + if self.get_data_from_driver(MSR_INTEL_RAPL_POWER_UNIT).is_ok() { + self.vendor = CpuVendor::Intel; + return Ok(()); + } + + // Try AMD + if self.get_data_from_driver(MSR_AMD_RAPL_POWER_UNIT).is_ok() { + self.vendor = CpuVendor::AMD; + return Ok(()); + } + + Err(Error::from_thread()) + } + fn get_energy_units(&mut self) -> Result<()> { - let reply_data = self.get_data_from_driver(MSR_RAPL_POWER_UNIT)?; + let msr = match self.vendor { + CpuVendor::Intel => MSR_INTEL_RAPL_POWER_UNIT, + CpuVendor::AMD => MSR_AMD_RAPL_POWER_UNIT, + }; + + let reply_data = self.get_data_from_driver(msr)?; // Time Units const TIME_MASK: u64 = 0xF0000; @@ -129,24 +168,36 @@ impl RaplDriver { } fn check_supported_platform(&mut self) -> Result<()> { - // Check for PSYS (Platform) support - if let Ok(reply_data) = self.get_data_from_driver(MSR_PLATFORM_ENERGY_STATUS) { - if reply_data != 0 { - self.psys = true; - return Ok(()); - } - } + match self.vendor { + CpuVendor::Intel => { + // Check for PSYS (Platform) support + if let Ok(reply_data) = self.get_data_from_driver(MSR_INTEL_PLATFORM_ENERGY_STATUS) { + if reply_data != 0 { + self.psys = true; + return Ok(()); + } + } - // If PSYS not supported, check PKG and DRAM - if let Ok(reply_data) = self.get_data_from_driver(MSR_PKG_ENERGY_STATUS) { - if reply_data != 0 { - self.pkg = true; - } - } + // If PSYS not supported, check PKG and DRAM + if let Ok(reply_data) = self.get_data_from_driver(MSR_INTEL_PKG_ENERGY_STATUS) { + if reply_data != 0 { + self.pkg = true; + } + } - if let Ok(reply_data) = self.get_data_from_driver(MSR_DRAM_ENERGY_STATUS) { - if reply_data != 0 { - self.dram = true; + if let Ok(reply_data) = self.get_data_from_driver(MSR_INTEL_DRAM_ENERGY_STATUS) { + if reply_data != 0 { + self.dram = true; + } + } + } + CpuVendor::AMD => { + // AMD only supports PKG, no DRAM or PSYS + if let Ok(reply_data) = self.get_data_from_driver(MSR_AMD_PKG_ENERGY_STATUS) { + if reply_data != 0 { + self.pkg = true; + } + } } } @@ -154,20 +205,27 @@ impl RaplDriver { } pub fn get_rapl_energy(&self) -> Result { + match self.vendor { + CpuVendor::Intel => self.get_intel_energy(), + CpuVendor::AMD => self.get_amd_energy(), + } + } + + fn get_intel_energy(&self) -> Result { if self.psys { - let reply_data = self.get_data_from_driver(MSR_PLATFORM_ENERGY_STATUS)?; + let reply_data = self.get_data_from_driver(MSR_INTEL_PLATFORM_ENERGY_STATUS)?; let raw_psys_energy = (reply_data & 0xFFFFFFFF) as u32; let psys_energy = raw_psys_energy as f64 * self.energy_unit; return Ok(psys_energy); } if self.pkg { - let reply_data = self.get_data_from_driver(MSR_PKG_ENERGY_STATUS)?; + let reply_data = self.get_data_from_driver(MSR_INTEL_PKG_ENERGY_STATUS)?; let raw_pkg_energy = (reply_data & 0xFFFFFFFF) as u32; let pkg_energy = raw_pkg_energy as f64 * self.energy_unit; if self.dram { - let reply_data = self.get_data_from_driver(MSR_DRAM_ENERGY_STATUS)?; + let reply_data = self.get_data_from_driver(MSR_INTEL_DRAM_ENERGY_STATUS)?; let raw_dram_energy = (reply_data & 0xFFFFFFFF) as u32; let dram_energy = raw_dram_energy as f64 * self.energy_unit; return Ok(pkg_energy + dram_energy); @@ -178,6 +236,17 @@ impl RaplDriver { Ok(0.0) } + + fn get_amd_energy(&self) -> Result { + if self.pkg { + let reply_data = self.get_data_from_driver(MSR_AMD_PKG_ENERGY_STATUS)?; + let raw_pkg_energy = (reply_data & 0xFFFFFFFF) as u32; + let pkg_energy = raw_pkg_energy as f64 * self.energy_unit; + return Ok(pkg_energy); + } + + Ok(0.0) + } } impl Drop for RaplDriver {