-
-
Notifications
You must be signed in to change notification settings - Fork 96
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Consider using WMI for Windows cpu::frequency #232
Comments
i found that in both cases (my amd and intel machine) WMI returns only base speed value, not realtime value. i tried systeminformation lib in node, turns out it use wmi too, and it's only showing base speed. |
It looks like the oshi Java library had the same issue as #229 in oshi/oshi#966, they improved or fixed the situation in oshi/oshi#989 with a Performance counter and a WMI call getting Win32_PerfRawData_Counters_ProcessorInformation |
Hello, I ran a quick and dirty experiment with wmi crate. I found that WMI has Pre-formatted counters that are easier to use than rawdata counter. Especially this property on performance counter called Win32_perfformatteddata_counters_processorinformation : I think this is the counter used in Perfmon windows utility, also I was not able to check this : Here is a small code, that runs with only the wmi dependency in Cargo.toml use std::time::Duration;
use std::thread::sleep;
use std::collections::HashMap;
use wmi::Variant;
use wmi::{COMLibrary, WMIConnection};
fn main() {
let com_con = COMLibrary::new().unwrap();
let wmi_con = WMIConnection::new(com_con.into()).unwrap();
for _ in 0..10 {
let results: Vec<HashMap<String, Variant>> = wmi_con
.raw_query("SELECT Name, PercentProcessorUtility FROM Win32_PerfFormattedData_Counters_ProcessorInformation WHERE NOT Name LIKE \"%_Total\"").unwrap();
for procs in results {
println!("{:?}", procs);
}
sleep(Duration::new(1, 0));
}
} On an Octocore CPU this is the result of the first and last iteration of the loop :
You have 8 entries, one for each proc (from "0,0" to "0,7") and a string representing the current utility percent for the proc. Tell me if you are interested in further investigations. I'm new to Rust but it could lead to a first PR Regards, EDIT : I'm a bit off-topic as the subject here is the frequency, but I think there is a way to compute frequency from the various other informations available in the counter, like this for example in each proc : "PercentofMaximumFrequency": I8( |
Hi again :) I think it could be worth it to integrate WMI in heim for windows, as you could use it for more than just CPU Frequency. If we look back to your criterias : SELECT PercentofMaximumFrequency, PercentProcessorPerformance FROM Win32_PerfFormattedData_Counters_ProcessorInformation WHERE Name = '_Total' The PercentProcessorPerformance is mentionned in this issue in oshi : oshi/oshi#966 (comment) - Is WMI available in all Windows versions? - Are there crates available and maintained? wmi crate? I'll try to look into async WMI, and if an implementation is possible in Rust Regards |
Hi, @apennamen! Amazing investigation, thank you! Even if it will take time and effort to introduce async support for Let me know if you need any help with your work! |
Hello there! I'm struggling on a AddRef/Release problem when adding async support to WMI crate. I think I won't wait until this is resolved (and hopefully merged!) before working on adding a Proof of Concept. See you soon! |
Hello, As the work for adding async queries is reaching the end in the wmi crate (waiting for final reviews and minor adjustments), I started looking into the conception for how to integrate WMI with heim for frequencies, before creating a pull request. WMI BenefitsWe can take advantage of WMI to query general CPU frequency information, as well as per-CPU information. So we could provide a CPU total information: per-CPU information: For the max and min frequency, some small researchs are needed to query them with WMI. TradeoffThere is adding complexity if we want to offer WMI + fallback to Winternl. I think it can be handle quite "elegantly" with a design pattern, but of course it would be easier to just stick with WMI for frequency. General DesignStrategy Design PatternIf WMI can't be used, we switch back to Winternl System Services. As we'll only know this at runtime, one way to implement this is to use a Strategy in trait FreqStrategy {
fn current(&self) -> Frequency;
fn max(&self) -> Option<Frequency>;
fn min(&self) -> Option<Frequency> {
None
}
}
struct WmiStrategy;
impl FreqStrategy for WmiFreqStrategy {
// -snip- use WMI to retrieve info
}
struct WinternlStrategy;
impl FreqStrategy for WinternlStrategy {
// -snip- use winternl to retrieve info
}
pub struct CpuFrequency {
// We use trait object to represent the abstract strategy
strategy: Box<dyn FreqStrategy>,
}
impl CpuFrequency {
pub fn current(&self) -> Frequency {
self.strategy.current()
}
pub fn max(&self) -> Option<Frequency> {
self.strategy.max()
}
pub fn min(&self) -> Option<Frequency> {
self.strategy.min()
}
}
pub async fn frequency() -> Result<CpuFrequency> {
// -snip- chose strategy: if WMI Connection fail, switch to Winternl
} Pitfall: I was not expecting WMI ConnectionFor better performance, it is better to initialize the WMI Connection once, and then use it to query for frequency or other information. I guess one use case for heim-cpu is to get "real-time" CPU frequency update, and therefore to poll regularly the connection to get the info. The WMI Connection could be a member of the New BindingsBoth strategies would be moved to the binding module if it's appropriate (i do not get yet the signification of the binding module, if you can help me). Per-CPU FrequenciesThere is some reflexion to have here, as the information is available only with WMI and not with Winternl. Regards, |
Hey, @apennamen, sorry for not getting back to you earlier.
I don't know much about Windows, but what are chances that WMI will be unaccessible on user machine?
All top-level functions are marked as As I mentioned before, all functions in
That sounds like a better approach: if it will be painless to integrate, I would prefer to replace whole Windows implementation with WMI. Let me know what you think about it! |
Hello @svartalf ! It's okay I tested an implementation with the strategy, we can have both winternl and WMI.
I have absolutely no previous experience with WMI, but I'll ask on the windows-dev channel of the discord if we can take for word the info in the MSDN documentation ^^
Yes in fact it's only for the "current" getter that could have been interesting to trigger the wmi query. In your opinion, what is the best place to write the lazy_static WMI Connection ? I'll have to try different options and see which is best :) Regards, |
Hey!
Any news on that?
I would prefer to stick with the current flow, when we load everything at once and getters are actually getters. I imagine that fetching all that info in one query is way cheaper than doing multiple queries for each getter.
I guess if we will use it everywhere, putting it somewhere in the |
CallNtPowerInformation
andPROCESSOR_POWER_INFORMATION
combination returns some nominal frequency values, which are not really useful and on some systems could produce really weird values (ex. current frequency = 0, see #229).It seems that WMI query for
Win32_Processor
is more reliable, it should be checked ifheim
should use WMI to load that info.Points to check:
wmi
crate?The text was updated successfully, but these errors were encountered: