blob: 87d29afdd60153e4a8f5eb2c5a0b5ac38edfd59c [file] [log] [blame]
// Copyright (C) 2019 The Android Open Source Project
//
// 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.
#include <random>
#include <benchmark/benchmark.h>
#include "src/trace_processor/containers/bit_vector.h"
#include "src/trace_processor/containers/bit_vector_iterators.h"
namespace {
using perfetto::trace_processor::BitVector;
bool IsBenchmarkFunctionalOnly() {
return getenv("BENCHMARK_FUNCTIONAL_TEST_ONLY") != nullptr;
}
void BitVectorArgs(benchmark::internal::Benchmark* b) {
std::vector<int> set_percentages;
if (IsBenchmarkFunctionalOnly()) {
set_percentages = std::vector<int>{50};
} else {
set_percentages = std::vector<int>{0, 1, 5, 50, 95, 99, 100};
}
for (int percentage : set_percentages) {
b->Args({64, percentage});
if (!IsBenchmarkFunctionalOnly()) {
b->Args({512, percentage});
b->Args({8192, percentage});
b->Args({123456, percentage});
b->Args({1234567, percentage});
}
}
}
void UpdateSetBitsArgs(benchmark::internal::Benchmark* b) {
if (IsBenchmarkFunctionalOnly()) {
b->Args({64, 50, 50});
} else {
std::vector<int64_t> set_percentages{1, 5, 50, 95, 99};
b->ArgsProduct({{1234567}, set_percentages, set_percentages});
}
}
BitVector BvWithSizeAndSetPercentage(uint32_t size, uint32_t set_percentage) {
static constexpr uint32_t kRandomSeed = 29;
std::minstd_rand0 rnd_engine(kRandomSeed);
BitVector bv;
for (uint32_t i = 0; i < size; ++i) {
if (rnd_engine() % 100 < set_percentage) {
bv.AppendTrue();
} else {
bv.AppendFalse();
}
}
return bv;
}
} // namespace
static void BM_BitVectorAppendTrue(benchmark::State& state) {
BitVector bv;
for (auto _ : state) {
bv.AppendTrue();
benchmark::ClobberMemory();
}
}
BENCHMARK(BM_BitVectorAppendTrue);
static void BM_BitVectorAppendFalse(benchmark::State& state) {
BitVector bv;
for (auto _ : state) {
bv.AppendFalse();
benchmark::ClobberMemory();
}
}
BENCHMARK(BM_BitVectorAppendFalse);
static void BM_BitVectorSet(benchmark::State& state) {
static constexpr uint32_t kRandomSeed = 42;
std::minstd_rand0 rnd_engine(kRandomSeed);
uint32_t size = static_cast<uint32_t>(state.range(0));
uint32_t set_percentage = static_cast<uint32_t>(state.range(1));
BitVector bv = BvWithSizeAndSetPercentage(size, set_percentage);
static constexpr uint32_t kPoolSize = 1024 * 1024;
std::vector<bool> bit_pool(kPoolSize);
std::vector<uint32_t> row_pool(kPoolSize);
for (uint32_t i = 0; i < kPoolSize; ++i) {
bit_pool[i] = rnd_engine() % 2;
row_pool[i] = rnd_engine() % size;
}
uint32_t pool_idx = 0;
for (auto _ : state) {
bv.Set(row_pool[pool_idx]);
pool_idx = (pool_idx + 1) % kPoolSize;
benchmark::ClobberMemory();
}
}
BENCHMARK(BM_BitVectorSet)->Apply(BitVectorArgs);
static void BM_BitVectorClear(benchmark::State& state) {
static constexpr uint32_t kRandomSeed = 42;
std::minstd_rand0 rnd_engine(kRandomSeed);
uint32_t size = static_cast<uint32_t>(state.range(0));
uint32_t set_percentage = static_cast<uint32_t>(state.range(1));
BitVector bv = BvWithSizeAndSetPercentage(size, set_percentage);
static constexpr uint32_t kPoolSize = 1024 * 1024;
std::vector<uint32_t> row_pool(kPoolSize);
for (uint32_t i = 0; i < kPoolSize; ++i) {
row_pool[i] = rnd_engine() % size;
}
uint32_t pool_idx = 0;
for (auto _ : state) {
bv.Clear(row_pool[pool_idx]);
pool_idx = (pool_idx + 1) % kPoolSize;
benchmark::ClobberMemory();
}
}
BENCHMARK(BM_BitVectorClear)->Apply(BitVectorArgs);
static void BM_BitVectorIndexOfNthSet(benchmark::State& state) {
static constexpr uint32_t kRandomSeed = 42;
std::minstd_rand0 rnd_engine(kRandomSeed);
uint32_t size = static_cast<uint32_t>(state.range(0));
uint32_t set_percentage = static_cast<uint32_t>(state.range(1));
BitVector bv = BvWithSizeAndSetPercentage(size, set_percentage);
static constexpr uint32_t kPoolSize = 1024 * 1024;
std::vector<uint32_t> row_pool(kPoolSize);
uint32_t set_bit_count = bv.CountSetBits();
if (set_bit_count == 0) {
state.SkipWithError("Cannot find set bit in all zeros bitvector");
return;
}
for (uint32_t i = 0; i < kPoolSize; ++i) {
row_pool[i] = rnd_engine() % set_bit_count;
}
uint32_t pool_idx = 0;
for (auto _ : state) {
benchmark::DoNotOptimize(bv.IndexOfNthSet(row_pool[pool_idx]));
pool_idx = (pool_idx + 1) % kPoolSize;
}
}
BENCHMARK(BM_BitVectorIndexOfNthSet)->Apply(BitVectorArgs);
static void BM_BitVectorCountSetBits(benchmark::State& state) {
static constexpr uint32_t kRandomSeed = 42;
std::minstd_rand0 rnd_engine(kRandomSeed);
uint32_t size = static_cast<uint32_t>(state.range(0));
uint32_t set_percentage = static_cast<uint32_t>(state.range(1));
uint32_t count = 0;
BitVector bv;
for (uint32_t i = 0; i < size; ++i) {
bool value = rnd_engine() % 100 < set_percentage;
if (value) {
bv.AppendTrue();
} else {
bv.AppendFalse();
}
if (value)
count++;
}
uint32_t res = count;
for (auto _ : state) {
benchmark::DoNotOptimize(res &= bv.CountSetBits());
}
PERFETTO_CHECK(res == count);
}
BENCHMARK(BM_BitVectorCountSetBits)->Apply(BitVectorArgs);
static void BM_BitVectorResize(benchmark::State& state) {
static constexpr uint32_t kRandomSeed = 42;
std::minstd_rand0 rnd_engine(kRandomSeed);
static constexpr uint32_t kPoolSize = 1024 * 1024;
static constexpr uint32_t kMaxSize = 1234567;
std::vector<bool> resize_fill_pool(kPoolSize);
std::vector<uint32_t> resize_count_pool(kPoolSize);
for (uint32_t i = 0; i < kPoolSize; ++i) {
resize_fill_pool[i] = rnd_engine() % 2;
resize_count_pool[i] = rnd_engine() % kMaxSize;
}
uint32_t pool_idx = 0;
BitVector bv;
for (auto _ : state) {
bv.Resize(resize_count_pool[pool_idx], resize_fill_pool[pool_idx]);
pool_idx = (pool_idx + 1) % kPoolSize;
benchmark::ClobberMemory();
}
}
BENCHMARK(BM_BitVectorResize);
static void BM_BitVectorRangeFixedSize(benchmark::State& state) {
static constexpr uint32_t kRandomSeed = 42;
std::minstd_rand0 rnd_engine(kRandomSeed);
uint32_t size = static_cast<uint32_t>(state.range(0));
uint32_t set_percentage = static_cast<uint32_t>(state.range(1));
std::vector<uint32_t> resize_fill_pool(size);
for (uint32_t i = 0; i < size; ++i) {
resize_fill_pool[i] = rnd_engine() % 100 < set_percentage ? 90 : 100;
}
for (auto _ : state) {
auto filler = [&resize_fill_pool](uint32_t i) PERFETTO_ALWAYS_INLINE {
return resize_fill_pool[i] < 95;
};
BitVector bv = BitVector::Range(0, size, filler);
benchmark::ClobberMemory();
}
}
BENCHMARK(BM_BitVectorRangeFixedSize)->Apply(BitVectorArgs);
static void BM_BitVectorUpdateSetBits(benchmark::State& state) {
static constexpr uint32_t kRandomSeed = 42;
std::minstd_rand0 rnd_engine(kRandomSeed);
uint32_t size = static_cast<uint32_t>(state.range(0));
uint32_t set_percentage = static_cast<uint32_t>(state.range(1));
uint32_t picker_set_percentage = static_cast<uint32_t>(state.range(2));
BitVector bv;
BitVector picker;
for (uint32_t i = 0; i < size; ++i) {
bool value = rnd_engine() % 100 < set_percentage;
if (value) {
bv.AppendTrue();
bool picker_value = rnd_engine() % 100 < picker_set_percentage;
if (picker_value) {
picker.AppendTrue();
} else {
picker.AppendFalse();
}
} else {
bv.AppendFalse();
}
}
uint32_t set_bit_count = bv.CountSetBits();
uint32_t picker_set_bit_count = picker.CountSetBits();
for (auto _ : state) {
BitVector copy = bv.Copy();
copy.UpdateSetBits(picker);
benchmark::DoNotOptimize(copy);
}
state.counters["s/set bit"] = benchmark::Counter(
set_bit_count, benchmark::Counter::kIsIterationInvariantRate |
benchmark::Counter::kInvert);
state.counters["s/set picker bit"] = benchmark::Counter(
picker_set_bit_count, benchmark::Counter::kIsIterationInvariantRate |
benchmark::Counter::kInvert);
}
BENCHMARK(BM_BitVectorUpdateSetBits)->Apply(UpdateSetBitsArgs);
static void BM_BitVectorSetBitsIterator(benchmark::State& state) {
uint32_t size = static_cast<uint32_t>(state.range(0));
uint32_t set_percentage = static_cast<uint32_t>(state.range(1));
BitVector bv = BvWithSizeAndSetPercentage(size, set_percentage);
for (auto _ : state) {
for (auto it = bv.IterateSetBits(); it; it.Next()) {
benchmark::DoNotOptimize(it.index());
}
}
}
BENCHMARK(BM_BitVectorSetBitsIterator)->Apply(BitVectorArgs);