#性能分析 #性能 #多线程 #作用域 #仪器化

profi

基于作用域的单线程和多线程性能分析

3 个版本

0.1.2 2024年3月30日
0.1.1 2024年3月30日
0.1.0 2024年3月30日

开发工具 中排名第 415

每月下载量 25
用于 hunt

MIT 许可

36KB
546

Profi

单线程和多线程应用程序的简单分析器。

记录作用域结束所需的时间,并在程序退出时打印计时结果。

每次测量的开销为 ~25ns-50ns,因此它不应影响基准测试。
运行 基准测试 示例以查看您的机器上的开销。

配置

profienable 功能控制,该功能默认启用。
当禁用时,所有宏和方法都将变为无操作,从而对您的代码没有任何影响。

要禁用它,请将 default-features = false 添加到您的 Cargo.toml 中的 profi 依赖项。

为了方便,您还可以添加一个自定义功能

[dependencies]
profi = { version = "*", default-features = false }

[features]
prof = ["profi/enable"]

并使用 cargo run --release --features prof

如果您使用 rayon,请启用 rayon 功能

使用方法

有关更多使用案例,请参阅 examples

基本使用

use profi::{prof, print_on_exit};

fn main() {
 // Prints the timings to stdout when the program exits
 // Always put at the top of the main function to ensure it's dropped last
 //
 // An implicit `main` guard is created to profile the whole application
 print_on_exit!();

 // Sleep for a bit to simulate some work
 std::thread::sleep(std::time::Duration::from_millis(200));
}
┌──────────────┬────────────────────┬───────────┬──────────────┬───────┐
│ Name         ┆ % Application Time ┆ Real Time ┆ Average time ┆ Calls │
╞══════════════╪════════════════════╪═══════════╪══════════════╪═══════╡
│ simple::main ┆ 100.00%            ┆ 200.13ms  ┆       -      ┆     1 │
└──────────────┴────────────────────┴───────────┴──────────────┴───────┘

循环

use profi::{prof, print_on_exit};

fn main() {
  print_on_exit!();

  for _ in 0..100 {
      prof!(iteration);
      std::thread::sleep(std::time::Duration::from_millis(10));
  }
}
┌────────────┬────────────────────┬───────────┬──────────────┬───────┐
│ Name       ┆ % Application Time ┆ Real Time ┆ Average time ┆ Calls │
╞════════════╪════════════════════╪═══════════╪══════════════╪═══════╡
│ loop::main ┆ 100.00%            ┆ 1.01s     ┆       -      ┆     1 │
├╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┤
│ iteration  ┆ 99.99%             ┆ 1.01s     ┆ 10.10ms/call ┆   100 │
└────────────┴────────────────────┴───────────┴──────────────┴───────┘

多个线程

use profi::{print_on_exit, prof_guard};

fn do_work(i: usize) {
    // Need to bind it to a variable to ensure it isn't dropped before sleeping
    let _guard = if i < 6 {
        prof_guard!("6 first")
    } else {
        prof_guard!("4 last")
    };
    std::thread::sleep(std::time::Duration::from_millis(10));
    // The guard goes out of scope here
}

fn main() {
    print_on_exit!();
    
    // Spawn 10 threads
    std::thread::scope(|s| {
        for i in 0..10 {
            s.spawn(move || {
                do_work(i);
            });
        }
    });
}
┌───────────────┬────────────────────┬───────────┬────────────┬──────────┬──────────────┬───────┐
│ Name          ┆ % Application Time ┆ Real Time ┆ % CPU Time ┆ CPU Time ┆ Average time ┆ Calls │
╞═══════════════╪════════════════════╪═══════════╪════════════╪══════════╪══════════════╪═══════╡
│ threads::main ┆ 100.00%            ┆ 10.48ms   ┆ 9.43%      ┆ 10.48ms  ┆       -      ┆     1 │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┤
│ 6 first       ┆ 96.42%             ┆ 10.11ms   ┆ 54.38%     ┆ 60.44ms  ┆ 10.08ms/call ┆     6 │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌┤
│ 4 last        ┆ 95.93%             ┆ 10.06ms   ┆ 36.19%     ┆ 40.22ms  ┆ 10.06ms/call ┆     4 │
└───────────────┴────────────────────┴───────────┴────────────┴──────────┴──────────────┴───────┘

"CPU 时间" 是所有线程在该作用域上花费的总时间。

例如,"6 first" 的 "CPU 时间" 为 60 毫秒,因为每个线程等待 10ms,而程序创建了六个这样的线程。

属性

启用 attributes 功能以在函数上使用 profile 属性。
这将在函数的开始处添加一个保护器。

use profi::profile;

#[profile]
fn anotated() { /* ... */ }

功能

名称 描述
enable 激活性能分析,如果不激活,所有宏都将变为无操作
attributes 启用 #[prof]
deep-hierarchy 默认情况下,profi 会合并函数的所有使用,使用此功能可以禁用此行为。
有关更多信息,请参阅 nested 示例
nightly 启用仅在夜间进行的优化(目前未使用)
rayon 如果使用 rayon 则是必要的

依赖关系

~0–0.9MB
~15K SLoC