#基准测试 #延迟 #测试

bursty

测试支持在多线程代码中加剧竞争

1 个不稳定版本

0.1.0 2023 年 8 月 26 日

#710并发

MIT/Apache

26KB
430

一个测试支持库,用于加剧测试代码中的竞争。

目标

  • 通过加剧竞争来帮助模糊测试多线程代码。
  • 帮助在高竞争下基准测试多线程代码。

动机

在开发多线程代码时,通常会提出两个问题:

  • 它是否正确?
  • 它是否足够快?

遗憾的是,虽然可能可以彻底测试串行代码的所有代码路径,但没有被测试代码的广泛合作,测试并发代码的所有潜在交织是不可能的。同样,基准测试并发代码可能相当困难,特别是测量延迟。

这就是 Bursty 的目的:帮助构建测试和基准测试,作为管道中的一系列步骤,其中所有并发线程都同步执行每个步骤,从而在每个步骤中最大化竞争。

[^1] 有关有趣的方法,请参阅 loom

它是如何工作的?

Bursty 是一个框架,用于在用户配置的线程数上同步执行一系列步骤,同时访问全局共享和线程局部状态。

快速演示 —— 摘自 BurstyBuilder 文档

use std::sync::atomic::{AtomicI32, Ordering};
use bursty::BurstyBuilder;

//  Construct a builder with a globally-shared `AtomicI32` and two thread-local "states" (1 and 10).
let mut builder = BurstyBuilder::new(AtomicI32::new(0), vec!(1, 10));

//  Add a step in the pipeline to execute on each thread, which adds the local integer to the global one.
builder.add_simple_step(|| |global: &AtomicI32, local: &mut i32| { global.fetch_add(*local, Ordering::Relaxed); });

//  Launch the execution, with 4 iterations of the pipeline.
let mut bursty = builder.launch(4);

assert!(44 >= bursty.global().load(Ordering::Relaxed));

//  Join all threads, blocking until they are done, or one panicks.
bursty.join();

//  Check the global and local states.
assert_eq!(44, bursty.global().load(Ordering::Relaxed));
assert_eq!(vec!(1, 10), bursty.into_locals());

重要的是要注意,用户定义的步骤不必在所有线程上具有相同的行为。例如,步骤可以完美地添加奇数并减去偶数。这允许测试混合的工作负载。

如何实现同步执行?

通过自旋。

在执行每个步骤之间,Bursty 注入一个会合点,一个初始化为线程数的简单原子整数。当达到这个原子时,每个线程都会递减它,然后自旋,直到原子为 0,然后继续。

这是确保所有线程几乎同时开始执行下一个步骤的最准确方式,但这也意味着极端的 CPU 密集型。

通常不建议在机器上运行比物理核心更多的线程。

如何进行模糊测试?

使用Bursty进行模糊测试时,只需创建测试流水线,并根据执行时间和你愿意等待的时间调整迭代次数。每次迭代可能与其他迭代有略微不同的间隔,随着时间的推移,将测试越来越多不同的间隔...但并没有一个保证所有间隔都会被测试的神奇数字。

如何进行基准测试?

选择一个允许用户报告测量的基准测试框架,然后创建流水线。为了提高效率,建议创建一个可以多次连续执行的自动重置流水线,并一次性安排多个迭代,这样就不需要每次都创建N个线程。

类似项目

我不知道有任何项目允许在高度竞争下进行基准测试延迟。

对于测试正确性,正如所述,loom可能会很有兴趣。特别是,loom更有可能提供确定的答案,而模糊测试方法只能提高信心。

无运行时依赖