使用Rust构建一个CPU基准测试工具

481次阅读  |  发布于1年以前

在这篇文章中,我们将创建一个能执行的Rust脚本来测量CPU的性能。

为了实现目标,我们将创建一些在循环中运行的虚拟计算,分布在所有可用的CPU 内核上。理想情况下,我们的计算需要CPU密集型任务,所以我们尽可能接近100%的CPU使用率。

创建一个Rust项目:

cargo new cpu-benchmark

在Cargo.toml文件中添加如下代码:

[dependencies]
indicatif = "0.17.5"
sysinfo = "0.29.7"

[profile.release]
lto = "fat"
strip = "debuginfo"

因为计算阶乘是一项cpu密集型任务,所以我们首先在src/main.rs文件中写入一个计算阶乘的函数:

pub fn factorial(num: u128) -> u128 {
    (1..=num).product()
}

然后,我们在循环中调用这个阶乘函数:

fn add_one_loop(&n_loops: &u64) {
    for _in in 0..n_loops {
        let _ = factorial(20);
    }
}

在main函数中,我们需要做一些处理:

对于系统信息,我们使用一个名为sysinfo的crate:

use sysinfo::{System, SystemExt};

fn main() {
    let mut sys = System::new_all();
    sys.refresh_all();
    // 显示系统信息
    println!("System name:             {:?}", sys.name());
    println!("System kernel version:   {:?}", sys.kernel_version());
    println!("System OS version:       {:?}", sys.os_version());
    println!("System host name:        {:?}", sys.host_name());
    // 获取CPU数
    println!("Number of available threads: {}", sys.cpus().len());
}

进度条我们使用另一个名为indicatif的crate,此外,我们还测量开始和结束之间的时间,并计算每秒的计算次数以获得分数。

main.rs的完整代码如下:

use std::{thread::available_parallelism, time::Instant, env};

use indicatif::ProgressBar;
use sysinfo::{System, SystemExt};


pub fn factorial(num: u128) -> u128 {
    (1..=num).product()
}

fn add_one_loop(&n_loops: &u64) {
    for _in in 0..n_loops {
        let _ = factorial(20);
    }
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let num_calcs_arg: Option<&String> = args.get(1);
    let num_calcs: u64 = match num_calcs_arg {
        Some(num_calcs_arg) => num_calcs_arg.trim().parse::<u64>().unwrap(),
        None => 400000000, 
    };
    let num_iters: u64 = 20000;
    let total_calc: u64 = num_calcs * num_iters;
    println!(
        "Running {} calculations over {} iterations each with a total of {} calculations.",
        &num_calcs, &num_iters, &total_calc,
    );

    // 获取系统信息
    let mut sys = System::new_all();
    sys.refresh_all();
    // 显示系统信息
    println!("System name:             {:?}", sys.name());
    println!("System kernel version:   {:?}", sys.kernel_version());
    println!("System OS version:       {:?}", sys.os_version());
    println!("System host name:        {:?}", sys.host_name());
    // 获取CPU数
    println!("Number of available threads: {}", sys.cpus().len());

    // 获取我们可以使用多少线程的信息,并使用其中的一半
    let available_cores: u64 = available_parallelism().unwrap().get() as u64;
    let iter_per_core: u64 = num_calcs / available_cores;

    let now = Instant::now();

    let bar = ProgressBar::new(num_iters);
    for _i in 0..num_iters {
        let mut results = Vec::new();
        let mut threads = Vec::new();
        for _i in 0..available_cores {
            threads.push(std::thread::spawn(move || add_one_loop(&iter_per_core)));
        }
        for thread in threads {
            results.extend(thread.join());
        }
        bar.inc(1);
    }
    bar.finish();

    let elapsed = now.elapsed();
    let calc_per_sec: f64 = (total_calc as f64) / (elapsed.as_secs() as f64);
    println!("Total runtime: {:.2?}", elapsed);
    println!("Calculations per second: {:.2?} seconds.", calc_per_sec);
}

现在运行如下命令测试我们的简单脚本:

cargo run --release

结果如下:

Running 400000000 calculations over 20000 iterations each with a total of 8000000000000 calculations.
System name:             Some("Darwin")
System kernel version:   Some("21.6.0")
System OS version:       Some("12.6.6")
System host name:        Some("master")
Number of available threads: 4
███████████████████████████████████████████████████████████████████████████████████████████████████████████████████ 20000/20000
Total runtime: 2.52s
Calculations per second: 4000000000000.00 seconds.

我们获得了系统信息、运行时间、进度条和可解释的基准分数。

Copyright© 2013-2020

All Rights Reserved 京ICP备2023019179号-8