Skip to content

Commit

Permalink
benchmark
Browse files Browse the repository at this point in the history
  • Loading branch information
huixie90 committed Jun 5, 2024
1 parent dcf54d9 commit 1244988
Show file tree
Hide file tree
Showing 6 changed files with 567 additions and 2 deletions.
332 changes: 331 additions & 1 deletion any_view.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion impl/any_view/any_view_te.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ constexpr auto operator<=>(category lhs, category rhs) noexcept {
} // namespace __any_view

template <class Ref, category Cat = category::input, class Value = decay_t<Ref>,
class RValueRef = add_rvalue_reference_t<Value>,
class RValueRef = add_rvalue_reference_t<remove_reference_t<Ref>>,
class Diff = ptrdiff_t>
class any_view {
public:
Expand Down
31 changes: 31 additions & 0 deletions impl/any_view/benchmark/micro.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#include <benchmark/benchmark.h>

#include <ranges>
#include <vector>

#include "any_view.hpp"

static void BM_vector(benchmark::State& state) {
std::vector v =
std::views::iota(0, state.range(0)) | std::ranges::to<std::vector>();
for (auto _ : state) {
for (auto i : v) {
benchmark::DoNotOptimize(i);
}
}
}
// Register the function as a benchmark
BENCHMARK(BM_vector)->RangeMultiplier(2)->Range(1 << 10, 1 << 18);

// Define another benchmark
static void BM_AnyView(benchmark::State& state) {
std::vector v =
std::views::iota(0, state.range(0)) | std::ranges::to<std::vector>();
std::ranges::any_view<int&> av(std::views::all(v));
for (auto _ : state) {
for (auto i : av) {
benchmark::DoNotOptimize(i);
}
}
}
BENCHMARK(BM_AnyView)->RangeMultiplier(2)->Range(1 << 10, 1 << 18);
105 changes: 105 additions & 0 deletions impl/any_view/benchmark/pipeline.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#include <benchmark/benchmark.h>

#include <random>
#include <ranges>
#include <vector>

#include "any_view.hpp"
#include "widget.hpp"

namespace {

constexpr auto MaxSize = 1 << 18;

auto generate_random_widgets() {
std::vector<lib::Widget> widgets;
widgets.reserve(MaxSize);

static const char alphanum[] =
"0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz";
std::random_device char_dev;
std::mt19937 char_rng(char_dev());
std::uniform_int_distribution<std::mt19937::result_type> char_dist(
0, sizeof(alphanum) - 1);

std::random_device len_dev;
std::mt19937 len_rng(len_dev());
std::uniform_int_distribution<std::mt19937::result_type> len_dist(1, 30);

auto gen_next_str = [&]() {
int len = len_dist(len_rng);
std::string tmp_s;
tmp_s.reserve(len);

for (int i = 0; i < len; ++i) {
tmp_s.push_back(alphanum[char_dist(char_rng)]);
}

return tmp_s;
};

std::random_device w_dev;
std::mt19937 w_rng(w_dev());
std::uniform_int_distribution<int> w_dist(0, 100);

auto gen_size = [&] { return w_dist(w_rng); };

for (auto i = 0; i < MaxSize; ++i) {
widgets.push_back(lib::Widget{gen_next_str(), gen_size()});
}
return widgets;
}

const auto global_widgets = generate_random_widgets();
} // namespace

using namespace lib;

static void BM_AnyViewPipeline(benchmark::State& state) {
lib::UI1 ui1{global_widgets | std::views::take(state.range(0)) |
std::ranges::to<std::vector>()};
for (auto _ : state) {
for (auto const& name : ui1.getWidgetNames()) {
benchmark::DoNotOptimize(const_cast<std::string&>(name));
}
}
}
BENCHMARK(BM_AnyViewPipeline)->RangeMultiplier(2)->Range(1 << 10, 1 << 18);

static void BM_RawPipeline(benchmark::State& state) {
lib::UI2 ui2{global_widgets | std::views::take(state.range(0)) |
std::ranges::to<std::vector>()};
for (auto _ : state) {
for (const auto& name : ui2.getWidgetNames()) {
benchmark::DoNotOptimize(const_cast<std::string&>(name));
}
}
}
// Register the function as a benchmark
BENCHMARK(BM_RawPipeline)->RangeMultiplier(2)->Range(1 << 10, 1 << 18);

static void BM_VectorCopy(benchmark::State& state) {
lib::UI3 ui3{global_widgets | std::views::take(state.range(0)) |
std::ranges::to<std::vector>()};
for (auto _ : state) {
for (const auto& name : ui3.getWidgetNames()) {
benchmark::DoNotOptimize(const_cast<std::string&>(name));
}
}
}
// Register the function as a benchmark
BENCHMARK(BM_VectorCopy)->RangeMultiplier(2)->Range(1 << 10, 1 << 18);

static void BM_VectorRefWrapper(benchmark::State& state) {
lib::UI4 ui4{global_widgets | std::views::take(state.range(0)) |
std::ranges::to<std::vector>()};
for (auto _ : state) {
for (const auto& nameRef : ui4.getWidgetNames()) {
benchmark::DoNotOptimize(const_cast<std::string&>(nameRef.get()));
}
}
}
// Register the function as a benchmark
BENCHMARK(BM_VectorRefWrapper)->RangeMultiplier(2)->Range(1 << 10, 1 << 18);
46 changes: 46 additions & 0 deletions impl/any_view/benchmark/widget.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#include "widget.hpp"

namespace lib {

std::ranges::any_view<const std::string&> UI1::getWidgetNames() const {
return widgets_ | std::views::filter([](const Widget& widget) {
return widget.size > 10;
}) |
std::views::transform(&Widget::name);
}

bool UI2::FilterFn::operator()(const Widget& widget) const {
return widget.size > 10;
}

const std::string& UI2::TransformFn::operator()(const Widget& widget) const {
return widget.name;
}

std::ranges::transform_view<
std::ranges::filter_view<std::ranges::ref_view<const std::vector<Widget>>,
UI2::FilterFn>,
UI2::TransformFn>
UI2::getWidgetNames() const {
return widgets_ | std::views::filter(UI2::FilterFn{}) |
std::views::transform(UI2::TransformFn{});
}

std::vector<std::string> UI3::getWidgetNames() const {
return widgets_ | std::views::filter([](const Widget& widget) {
return widget.size > 10;
}) |
std::views::transform(&Widget::name) | std::ranges::to<std::vector>();
}

std::vector<std::reference_wrapper<const std::string>> UI4::getWidgetNames()
const {
return widgets_ | std::views::filter([](const Widget& widget) {
return widget.size > 10;
}) |
std::views::transform(
[](const Widget& widget) { return std::cref(widget.name); }) |
std::ranges::to<std::vector>();
}

} // namespace lib
53 changes: 53 additions & 0 deletions impl/any_view/benchmark/widget.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#pragma once

#include <ranges>
#include <string>
#include <vector>

#include "any_view.hpp"

namespace lib {

struct Widget {
std::string name;
int size;
};

struct UI1 {
std::vector<Widget> widgets_;

std::ranges::any_view<const std::string&> getWidgetNames() const;
};

struct UI2 {
std::vector<Widget> widgets_;
// cannot use lambda because we need to spell the type of the view
struct FilterFn {
bool operator()(const Widget&) const;
};

struct TransformFn {
const std::string& operator()(const Widget&) const;
};
std::ranges::transform_view<
std::ranges::filter_view<std::ranges::ref_view<const std::vector<Widget>>,
FilterFn>,
TransformFn>
getWidgetNames() const;
};

struct UI3 {
std::vector<Widget> widgets_;

std::vector<std::string> getWidgetNames() const;
};

struct UI4 {
std::vector<Widget> widgets_;

std::vector<std::reference_wrapper<const std::string>> getWidgetNames() const;
};



} // namespace lib

0 comments on commit 1244988

Please sign in to comment.