【Rust调用Windows API】读取系统CPU利用率

前言

本片文章介绍使用Rust调用Windows系统API读取当前CPU的利用率(Kernel、User)、空闲率。

依赖

需要使用processthreadsapi.h头文件中定义的函数,在Cargo.toml加上这个feature

shell 复制代码
winapi = { version = "0.3.9", features = ["processthreadsapi"] }

实现

接口函数定义

读取CPU利用率需要读取两次CPU的利用时间来计算,使用 GetSystemTimes 函数:

rust 复制代码
pub fn GetSystemTimes(
    lpIdleTime: LPFILETIME,
    lpKernelTime: LPFILETIME,
    lpUserTime: LPFILETIME,
) -> BOOL;

函数接收三个参数,返回读取结果

  • lpIdleTime :指向 FILETIME 的指针,此结构接收系统处于空闲状态的时间量
  • lpKernelTime :指向FILETIME 的指针,此结构接收系统处于内核模式的时间量,其中包含空闲状态
  • lpUserTime :指向FILETIME 的指针,此结构接收系统处于用户模式的时间量

读取时间量

首先用Rust实现读取这三个时间量的函数(Result和WinError是自定义的,详情见上一篇文章:系统错误代码转为可读文本信息):

rust 复制代码
use winapi::shared::minwindef::FILETIME;
use winapi::um::errhandlingapi::GetLastError;
use winapi::um::processthreadsapi::GetSystemTimes;

pub struct SystemTimes {
    idle: FILETIME,
    kernel: FILETIME,
    user: FILETIME,
}
///
 获取自开机以来CPU时间信息,可用于计算CPU Usage
pub fn get_system_times() -> error::Result<SystemTimes> {
    let mut idle: FILETIME = unsafe { std::mem::zeroed() };
    let mut kernel: FILETIME = unsafe { std::mem::zeroed() };
    let mut user: FILETIME = unsafe { std::mem::zeroed() };
    unsafe {
        //  https://learn.microsoft.com/zh-cn/windows/win32/api/processthreadsapi/nf-processthreadsapi-getsystemtimes
        let res = GetSystemTimes(
            &mut idle as *mut FILETIME,
            &mut kernel as *mut FILETIME,
            &mut user as *mut FILETIME,
        );

        if res == 0 {
            return Err(WinError::with_code(GetLastError()));
        }
    };

    Ok(SystemTimes::new(idle, kernel, user))
}

解释时间量

这个函数得到的是一个封装了三个时间量的自定义结构体 SystemTimes,但里面的时间并不是我们常规使用的以毫秒或纳秒为单位的数字表示,而是以一个单位为百纳秒的高32位和低32位组成的结构体,直白的说它表示的是一个64位整数,只是这个整数分为高和低两段(为了兼容以前的32位机器),单位为百纳秒,百纳秒就是 100 纳秒。

这是FILETIME的定义

rust 复制代码
STRUCT!{#[debug] struct FILETIME {
    dwLowDateTime: DWORD,
    dwHighDateTime: DWORD,
}}

下面是我写的几个翻译FILETIME的工具函数,这几个函数是通用的,后面但凡涉及到FILETIME结构体的解析都可以使用它。

rust 复制代码
use std::time::Duration;
use winapi::shared::minwindef::FILETIME;

/// 将C中的 FILETIME 转为64位数字,单位为百纳秒
pub fn parse_filetime(filetime: FILETIME) -> u64 {
    u64::wrapping_shl(filetime.dwHighDateTime as u64, 32) | filetime.dwLowDateTime as u64
}

/// 解析 FILETIME 为 Duration,精度为纳秒
pub fn parse_filetime_duration(filetime: FILETIME) -> Duration {
    Duration::from_nanos(parse_filetime(filetime) * 100)
}

/// 计算两个 FILETIME 时间间隔,单位百纳秒
pub fn calculate_time_gap(start: FILETIME, end: FILETIME) -> i64 {
    let a = parse_filetime(start);
    let b = parse_filetime(end);

    (b - a) as i64
}

