这只是关于我最近在Rust生态系统中发现的东西的简短文章:
如果您订阅了Medium,并希望支持我,则可以阅读Medium上的这篇文章。
Criterion是Rust生态系统中一个众所周知且经常使用的基准测试框架。如果您还没有听说过,一定要查看一下!
从v0.3开始,Criterion支持进程内分析挂钩,它们允许我们在运行基准测试时使用自定义探查器。注册自定义探查器后,我们可以通过使用--profile-time标志运行基准测试套件来启用它们。
为基准测试有一个用于自定义探查器的钩子,您可以做一些很棒的事情,例如,使用pprof为每个基准测试生成火焰图。
这些数字很棒。但是我们怎样才能更快地做到这一点呢?我们在哪里花费最多的时间?”
以前,我只靠使用可靠的实用工具-cargo-flamegraph弄脏了手,但是问题是,当使用带有基准的cargo-flamegraph时,通常会出现一些不必要的混乱情况,例如基准测试的设置例程以及Criterion附带的框架代码。
pprof是一个CPU事件探查器,可用于在Linux上探查程序的特定部分。最重要的是:它甚至支持使用功能标志flamegraph生成探查图。
现在,我们将使用pprof为标准创建自定义探查器,该探查器将为每个基准打印火焰图。
[dev-依赖项] pprof = {版本=" 0.3" ,功能= [" flamegraph" ]}准则=" 0.3" #条件宏=" 0.3" #可选,如果您使用自定义测试框架
现在在您的长椅/文件夹中创建一个新文件。我们称之为perf.rs。在这里,我们将实现新的FlamegraphProfiler。
实现自定义事件探查器的接口实际上很简单,我们只需要实现Criterion的Criteria :: profiler :: Profiler特质就可以了。
使用std :: {fs :: File,os :: raw :: c_int,path :: Path};使用标准::探查器::探查器;使用pprof :: ProfilerGuard; ///可以与Criterion一起使用的小型自定义探查器,可以为基准创建火焰图。 ///另请参见[关于此的条件文档] [custom-profiler]。 /// /// ##有关如何启用定制分析器的示例:/// ///```/// mod perf; ///使用perf :: FlamegraphProfiler; /// /// fn fibonacci_profiled(criterion:& mut Criterion){/// //在此处正常使用准则struct。 ///} /// /// fn custom()-> Criterion {/// Criterion :: default()。with_profiler(FlamegraphProfiler :: new())///} /// /// criteria_group! {///名称=长凳; /// config = custom(); ///目标= fibonacci_profiled ///} ///```/// ///这样做的好处是它将仅对基准进行采样,而不对诸如///设置过程之类的东西进行采样。 /// ///此外,只有将`--profile-time< time>`传递给基准二进制文件时,它才会启动。 ///将在其报告目录中的每个单独基准中创建一个火焰图,///`profile / flamegraph.svg`下。 /// /// [custom-profiler]:https://bheisler.github.io/criterion.rs/book/user_guide/profiling.html#implementing-in-process-profiling-hooks发布结构FlamegraphProfiler< ' a> {频率:c_int,active_profiler:选项< ProfilerGuard< ' a> ,} impl< ' a> FlamegraphProfiler< ' a> {#[allow(dead_code)] pub fn new(频率:c_int)->自我{FlamegraphProfiler {频率,active_profiler:无,}}} impl< ' a> FlamegraphProfiler< ' a> {fn start_profiling(& mut self,_benchmark_id:& str,_benchmark_dir:& Path){self。 active_profiler = Some(ProfilerGuard :: new(self。frequency)。unwrap()); } fn stop_profiling(& mut self,_benchmark_id:& str,Benchmark_dir:& Path){std :: fs :: create_dir_all(beta_dir)。解开();让flamegraph_path = Benchmark_dir。加入(" flamegraph.svg"); let flamegraph_file = File :: create(& flamegraph_path)。期望("创建flamegraph.svg"时发生文件系统错误);如果让Some(分析者)=自我。 active_profiler。接受(){分析器。报告()。 build()。展开()。 Flamegraph(flamegraph_file)。期望("编写flamegraph错误"); }}}
要使用新的探查器,我们需要在Criterion中注册它。另请参阅Criterion的高级配置。
如果您将自定义测试框架功能与criteria-macro结合使用,则可以使用以下命令对其进行配置:
#![feature(custom_test_frameworks)]#![test_runner(criterion :: runner)]使用准则:: {Criterion,black_box};使用standard_macro ::条件;国防部性能; fn斐波那契(n:u64)-> u64 {匹配n {0 | 1 => 1,n => 1。斐波那契(n-1)+斐波那契(n-2),}} fn custom_criterion()->条件{Criterion :: default()。 with_profiler(perf :: FlamegraphProfiler :: new(100))}#[criterion(custom_criterion())] fn bench_custom(c:& mut Criterion){c。 bench_function(" Fibonacci-Custom",| b | b。iter(|| fibonacci(black_box(20)))); }
国防部性能;条件组! {名称=长凳; //这可以是任何返回`Criterion`对象的表达式。 config = Criterion :: default()。 with_profiler(perf :: FlamegraphProfiler :: new(100);目标=工作台}
既然我们已经设置了自定义探查器,那么就可以将其实际用于基准测试,如下一节所述。
要在不以root用户身份运行基准的情况下启用性能分析,您可能需要将Linux内核中的perf_event_paranoid的值调整为适合您的环境的值。最允许的值为-1。
使用我们的自定义FlamegraphProfiler,此命令将在benchs / my_bench.rs中运行基准5秒钟。
注意:您需要指定基准的名称,否则可能会收到错误Unrecognized选项:' profile-time'。有关有效的命令行选项,另请参见长条凳给出“ Uncognized Option”的错误。