/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/***
* A benchmark comparing SparseByteSet to bitset<256> and bool[256].
*/
#include <folly/container/SparseByteSet.h>
#include <bitset>
#include <random>
#include <vector>
#include <fmt/core.h>
#include <folly/Benchmark.h>
#include <folly/Format.h>
#include <folly/portability/GFlags.h>
using namespace std;
using namespace folly;
namespace {
// Interface-identical to SparseByteSet. So that we can do compile-time
// polymorphism.
class BitSetWrapper {
public:
inline bool add(uint8_t i) {
auto r = !contains(i);
if (r) {
rep_[i] = true;
}
return r;
}
inline bool contains(uint8_t i) { return rep_[i]; }
private:
bitset<256> rep_;
};
class BoolArraySet {
public:
BoolArraySet() { memset(rep_, 0, sizeof(rep_)); }
inline bool add(uint8_t i) {
auto r = !contains(i);
if (r) {
rep_[i] = true;
}
return r;
}
inline bool contains(uint8_t i) { return rep_[i]; }
private:
bool rep_[256];
};
template <typename Coll>
void rand_bench(int iters, size_t size_add, size_t size_contains) {
BenchmarkSuspender braces;
vector<uint8_t> seq_add;
vector<uint8_t> seq_contains;
mt19937 rng;
uniform_int_distribution<uint8_t> dist;
for (size_t i = 0; i < size_add; ++i) {
seq_add.push_back(dist(rng));
}
for (size_t i = 0; i < size_contains; ++i) {
seq_contains.push_back(dist(rng));
}
braces.dismissing([&] {
while (iters--) {
Coll coll;
for (auto b : seq_add) {
coll.add(b);
}
bool q{};
for (auto b : seq_contains) {
q ^= coll.contains(b);
}
doNotOptimizeAway(q);
}
});
}
void setup_rand_bench() {
vector<pair<size_t, size_t>> rand_bench_params = {
{4, 4},
{4, 16},
{4, 64},
{4, 256},
{16, 4},
{16, 16},
{16, 64},
{16, 256},
{64, 4},
{64, 16},
{64, 64},
{64, 256},
{256, 4},
{256, 16},
{256, 64},
{256, 256},
};
for (auto kvp : rand_bench_params) {
size_t size_add, size_contains;
tie(size_add, size_contains) = kvp;
addBenchmark(
__FILE__,
fmt::format("bitset_rand_bench({}, {})", size_add, size_contains),
[=](int iters) {
rand_bench<BitSetWrapper>(iters, size_add, size_contains);
return iters;
});
addBenchmark(
__FILE__,
fmt::format(
"%bool_array_set_rand_bench({}, {})", size_add, size_contains),
[=](int iters) {
rand_bench<BoolArraySet>(iters, size_add, size_contains);
return iters;
});
addBenchmark(
__FILE__,
fmt::format(
"%sparse_byte_set_rand_bench({}, {})", size_add, size_contains),
[=](int iters) {
rand_bench<SparseByteSet>(iters, size_add, size_contains);
return iters;
});
addBenchmark(__FILE__, "-", [](int) { return 0; });
}
}
} // namespace
int main(int argc, char** argv) {
gflags::ParseCommandLineFlags(&argc, &argv, true);
setup_rand_bench();
runBenchmarks();
return 0;
}