这里提示一下:左位移在Rust里面可能存在溢出,不能像其他语言这样写:

java 复制代码
a << 32 | b

Rust有溢出检查,有存在溢出的可能都通过不了编译,所以这里先转为64位再左位移,位移使用 wrapping_shl 函数

计算CPU利用率

计算CPU利用率需要两次间隔一定时间来算,这里写一个测试代码,每隔1秒读取一次CPU使用时间量,循环10次,计算出每秒CPU的使用情况

rust 复制代码
#[test]
pub fn test_system_times() {
    let mut count = 0;
    let mut last_times = get_system_times().unwrap();
    while count < 10 {
        sleep(Duration::from_secs(1));

        let cur_times = get_system_times().unwrap();

        let idle = calculate_time_gap(last_times.get_idle(), cur_times.get_idle()) as f64;
        let kernel = calculate_time_gap(last_times.get_kernel(), cur_times.get_kernel()) as f64;
        let user = calculate_time_gap(last_times.get_user(), cur_times.get_user()) as f64;

        let sum = kernel + user;

        let idle_percent = idle * 100.0 / sum;
        let cpu_percent = (sum - idle) * 100.0 / sum;

        let kernel_percent = (kernel - idle) * 100.0 / sum;
        let user_percent = user * 100.0 / sum;

        println!("CPU利用率:{:.2}% (Kernel: {:.2}%\tUser:{:.2}%)\tCPU空闲率:{:.2}%", cpu_percent, kernel_percent, user_percent, idle_percent);

        last_times = cur_times;
        count += 1;
    }
}

运行结果

text 复制代码
CPU利用率:12.60% (Kernel: 6.04%	User:6.56%)	CPU空闲率:87.40%
CPU利用率:2.33% (Kernel: 0.78%	User:1.55%)	CPU空闲率:97.67%
CPU利用率:1.56% (Kernel: 0.78%	User:0.78%)	CPU空闲率:98.44%
CPU利用率:7.03% (Kernel: 3.39%	User:3.65%)	CPU空闲率:92.97%
CPU利用率:0.78% (Kernel: 0.52%	User:0.26%)	CPU空闲率:99.22%
CPU利用率:1.56% (Kernel: 0.00%	User:1.56%)	CPU空闲率:98.44%
CPU利用率:2.05% (Kernel: 0.77%	User:1.28%)	CPU空闲率:97.95%
CPU利用率:4.74% (Kernel: 2.63%	User:2.11%)	CPU空闲率:95.26%
CPU利用率:0.52% (Kernel: 0.26%	User:0.26%)	CPU空闲率:99.48%
CPU利用率:2.33% (Kernel: 1.04%	User:1.30%)	CPU空闲率:97.67%
相关推荐
lucky67072 小时前
Windows 上彻底卸载 Node.js
windows·node.js
编程小白20262 小时前
从 C++ 基础到效率翻倍:Qt 开发环境搭建与Windows 神级快捷键指南
开发语言·c++·windows·qt·学习
凯子坚持 c4 小时前
CANN 性能剖析实战:从原始事件到交互式火焰图
windows·microsoft
开开心心就好4 小时前
发票合并打印工具,多页布局设置实时预览
linux·运维·服务器·windows·pdf·harmonyos·1024程序员节
獨枭4 小时前
PyCharm 跑通 SAM 全流程实战
windows
仙剑魔尊重楼5 小时前
音乐制作电子软件FL Studio2025.2.4.5242中文版新功能介绍
windows·音频·录屏·音乐·fl studio
PHP小志6 小时前
Windows 服务器怎么修改密码和用户名?账户被系统锁定如何解锁
windows
Hello.Reader6 小时前
Rocket Fairings 实战把全局能力做成“结构化中间件”
中间件·rust·rocket
Andrew_Ryan6 小时前
rust arena 内存分配
rust
Andrew_Ryan6 小时前
深入理解 Rust 内存管理:基于 typed_arena 的指针操作实践
rust