summaryrefslogtreecommitdiffstats
path: root/lib/libcxx/benchmarks/string.bench.cpp
diff options
context:
space:
mode:
authorpatrick <patrick@openbsd.org>2021-01-11 15:31:56 +0000
committerpatrick <patrick@openbsd.org>2021-01-11 15:31:56 +0000
commit16ff81ed8b1ed9aa06fb1a731a2446b66cc49bef (patch)
tree1a7dd8152b94f6f8cd318bfaf85aa40882854583 /lib/libcxx/benchmarks/string.bench.cpp
parentsync (diff)
downloadwireguard-openbsd-16ff81ed8b1ed9aa06fb1a731a2446b66cc49bef.tar.xz
wireguard-openbsd-16ff81ed8b1ed9aa06fb1a731a2446b66cc49bef.zip
Remove libc++ and libc++abi 8.0.0 now that we switched to version 10.0.1
in the gnu/ directory.
Diffstat (limited to 'lib/libcxx/benchmarks/string.bench.cpp')
-rw-r--r--lib/libcxx/benchmarks/string.bench.cpp375
1 files changed, 0 insertions, 375 deletions
diff --git a/lib/libcxx/benchmarks/string.bench.cpp b/lib/libcxx/benchmarks/string.bench.cpp
deleted file mode 100644
index b8f97e6e2c1..00000000000
--- a/lib/libcxx/benchmarks/string.bench.cpp
+++ /dev/null
@@ -1,375 +0,0 @@
-
-#include <cstdint>
-#include <new>
-#include <vector>
-
-#include "CartesianBenchmarks.hpp"
-#include "GenerateInput.hpp"
-#include "benchmark/benchmark.h"
-#include "test_macros.h"
-
-constexpr std::size_t MAX_STRING_LEN = 8 << 14;
-
-// Benchmark when there is no match.
-static void BM_StringFindNoMatch(benchmark::State &state) {
- std::string s1(state.range(0), '-');
- std::string s2(8, '*');
- for (auto _ : state)
- benchmark::DoNotOptimize(s1.find(s2));
-}
-BENCHMARK(BM_StringFindNoMatch)->Range(10, MAX_STRING_LEN);
-
-// Benchmark when the string matches first time.
-static void BM_StringFindAllMatch(benchmark::State &state) {
- std::string s1(MAX_STRING_LEN, '-');
- std::string s2(state.range(0), '-');
- for (auto _ : state)
- benchmark::DoNotOptimize(s1.find(s2));
-}
-BENCHMARK(BM_StringFindAllMatch)->Range(1, MAX_STRING_LEN);
-
-// Benchmark when the string matches somewhere in the end.
-static void BM_StringFindMatch1(benchmark::State &state) {
- std::string s1(MAX_STRING_LEN / 2, '*');
- s1 += std::string(state.range(0), '-');
- std::string s2(state.range(0), '-');
- for (auto _ : state)
- benchmark::DoNotOptimize(s1.find(s2));
-}
-BENCHMARK(BM_StringFindMatch1)->Range(1, MAX_STRING_LEN / 4);
-
-// Benchmark when the string matches somewhere from middle to the end.
-static void BM_StringFindMatch2(benchmark::State &state) {
- std::string s1(MAX_STRING_LEN / 2, '*');
- s1 += std::string(state.range(0), '-');
- s1 += std::string(state.range(0), '*');
- std::string s2(state.range(0), '-');
- for (auto _ : state)
- benchmark::DoNotOptimize(s1.find(s2));
-}
-BENCHMARK(BM_StringFindMatch2)->Range(1, MAX_STRING_LEN / 4);
-
-static void BM_StringCtorDefault(benchmark::State &state) {
- for (auto _ : state) {
- std::string Default;
- benchmark::DoNotOptimize(Default);
- }
-}
-BENCHMARK(BM_StringCtorDefault);
-
-enum class Length { Empty, Small, Large, Huge };
-struct AllLengths : EnumValuesAsTuple<AllLengths, Length, 4> {
- static constexpr const char* Names[] = {"Empty", "Small", "Large", "Huge"};
-};
-
-enum class Opacity { Opaque, Transparent };
-struct AllOpacity : EnumValuesAsTuple<AllOpacity, Opacity, 2> {
- static constexpr const char* Names[] = {"Opaque", "Transparent"};
-};
-
-enum class DiffType { Control, ChangeFirst, ChangeMiddle, ChangeLast };
-struct AllDiffTypes : EnumValuesAsTuple<AllDiffTypes, DiffType, 4> {
- static constexpr const char* Names[] = {"Control", "ChangeFirst",
- "ChangeMiddle", "ChangeLast"};
-};
-
-TEST_ALWAYS_INLINE const char* getSmallString(DiffType D) {
- switch (D) {
- case DiffType::Control:
- return "0123456";
- case DiffType::ChangeFirst:
- return "-123456";
- case DiffType::ChangeMiddle:
- return "012-456";
- case DiffType::ChangeLast:
- return "012345-";
- }
-}
-
-TEST_ALWAYS_INLINE const char* getLargeString(DiffType D) {
-#define LARGE_STRING_FIRST "123456789012345678901234567890"
-#define LARGE_STRING_SECOND "234567890123456789012345678901"
- switch (D) {
- case DiffType::Control:
- return "0" LARGE_STRING_FIRST "1" LARGE_STRING_SECOND "2";
- case DiffType::ChangeFirst:
- return "-" LARGE_STRING_FIRST "1" LARGE_STRING_SECOND "2";
- case DiffType::ChangeMiddle:
- return "0" LARGE_STRING_FIRST "-" LARGE_STRING_SECOND "2";
- case DiffType::ChangeLast:
- return "0" LARGE_STRING_FIRST "1" LARGE_STRING_SECOND "-";
- }
-}
-
-TEST_ALWAYS_INLINE const char* getHugeString(DiffType D) {
-#define HUGE_STRING0 "0123456789"
-#define HUGE_STRING1 HUGE_STRING0 HUGE_STRING0 HUGE_STRING0 HUGE_STRING0
-#define HUGE_STRING2 HUGE_STRING1 HUGE_STRING1 HUGE_STRING1 HUGE_STRING1
-#define HUGE_STRING3 HUGE_STRING2 HUGE_STRING2 HUGE_STRING2 HUGE_STRING2
-#define HUGE_STRING4 HUGE_STRING3 HUGE_STRING3 HUGE_STRING3 HUGE_STRING3
- switch (D) {
- case DiffType::Control:
- return "0123456789" HUGE_STRING4 "0123456789" HUGE_STRING4 "0123456789";
- case DiffType::ChangeFirst:
- return "-123456789" HUGE_STRING4 "0123456789" HUGE_STRING4 "0123456789";
- case DiffType::ChangeMiddle:
- return "0123456789" HUGE_STRING4 "01234-6789" HUGE_STRING4 "0123456789";
- case DiffType::ChangeLast:
- return "0123456789" HUGE_STRING4 "0123456789" HUGE_STRING4 "012345678-";
- }
-}
-
-TEST_ALWAYS_INLINE std::string makeString(Length L,
- DiffType D = DiffType::Control,
- Opacity O = Opacity::Transparent) {
- switch (L) {
- case Length::Empty:
- return maybeOpaque("", O == Opacity::Opaque);
- case Length::Small:
- return maybeOpaque(getSmallString(D), O == Opacity::Opaque);
- case Length::Large:
- return maybeOpaque(getLargeString(D), O == Opacity::Opaque);
- case Length::Huge:
- return maybeOpaque(getHugeString(D), O == Opacity::Opaque);
- }
-}
-
-template <class Length, class Opaque>
-struct StringConstructDestroyCStr {
- static void run(benchmark::State& state) {
- for (auto _ : state) {
- benchmark::DoNotOptimize(
- makeString(Length(), DiffType::Control, Opaque()));
- }
- }
-
- static std::string name() {
- return "BM_StringConstructDestroyCStr" + Length::name() + Opaque::name();
- }
-};
-
-template <class Length, bool MeasureCopy, bool MeasureDestroy>
-static void StringCopyAndDestroy(benchmark::State& state) {
- static constexpr size_t NumStrings = 1024;
- auto Orig = makeString(Length());
- std::aligned_storage<sizeof(std::string)>::type Storage[NumStrings];
-
- while (state.KeepRunningBatch(NumStrings)) {
- if (!MeasureCopy)
- state.PauseTiming();
- for (size_t I = 0; I < NumStrings; ++I) {
- ::new (static_cast<void*>(Storage + I)) std::string(Orig);
- }
- if (!MeasureCopy)
- state.ResumeTiming();
- if (!MeasureDestroy)
- state.PauseTiming();
- for (size_t I = 0; I < NumStrings; ++I) {
- using S = std::string;
- reinterpret_cast<S*>(Storage + I)->~S();
- }
- if (!MeasureDestroy)
- state.ResumeTiming();
- }
-}
-
-template <class Length>
-struct StringCopy {
- static void run(benchmark::State& state) {
- StringCopyAndDestroy<Length, true, false>(state);
- }
-
- static std::string name() { return "BM_StringCopy" + Length::name(); }
-};
-
-template <class Length>
-struct StringDestroy {
- static void run(benchmark::State& state) {
- StringCopyAndDestroy<Length, false, true>(state);
- }
-
- static std::string name() { return "BM_StringDestroy" + Length::name(); }
-};
-
-template <class Length>
-struct StringMove {
- static void run(benchmark::State& state) {
- // Keep two object locations and move construct back and forth.
- std::aligned_storage<sizeof(std::string), alignof(std::string)>::type Storage[2];
- using S = std::string;
- size_t I = 0;
- S *newS = new (static_cast<void*>(Storage)) std::string(makeString(Length()));
- for (auto _ : state) {
- // Switch locations.
- I ^= 1;
- benchmark::DoNotOptimize(Storage);
- // Move construct into the new location,
- S *tmpS = new (static_cast<void*>(Storage + I)) S(std::move(*newS));
- // then destroy the old one.
- newS->~S();
- newS = tmpS;
- }
- newS->~S();
- }
-
- static std::string name() { return "BM_StringMove" + Length::name(); }
-};
-
-enum class Relation { Eq, Less, Compare };
-struct AllRelations : EnumValuesAsTuple<AllRelations, Relation, 3> {
- static constexpr const char* Names[] = {"Eq", "Less", "Compare"};
-};
-
-template <class Rel, class LHLength, class RHLength, class DiffType>
-struct StringRelational {
- static void run(benchmark::State& state) {
- auto Lhs = makeString(RHLength());
- auto Rhs = makeString(LHLength(), DiffType());
- for (auto _ : state) {
- benchmark::DoNotOptimize(Lhs);
- benchmark::DoNotOptimize(Rhs);
- switch (Rel()) {
- case Relation::Eq:
- benchmark::DoNotOptimize(Lhs == Rhs);
- break;
- case Relation::Less:
- benchmark::DoNotOptimize(Lhs < Rhs);
- break;
- case Relation::Compare:
- benchmark::DoNotOptimize(Lhs.compare(Rhs));
- break;
- }
- }
- }
-
- static bool skip() {
- // Eq is commutative, so skip half the matrix.
- if (Rel() == Relation::Eq && LHLength() > RHLength())
- return true;
- // We only care about control when the lengths differ.
- if (LHLength() != RHLength() && DiffType() != ::DiffType::Control)
- return true;
- // For empty, only control matters.
- if (LHLength() == Length::Empty && DiffType() != ::DiffType::Control)
- return true;
- return false;
- }
-
- static std::string name() {
- return "BM_StringRelational" + Rel::name() + LHLength::name() +
- RHLength::name() + DiffType::name();
- }
-};
-
-enum class Depth { Shallow, Deep };
-struct AllDepths : EnumValuesAsTuple<AllDepths, Depth, 2> {
- static constexpr const char* Names[] = {"Shallow", "Deep"};
-};
-
-enum class Temperature { Hot, Cold };
-struct AllTemperatures : EnumValuesAsTuple<AllTemperatures, Temperature, 2> {
- static constexpr const char* Names[] = {"Hot", "Cold"};
-};
-
-template <class Temperature, class Depth, class Length>
-struct StringRead {
- void run(benchmark::State& state) const {
- static constexpr size_t NumStrings =
- Temperature() == ::Temperature::Hot
- ? 1 << 10
- : /* Enough strings to overflow the cache */ 1 << 20;
- static_assert((NumStrings & (NumStrings - 1)) == 0,
- "NumStrings should be a power of two to reduce overhead.");
-
- std::vector<std::string> Values(NumStrings, makeString(Length()));
- size_t I = 0;
- for (auto _ : state) {
- // Jump long enough to defeat cache locality, and use a value that is
- // coprime with NumStrings to ensure we visit every element.
- I = (I + 17) % NumStrings;
- const auto& V = Values[I];
-
- // Read everything first. Escaping data() through DoNotOptimize might
- // cause the compiler to have to recalculate information about `V` due to
- // aliasing.
- const char* const Data = V.data();
- const size_t Size = V.size();
- benchmark::DoNotOptimize(Data);
- benchmark::DoNotOptimize(Size);
- if (Depth() == ::Depth::Deep) {
- // Read into the payload. This mainly shows the benefit of SSO when the
- // data is cold.
- benchmark::DoNotOptimize(*Data);
- }
- }
- }
-
- static bool skip() {
- // Huge does not give us anything that Large doesn't have. Skip it.
- if (Length() == ::Length::Huge) {
- return true;
- }
- return false;
- }
-
- std::string name() const {
- return "BM_StringRead" + Temperature::name() + Depth::name() +
- Length::name();
- }
-};
-
-void sanityCheckGeneratedStrings() {
- for (auto Lhs : {Length::Empty, Length::Small, Length::Large, Length::Huge}) {
- const auto LhsString = makeString(Lhs);
- for (auto Rhs :
- {Length::Empty, Length::Small, Length::Large, Length::Huge}) {
- if (Lhs > Rhs)
- continue;
- const auto RhsString = makeString(Rhs);
-
- // The smaller one must be a prefix of the larger one.
- if (RhsString.find(LhsString) != 0) {
- fprintf(stderr, "Invalid autogenerated strings for sizes (%d,%d).\n",
- static_cast<int>(Lhs), static_cast<int>(Rhs));
- std::abort();
- }
- }
- }
- // Verify the autogenerated diffs
- for (auto L : {Length::Small, Length::Large, Length::Huge}) {
- const auto Control = makeString(L);
- const auto Verify = [&](std::string Exp, size_t Pos) {
- // Only change on the Pos char.
- if (Control[Pos] != Exp[Pos]) {
- Exp[Pos] = Control[Pos];
- if (Control == Exp)
- return;
- }
- fprintf(stderr, "Invalid autogenerated diff with size %d\n",
- static_cast<int>(L));
- std::abort();
- };
- Verify(makeString(L, DiffType::ChangeFirst), 0);
- Verify(makeString(L, DiffType::ChangeMiddle), Control.size() / 2);
- Verify(makeString(L, DiffType::ChangeLast), Control.size() - 1);
- }
-}
-
-int main(int argc, char** argv) {
- benchmark::Initialize(&argc, argv);
- if (benchmark::ReportUnrecognizedArguments(argc, argv))
- return 1;
-
- sanityCheckGeneratedStrings();
-
- makeCartesianProductBenchmark<StringConstructDestroyCStr, AllLengths,
- AllOpacity>();
- makeCartesianProductBenchmark<StringCopy, AllLengths>();
- makeCartesianProductBenchmark<StringMove, AllLengths>();
- makeCartesianProductBenchmark<StringDestroy, AllLengths>();
- makeCartesianProductBenchmark<StringRelational, AllRelations, AllLengths,
- AllLengths, AllDiffTypes>();
- makeCartesianProductBenchmark<StringRead, AllTemperatures, AllDepths,
- AllLengths>();
- benchmark::RunSpecifiedBenchmarks();
-}