xref: /aosp_15_r20/external/abseil-cpp/absl/log/internal/vlog_config_benchmark.cc (revision 9356374a3709195abf420251b3e825997ff56c0f)
1 // Copyright 2022 The Abseil Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include <algorithm>
16 #include <atomic>
17 #include <cstddef>
18 #include <cstring>
19 #include <memory>
20 #include <new>
21 #include <random>
22 #include <string>
23 #include <type_traits>
24 #include <utility>
25 #include <vector>
26 
27 #include "absl/base/config.h"
28 #include "absl/container/internal/layout.h"
29 #include "absl/log/internal/vlog_config.h"
30 #include "absl/memory/memory.h"
31 #include "absl/random/distributions.h"
32 #include "absl/strings/str_cat.h"
33 #include "benchmark/benchmark.h"
34 
35 namespace absl {
36 ABSL_NAMESPACE_BEGIN
37 namespace log_internal {
38 // Performance of `UpdateLogSites` depends upon the number and organization of
39 // `VLogSite`s in the program.  We can synthesize some on the heap to mimic
40 // their layout and linkage in static data.
41 class SyntheticBinary {
42  public:
SyntheticBinary(const size_t num_tus,const size_t max_extra_static_data_bytes_per_tu,const size_t max_sites_per_tu,const int num_shuffles)43   explicit SyntheticBinary(const size_t num_tus,
44                            const size_t max_extra_static_data_bytes_per_tu,
45                            const size_t max_sites_per_tu,
46                            const int num_shuffles) {
47     per_tu_data_.reserve(num_tus);
48     auto sites = absl::make_unique<VLogSite *[]>(num_tus * max_sites_per_tu);
49     for (size_t i = 0; i < num_tus; i++) {
50       const std::string filename =
51           absl::StrCat("directory-", i / 100, "/subdirectory-", i % 100 / 10,
52                        "/file-", i % 10, ".cc");
53       container_internal::Layout<char, VLogSite, char> layout(
54           filename.size() + 1,
55           absl::LogUniform<size_t>(bitgen_, 1, max_sites_per_tu),
56           absl::LogUniform<size_t>(bitgen_, 0,
57                                    max_extra_static_data_bytes_per_tu));
58       auto buf = absl::make_unique<char[]>(layout.AllocSize());
59       layout.PoisonPadding(buf.get());
60       memcpy(layout.Pointer<0>(buf.get()), filename.c_str(),
61              filename.size() + 1);
62       for (VLogSite &site : layout.Slice<1>(buf.get())) {
63         sites[num_sites_++] =
64             new (&site) VLogSite(layout.Pointer<0>(buf.get()));
65         // The last one is a dangling pointer but will be fixed below.
66         site.next_.store(&site + 1, std::memory_order_seq_cst);
67       }
68       num_extra_static_data_bytes_ += layout.Size<2>();
69       per_tu_data_.push_back(PerTU{layout, std::move(buf)});
70     }
71     // Now link the files together back-to-front into a circular list.
72     for (size_t i = 0; i < num_tus; i++) {
73       auto &tu = per_tu_data_[i];
74       auto &next_tu = per_tu_data_[(i + 1) % num_tus];
75       tu.layout.Slice<1>(tu.buf.get())
76           .back()
77           .next_.store(next_tu.layout.Pointer<1>(next_tu.buf.get()),
78                        std::memory_order_seq_cst);
79     }
80     // Now do some shufflin'.
81     auto new_sites = absl::make_unique<VLogSite *[]>(num_sites_);
82     for (int shuffle_num = 0; shuffle_num < num_shuffles; shuffle_num++) {
83       // Each shuffle cuts the ring into three pieces and rearranges them.
84       const size_t cut_a = absl::Uniform(bitgen_, size_t{0}, num_sites_);
85       const size_t cut_b = absl::Uniform(bitgen_, size_t{0}, num_sites_);
86       const size_t cut_c = absl::Uniform(bitgen_, size_t{0}, num_sites_);
87       if (cut_a == cut_b || cut_b == cut_c || cut_a == cut_c) continue;
88       // The same cuts, sorted:
89       const size_t cut_1 = std::min({cut_a, cut_b, cut_c});
90       const size_t cut_3 = std::max({cut_a, cut_b, cut_c});
91       const size_t cut_2 = cut_a ^ cut_b ^ cut_c ^ cut_1 ^ cut_3;
92       VLogSite *const tmp = sites[cut_1]->next_.load(std::memory_order_seq_cst);
93       sites[cut_1]->next_.store(
94           sites[cut_2]->next_.load(std::memory_order_seq_cst),
95           std::memory_order_seq_cst);
96       sites[cut_2]->next_.store(
97           sites[cut_3]->next_.load(std::memory_order_seq_cst),
98           std::memory_order_seq_cst);
99       sites[cut_3]->next_.store(tmp, std::memory_order_seq_cst);
100       memcpy(&new_sites[0], &sites[0], sizeof(VLogSite *) * (cut_1 + 1));
101       memcpy(&new_sites[cut_1 + 1], &sites[cut_2 + 1],
102              sizeof(VLogSite *) * (cut_3 - cut_2));
103       memcpy(&new_sites[cut_1 + 1 + cut_3 - cut_2], &sites[cut_1 + 1],
104              sizeof(VLogSite *) * (cut_2 - cut_1));
105       memcpy(&new_sites[cut_3 + 1], &sites[cut_3 + 1],
106              sizeof(VLogSite *) * (num_sites_ - cut_3 - 1));
107       sites.swap(new_sites);
108     }
109     const char *last_file = nullptr;
110     for (size_t i = 0; i < num_sites_; i++) {
111       if (sites[i]->file_ == last_file) continue;
112       last_file = sites[i]->file_;
113       num_new_files_++;
114     }
115     absl::log_internal::SetVModuleListHeadForTestOnly(sites[0]);
116     sites[num_tus - 1]->next_.store(nullptr, std::memory_order_seq_cst);
117   }
~SyntheticBinary()118   ~SyntheticBinary() {
119     static_assert(std::is_trivially_destructible<VLogSite>::value, "");
120     absl::log_internal::SetVModuleListHeadForTestOnly(nullptr);
121   }
122 
num_sites() const123   size_t num_sites() const { return num_sites_; }
num_new_files() const124   size_t num_new_files() const { return num_new_files_; }
num_extra_static_data_bytes() const125   size_t num_extra_static_data_bytes() const {
126     return num_extra_static_data_bytes_;
127   }
128 
129  private:
130   struct PerTU {
131     container_internal::Layout<char, VLogSite, char> layout;
132     std::unique_ptr<char[]> buf;
133   };
134 
135   std::mt19937 bitgen_;
136   std::vector<PerTU> per_tu_data_;
137   size_t num_sites_ = 0;
138   size_t num_new_files_ = 0;
139   size_t num_extra_static_data_bytes_ = 0;
140 };
141 
142 namespace {
BM_UpdateVModuleEmpty(benchmark::State & state)143 void BM_UpdateVModuleEmpty(benchmark::State& state) {
144   SyntheticBinary bin(static_cast<size_t>(state.range(0)), 10 * 1024 * 1024,
145                       256, state.range(1));
146   for (auto s : state) {
147     absl::log_internal::UpdateVModule("");
148   }
149   state.SetItemsProcessed(static_cast<int>(bin.num_new_files()));
150 }
151 BENCHMARK(BM_UpdateVModuleEmpty)
152     ->ArgPair(100, 200)
153     ->ArgPair(1000, 2000)
154     ->ArgPair(10000, 20000);
155 
BM_UpdateVModuleShort(benchmark::State & state)156 void BM_UpdateVModuleShort(benchmark::State& state) {
157   SyntheticBinary bin(static_cast<size_t>(state.range(0)), 10 * 1024 * 1024,
158                       256, state.range(1));
159   for (auto s : state) {
160     absl::log_internal::UpdateVModule("directory2/*=4");
161   }
162   state.SetItemsProcessed(static_cast<int>(bin.num_new_files()));
163 }
164 BENCHMARK(BM_UpdateVModuleShort)
165     ->ArgPair(100, 200)
166     ->ArgPair(1000, 2000)
167     ->ArgPair(10000, 20000);
168 
BM_UpdateVModuleLong(benchmark::State & state)169 void BM_UpdateVModuleLong(benchmark::State& state) {
170   SyntheticBinary bin(static_cast<size_t>(state.range(0)), 10 * 1024 * 1024,
171                       256, state.range(1));
172   for (auto s : state) {
173     absl::log_internal::UpdateVModule(
174         "d?r?c?o?y2/*=4,d?*r?*c?**o?*y1/*=2,d?*rc?**o?*y3/*=2,,"
175         "d?*r?*c?**o?*1/*=1,d?*r?**o?*y1/*=2,d?*r???***y1/*=7,"
176         "d?*r?**o?*y1/aaa=6");
177   }
178   state.SetItemsProcessed(static_cast<int>(bin.num_new_files()));
179 }
180 BENCHMARK(BM_UpdateVModuleLong)
181     ->ArgPair(100, 200)
182     ->ArgPair(1000, 2000)
183     ->ArgPair(10000, 20000);
184 }  // namespace
185 }  // namespace log_internal
186 ABSL_NAMESPACE_END
187 }  // namespace absl
188