使用 Rust 構建一個 CPU 基準測試工具

在這篇文章中,我們將創建一個能執行的 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("23.4.0")
System OS version:       Some("14.4.1")
System host name:        Some("Koshkaaas-MacBook-Pro.local")
Number of available threads: 10
████████████████████████████████████████████████████████████████████████████████████ 20000/20000Total runtime: 1.99s
Calculations per seconds: 4011255834575.31 seconds

我們獲得了系統信息、運行時間、進度條和可解釋的基準分數。

posted @ 2024-04-16 15:12  RioTian  阅读(57)  评论(0编辑  收藏  举报