Skip to content

Commit 1b2ac76

Browse files
Benchmarks (#14)
* Added benchmarks * Remove C++23 dependency std::ranges::to * Add "reserved" benchmark for preallocated vector * CMake utility targets for categories
1 parent 4b15f0d commit 1b2ac76

File tree

15 files changed

+419
-18
lines changed

15 files changed

+419
-18
lines changed

CMakeLists.txt

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ install(
7676
PATTERN "${CMAKE_CURRENT_BINARY_DIR}/include/beman/any_view/*.hpp"
7777
)
7878

79-
macro(beman_add_executable)
79+
function(beman_add_executable)
8080
set(options)
8181
set(oneValueArgs CATEGORY TARGET)
8282
set(multiValueArgs SOURCES LIBRARIES)
@@ -90,13 +90,8 @@ macro(beman_add_executable)
9090
)
9191

9292
# [CMAKE.TARGET_NAMES]
93-
set(target
94-
"beman.any_view.${beman_executable_CATEGORY}.${beman_executable_TARGET}"
95-
)
96-
97-
if(NOT beman_executable_SOURCES)
98-
set(beman_executable_SOURCES "${beman_executable_TARGET}.cpp")
99-
endif()
93+
set(category beman.any_view.${beman_executable_CATEGORY})
94+
set(target ${category}.${beman_executable_TARGET})
10095

10196
add_executable(${target})
10297
# [CMAKE.PASSIVE_PROJECTS]
@@ -107,7 +102,13 @@ macro(beman_add_executable)
107102
${target}
108103
PRIVATE beman::any_view ${beman_executable_LIBRARIES}
109104
)
110-
endmacro()
105+
106+
if(NOT TARGET ${category})
107+
add_custom_target(${category})
108+
endif()
109+
110+
add_dependencies(${category} ${target})
111+
endfunction()
111112

112113
if(BEMAN_ANY_VIEW_BUILD_TESTS)
113114
enable_testing()
Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
22

