Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[vector.bool] Optimize copy / move algorithms #3353

Merged
merged 22 commits into from
Sep 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
f413538
[vector.bool] Optimize copy / move algorithms
miscco Jan 24, 2023
6616d06
Address review comments
miscco Jan 25, 2023
9a97135
Merge branch 'main' into vector_bool_copy
StephanTLavavej Apr 4, 2023
e874ecb
Drop `(void)`, as `_VbFirst` and `_VbDest` are `_Vbase*`.
StephanTLavavej Apr 4, 2023
249762d
Use `_Count` when calling `_Copy_vbool`.
StephanTLavavej Apr 4, 2023
a8842f7
Drop `inline` for `createRandomVector`.
StephanTLavavej Apr 4, 2023
2268a08
Merge branch 'main' into vector_bool_copy
StephanTLavavej May 15, 2023
8e3915c
Add `const` to `_VbFirst`, `_VbLast`, `_VbFirst_ch`, `_VbLast_ch`.
StephanTLavavej May 15, 2023
5bd00eb
Merge branch 'main' into vector_bool_copy
StephanTLavavej Sep 8, 2023
443ed7c
Fix bug: Disallow const_iterator as an output iterator.
StephanTLavavej Sep 9, 2023
391a630
Sort benchmarks.
StephanTLavavej Sep 9, 2023
5867980
Typo: missaligned => misaligned
StephanTLavavej Sep 9, 2023
dc311d0
`<functional>` is unused.
StephanTLavavej Sep 9, 2023
76b7d38
`rd` is unused.
StephanTLavavej Sep 9, 2023
2f99e37
Extract the size in the copy and move tests.
StephanTLavavej Sep 9, 2023
3102c7d
Add extra braces to create scopes for sub-tests.
StephanTLavavej Sep 9, 2023
8b21094
Mark result vectors as const.
StephanTLavavej Sep 9, 2023
46ee43f
Randomized test coverage found a bug.
StephanTLavavej Sep 11, 2023
5c3ec6d
Fix bugs with corner cases of the implementation
miscco Sep 12, 2023
7fe4f93
clang-format.
StephanTLavavej Sep 12, 2023
5447cae
`_Vbase` isn't vulnerable to integral promotions so we don't need to …
StephanTLavavej Sep 12, 2023
74270e7
Drop unnecessary parens.
StephanTLavavej Sep 12, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions benchmarks/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -110,3 +110,7 @@ add_benchmark(locale_classic src/locale_classic.cpp)
add_benchmark(path_lexically_normal src/path_lexically_normal.cpp)
add_benchmark(random_integer_generation src/random_integer_generation.cpp)
add_benchmark(std_copy src/std_copy.cpp)

add_benchmark(vector_bool_copy src/std/containers/sequences/vector.bool/copy/test.cpp)
add_benchmark(vector_bool_copy_n src/std/containers/sequences/vector.bool/copy_n/test.cpp)
add_benchmark(vector_bool_move src/std/containers/sequences/vector.bool/move/test.cpp)
100 changes: 100 additions & 0 deletions benchmarks/src/std/containers/sequences/vector.bool/copy/test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#include <benchmark/benchmark.h>
//
#include <algorithm>
#include <random>
#include <vector>

using namespace std;

static vector<bool> createRandomVector(const size_t size) {
static mt19937 gen{random_device{}()};
vector<bool> result(size);
generate_n(result.begin(), size, [] { return bernoulli_distribution{0.5}(gen); });
return result;
}

static void copy_block_aligned(benchmark::State& state) {
const auto size = state.range(0);
const vector<bool> source = createRandomVector(size);
vector<bool> dest(size, false);

for (auto _ : state) {
copy(source.cbegin(), source.cend(), dest.begin());
}
}

static void copy_source_misaligned(benchmark::State& state) {
const auto size = state.range(0);
const vector<bool> source = createRandomVector(size);
vector<bool> dest(size, false);

for (auto _ : state) {
copy(source.cbegin() + 1, source.cend(), dest.begin());
}
}

static void copy_dest_misaligned(benchmark::State& state) {
const auto size = state.range(0);
const vector<bool> source = createRandomVector(size);
vector<bool> dest(size, false);

for (auto _ : state) {
copy(source.cbegin(), source.cend() - 1, dest.begin() + 1);
}
}

