正确获取 std::valarray 到(google/quick)工作台

Posted

技术标签:

【中文标题】正确获取 std::valarray 到(google/quick)工作台【英文标题】:Getting std::valarray to (google/quick) bench properly 【发布时间】:2021-02-28 10:59:47 【问题描述】:

我正在尝试比较使用 std::valarray 与使用 Google Bench 的 std::vector/std::transform 操作的性能。我正在使用 QuickBench。

我的代码(用于 QuickBench)是

#include <random>

class RG 
public:
    double operator()() noexcept  return dis(gen);  
private:
    std::mt19937 gen std::random_device();
    std::uniform_real_distribution<> dis 0.0, 100.0;
;

static RG rg ;

static constexpr auto N = 1000;

#include <vector>
#include <algorithm>

static void Vector(benchmark::State& state) 
    std::vector<double> v1, v2;
    v1.reserve(N); v2.reserve(N);
    std::generate_n(back_inserter(v1),N,rg);
    std::generate_n(back_inserter(v2),N,rg);
    for (auto _ : state) 
        std::vector<double> v3; v3.reserve(N);
        std::transform(cbegin(v1), cend(v1), cbegin(v2), back_inserter(v3),
            [](auto d1, auto d2) noexcept  return 0.5*d1+1.5*d2;);
        benchmark::DoNotOptimize(v3);
    

// Register the function as a benchmark
BENCHMARK(Vector);

#include <valarray>

static void ValArray(benchmark::State& state) 
    std::valarray<double> v1N, v2N;
    std::generate(begin(v1),end(v1),rg);
    std::generate(begin(v2),end(v2),rg);
    for (auto _ : state) 
        std::valarray<double> v3;
        v3=0.5*v1+1.5*v2;
        benchmark::DoNotOptimize(v3);
    

BENCHMARK(ValArray);

QuickBench link Quickbench 说 std::valarraystd::vector 快 72 倍。那不可能是对的,对吧? 我做错了什么?

【问题讨论】:

std::vector 的问题在于,它要么强制对您进行零初始化(调整大小),要么大量分支不断检查是否需要新分配(reserve + back_inserter)。 unique_ptr 提供与 valarray 相似的性能:quick-bench.com/q/-aLzQp5kI0AfjU4rj7teRA_Pk5g 这是一个有 500,000 个元素和 par_unseq 版本的:quick-bench.com/q/hF3uylCLK5lMWnj0hZLVTjN23j4 @AyxanHaqverdili 谢谢。我只是想知道 valarray 是否有任何性能。我从来没有看到它在任何代码中使用过。我发现了一些关于它的帖子,称它为“破碎”。 (根据我的经验,它的一部分实际上被破坏了and just recently fixed。但是我发现它的性能相当不错! 【参考方案1】:

第 36 行:

std::valarray<double> v1N, v2N;

这会创建两个单元素valarray-s,也就是说,每个都包含一个值为N=1000 的元素。这是因为列表初始化语法 使用了采用std::initializer_list 的构造函数:

valarray(std::initializer_list<T> il);

它使用该列表的内容构造一个valarray,而不是预期的:

explicit valarray(std::size_t count);

这将构造一个valarraycount 元素。

您需要将该行更改为:

std::valarray<double> v1(N), v2(N);

【讨论】:

以上是关于正确获取 std::valarray 到(google/quick)工作台的主要内容,如果未能解决你的问题,请参考以下文章

将数据从 std::vector 传递到 std::valarray 的最有效方法

为啥 std::valarray 不是算术的?

为啥捕获 lambda 不能应用于 std::valarray?

std::valarray 和 std::array 有啥区别

将 std::vector 分配给 std::valarray

在哪里使用“std::valarray”是个好主意?