3+
# Fetch Benchmark
4+
FetchContent_Declare(
5+
benchmark
6+
GIT_REPOSITORY https://github.com/google/benchmark.git
7+
GIT_TAG v1.9.2
8+
EXCLUDE_FROM_ALL
9+
)
10+
set(BENCHMARK_ENABLE_TESTING OFF)
311
# Fetch GoogleTest
412
FetchContent_Declare(
513
googletest
@@ -8,18 +16,51 @@ FetchContent_Declare(
816
EXCLUDE_FROM_ALL
917
)
1018
set(INSTALL_GTEST OFF) # Disable GoogleTest installation
11-
FetchContent_MakeAvailable(googletest)
19+
FetchContent_MakeAvailable(benchmark googletest)
1220

1321
include(GoogleTest)
1422

15-
function(beman_add_test)
16-
beman_add_executable(${ARGN} CATEGORY tests LIBRARIES GTest::gtest
17-
GTest::gtest_main
23+
function(beman_add_benchmark name)
24+
beman_add_executable(
25+
TARGET ${name}
26+
SOURCES ${name}.benchmark.cpp ${ARGN}
27+
CATEGORY benchmarks
28+
LIBRARIES benchmark::benchmark
1829
)
19-
gtest_discover_tests(${target})
2030
endfunction()
2131

22-
beman_add_test(TARGET concepts SOURCES concepts.test.cpp)
23-
beman_add_test(TARGET constexpr SOURCES constexpr.test.cpp)
24-
beman_add_test(TARGET sfinae SOURCES sfinae.test.cpp)
25-
beman_add_test(TARGET type_traits SOURCES type_traits.test.cpp)
32+
function(beman_add_tests)
33+
foreach(name ${ARGN})
34+
beman_add_executable(
35+
TARGET ${name}
36+
SOURCES ${name}.test.cpp
37+
CATEGORY tests
38+
LIBRARIES GTest::gtest GTest::gtest_main
39+
)
40+
gtest_discover_tests(beman.any_view.tests.${name})
41+
endforeach()
42+
endfunction()
43+
44+
beman_add_benchmark(
45+
all
46+
detail/eager.cpp
47+
detail/fused.cpp
48+
detail/lazy.cpp
49+
detail/products.cpp
50+
detail/reserved.cpp
51+
)
52+
beman_add_benchmark(
53+
take
54+
detail/eager.cpp
55+
detail/fused.cpp
56+
detail/lazy.cpp
57+
detail/products.cpp
58+
detail/reserved.cpp
59+
)
60+
61+
beman_add_tests(
62+
concepts
63+
constexpr
64+
sfinae
65+
type_traits
66+
)
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2+
3+
#include "detail/eager.hpp"
4+
#include "detail/fused.hpp"
5+
#include "detail/lazy.hpp"
6+
#include "detail/products.hpp"
7+
#include "detail/reserved.hpp"
8+
9+
#include <benchmark/benchmark.h>
10+
11+
constexpr auto max_size = 1 << 18;
12+
13+
const auto global_products = generate_random_products(max_size);
14+
15+
inline void use(std::string_view name) {
16+
auto front = name.front();
17+
auto back = name.back();
18+
benchmark::DoNotOptimize(front);
19+
benchmark::DoNotOptimize(back);
20+
}
21+
22+
static void BM_all_eager(benchmark::State& state) {
23+
const auto size = state.range(0);
24+
const auto begin = global_products.begin();
25+
26+
eager::database db{.products = {begin, begin + size}};
27+
28+
for (auto _ : state) {
29+
for (std::string_view name : db.get_products({.min_quantity = 10})) {
30+
use(name);
31+
}
32+
}
33+
}
34+
35+
static void BM_all_fused(benchmark::State& state) {
36+
const auto size = state.range(0);
37+
const auto begin = global_products.begin();
38+
39+
fused::database db{.products = {begin, begin + size}};
40+
41+
for (auto _ : state) {
42+
for (std::string_view name : db.get_products({.min_quantity = 10})) {
43+
use(name);
44+
}
45+
}
46+
}
47+
48+
static void BM_all_lazy(benchmark::State& state) {
49+
const auto size = state.range(0);
50+
const auto begin = global_products.begin();
51+
52+
lazy::database db{.products = {begin, begin + size}};
53+
54+
for (auto _ : state) {
55+
for (std::string_view name : db.get_products({.min_quantity = 10})) {
56+
use(name);
57+
}
58+
}
59+
}
60+
61+
static void BM_all_reserved(benchmark::State& state) {
62+
const auto size = state.range(0);
63+
const auto begin = global_products.begin();
64+
65+
reserved::database db{.products = {begin, begin + size}};
66+
67+
for (auto _ : state) {
68+
for (std::string_view name : db.get_products({.min_quantity = 10})) {
69+
use(name);
70+
}
71+
}
72+
}
73+
74+
BENCHMARK(BM_all_eager)->RangeMultiplier(2)->Range(1 << 10, max_size);
75+
BENCHMARK(BM_all_fused)->RangeMultiplier(2)->Range(1 << 10, max_size);
76+
BENCHMARK(BM_all_lazy)->RangeMultiplier(2)->Range(1 << 10, max_size);
77+
BENCHMARK(BM_all_reserved)->RangeMultiplier(2)->Range(1 << 10, max_size);
78+
79+
BENCHMARK_MAIN();
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2+
3+
#include "eager.hpp"
4+
5+
auto eager::database::get_products(query_t query) const -> names_t {
6+
names_t results;
7+
8+
for (const auto& product : products) {
9+
if (product.quantity >= query.min_quantity) {
10+
results.emplace_back(product.name);
11+
}
12+
}
13+
14+
return results;
15+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2+
3+
#pragma once
4+
5+
#include "product.hpp"
6+
7+
#include <vector>
8+
9+
namespace eager {
10+
11+
using names_t = std::vector<std::string_view>;
12+
13+
struct database {
14+
std::vector<product_t> products;
15+
16+
auto get_products(query_t) const -> names_t;
17+
};
18+
19+
} // namespace eager
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2+
3+
#include "fused.hpp"
4+
5+
auto fused::database::get_products(query_t query) const -> names_t {
6+
return products | std::views::filter([=](const product_t& product) -> bool {
7+
return product.quantity >= query.min_quantity;
8+
}) |
9+
std::views::transform(&product_t::name);
10+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2+
3+
#pragma once
4+
5+
#include "product.hpp"
6+
7+
#include <beman/any_view/any_view.hpp>
8+
9+
#include <vector>
10+
11+
namespace fused {
12+
13+
using names_t = beman::any_view::any_view<const std::string, beman::any_view::any_view_options::forward>;
14+
15+
struct database {
16+
std::vector<product_t> products;
17+
18+
auto get_products(query_t) const -> names_t;
19+
};
20+
21+
} // namespace fused
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2+
3+
#include "lazy.hpp"
4+
5+
auto lazy::database::get_products(query_t query) const -> names_t {
6+
return products | std::views::filter([=](const product_t& product) -> bool {
7+
return product.quantity >= query.min_quantity;
8+
}) |
9+
std::views::transform(&product_t::name);
10+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2+
3+
#pragma once
4+
5+
#include "product.hpp"
6+
7+
#include <beman/any_view/any_view.hpp>
8+
9+
#include <vector>
10+
11+
namespace lazy {
12+
13+
using names_t = beman::any_view::any_view<const std::string>;
14+
15+
struct database {
16+
std::vector<product_t> products;
17+
18+
auto get_products(query_t) const -> names_t;
19+
};
20+
21+
} // namespace lazy
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2+
3+
#pragma once
4+
5+
#include <string>
6+
7+
struct product_t {
8+
std::string name;
9+
std::size_t quantity;
10+
};
11+
12+
struct query_t {
13+
std::size_t min_quantity;
14+
};

0 commit comments

Comments
 (0)