// Special benchmark for matching char alignment
static void copy_matching_alignment(benchmark::State& state) {
const auto size = state.range(0);
const vector<bool> source = createRandomVector(size);
vector<bool> dest(size, false);

for (auto _ : state) {
copy(source.cbegin() + 5, source.cend(), dest.begin() + 5);
}
}

// Special benchmarks for single block corner case
static void copy_both_single_blocks(benchmark::State& state) {
const vector<bool> source = createRandomVector(50);
vector<bool> dest(50, false);

const size_t length = 20;
for (auto _ : state) {
copy(source.cbegin() + 5, source.cbegin() + 5 + length, dest.begin() + 5);
}
}

static void copy_source_single_block(benchmark::State& state) {
const vector<bool> source = createRandomVector(50);
vector<bool> dest(50, false);

const size_t length = 20;
for (auto _ : state) {
copy(source.cbegin() + 5, source.cbegin() + 5 + length, dest.begin() + 25);
}
}

static void copy_dest_single_block(benchmark::State& state) {
const vector<bool> source = createRandomVector(50);
vector<bool> dest(50, false);

const size_t length = 20;
for (auto _ : state) {
copy(source.cbegin() + 25, source.cbegin() + 25 + length, dest.begin() + 5);
}
}

BENCHMARK(copy_block_aligned)->RangeMultiplier(64)->Range(64, 64 << 10);
BENCHMARK(copy_source_misaligned)->RangeMultiplier(64)->Range(64, 64 << 10);
BENCHMARK(copy_dest_misaligned)->RangeMultiplier(64)->Range(64, 64 << 10);
BENCHMARK(copy_matching_alignment)->RangeMultiplier(64)->Range(64, 64 << 10);

BENCHMARK(copy_both_single_blocks);
BENCHMARK(copy_source_single_block);
BENCHMARK(copy_dest_single_block);

BENCHMARK_MAIN();
100 changes: 100 additions & 0 deletions benchmarks/src/std/containers/sequences/vector.bool/copy_n/test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#include <benchmark/benchmark.h>
//
#include <algorithm>
#include <random>
#include <vector>

using namespace std;

static vector<bool> createRandomVector(const size_t size) {
static mt19937 gen{random_device{}()};
vector<bool> result(size);
generate_n(result.begin(), size, [] { return bernoulli_distribution{0.5}(gen); });
return result;
}

static void copy_n_block_aligned(benchmark::State& state) {
const auto size = state.range(0);
const vector<bool> source = createRandomVector(size);
vector<bool> dest(size, false);

for (auto _ : state) {
copy_n(source.cbegin(), size, dest.begin());
}
}

static void copy_n_source_misaligned(benchmark::State& state) {
const auto size = state.range(0);
const vector<bool> source = createRandomVector(size);
vector<bool> dest(size, false);

for (auto _ : state) {
copy_n(source.cbegin() + 1, size - 1, dest.begin());
}
}

static void copy_n_dest_misaligned(benchmark::State& state) {
const auto size = state.range(0);
const vector<bool> source = createRandomVector(size);
vector<bool> dest(size, false);

for (auto _ : state) {
copy_n(source.cbegin(), size - 1, dest.begin() + 1);
}
}

// Special benchmark for matching char alignment
static void copy_n_matching_alignment(benchmark::State& state) {
const auto size = state.range(0);
const vector<bool> source = createRandomVector(size);
vector<bool> dest(size, false);

for (auto _ : state) {
copy_n(source.cbegin() + 5, size - 5, dest.begin() + 5);
}
}

// Special benchmarks for single block corner case
static void copy_n_both_single_blocks(benchmark::State& state) {
const vector<bool> source = createRandomVector(50);
vector<bool> dest(50, false);

const size_t length = 20;
for (auto _ : state) {
copy_n(source.cbegin() + 5, length, dest.begin() + 5);
}
}

static void copy_n_source_single_block(benchmark::State& state) {
const vector<bool> source = createRandomVector(50);
vector<bool> dest(50, false);

const size_t length = 20;
for (auto _ : state) {
copy_n(source.cbegin() + 5, length, dest.begin() + 25);
}
}

