c++valarraygoogle-benchmark

Getting std::valarray to (google/quick) bench properly


I'm trying to compare the performance of using std::valarray vs. std::vector/std::transform operations using Google Bench. I'm using QuickBench.

My code (for QuickBench) is

#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> v1{N}, v2{N};
    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 says the std::valarray is 72 times faster then std::vector. That can't be right, right? What am I doing wrong?


Solution

  • Line 36:

    std::valarray<double> v1{N}, v2{N};
    

    This creates two one-element valarray-s, that is, each containing a single element whose value is N=1000. This is because the list-initialization syntax, {}, uses the constructor taking std::initializer_list:

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

    which constructs a valarray with the contents of that list, as opposed to the intended one:

    explicit valarray(std::size_t count);
    

    that would construct a valarray of count elements.

    You need to change that line to:

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