static void copy_n_dest_single_block(benchmark::State& state) {
const vector<bool> source = createRandomVector(50);
vector<bool> dest(50, false);

const size_t length = 20;
for (auto _ : state) {
copy_n(source.cbegin() + 25, length, dest.begin() + 5);
}
}

BENCHMARK(copy_n_block_aligned)->RangeMultiplier(64)->Range(64, 64 << 10);
BENCHMARK(copy_n_source_misaligned)->RangeMultiplier(64)->Range(64, 64 << 10);
BENCHMARK(copy_n_dest_misaligned)->RangeMultiplier(64)->Range(64, 64 << 10);
BENCHMARK(copy_n_matching_alignment)->RangeMultiplier(64)->Range(64, 64 << 10);

BENCHMARK(copy_n_both_single_blocks);
BENCHMARK(copy_n_source_single_block);
BENCHMARK(copy_n_dest_single_block);

BENCHMARK_MAIN();
100 changes: 100 additions & 0 deletions benchmarks/src/std/containers/sequences/vector.bool/move/test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#include <benchmark/benchmark.h>
//
#include <algorithm>
#include <random>
#include <vector>

using namespace std;

static vector<bool> createRandomVector(const size_t size) {
static mt19937 gen{random_device{}()};
vector<bool> result(size);
generate_n(result.begin(), size, [] { return bernoulli_distribution{0.5}(gen); });
return result;
}

static void move_block_aligned(benchmark::State& state) {
const auto size = state.range(0);
const vector<bool> source = createRandomVector(size);
vector<bool> dest(size, false);

for (auto _ : state) {
move(source.cbegin(), source.cend(), dest.begin());
}
}

static void move_source_misaligned(benchmark::State& state) {
const auto size = state.range(0);
const vector<bool> source = createRandomVector(size);
vector<bool> dest(size, false);

for (auto _ : state) {
move(source.cbegin() + 1, source.cend(), dest.begin());
}
}

static void move_dest_misaligned(benchmark::State& state) {
const auto size = state.range(0);
const vector<bool> source = createRandomVector(size);
vector<bool> dest(size, false);

for (auto _ : state) {
move(source.cbegin(), source.cend() - 1, dest.begin() + 1);
}
}

// Special benchmark for matching char alignment
static void move_matching_alignment(benchmark::State& state) {
const auto size = state.range(0);
const vector<bool> source = createRandomVector(size);
vector<bool> dest(size, false);

for (auto _ : state) {
move(source.cbegin() + 5, source.cend(), dest.begin() + 5);
}
}

// Special benchmarks for single block corner case
static void move_both_single_blocks(benchmark::State& state) {
const vector<bool> source = createRandomVector(50);
vector<bool> dest(50, false);

const size_t length = 20;
for (auto _ : state) {
move(source.cbegin() + 5, source.cbegin() + 5 + length, dest.begin() + 5);
}
}

static void move_source_single_block(benchmark::State& state) {
const vector<bool> source = createRandomVector(50);
vector<bool> dest(50, false);

const size_t length = 20;
for (auto _ : state) {
move(source.cbegin() + 5, source.cbegin() + 5 + length, dest.begin() + 25);
}
}

static void move_dest_single_block(benchmark::State& state) {
const vector<bool> source = createRandomVector(50);
vector<bool> dest(50, false);

const size_t length = 20;
for (auto _ : state) {
move(source.cbegin() + 25, source.cbegin() + 25 + length, dest.begin() + 5);
}
}

BENCHMARK(move_block_aligned)->RangeMultiplier(64)->Range(64, 64 << 10);
BENCHMARK(move_source_misaligned)->RangeMultiplier(64)->Range(64, 64 << 10);
BENCHMARK(move_dest_misaligned)->RangeMultiplier(64)->Range(64, 64 << 10);
BENCHMARK(move_matching_alignment)->RangeMultiplier(64)->Range(64, 64 << 10);

BENCHMARK(move_both_single_blocks);
BENCHMARK(move_source_single_block);
BENCHMARK(move_dest_single_block);

BENCHMARK_MAIN();
Loading