vlog_config_benchmark.cc (7359B)
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: 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 } 118 ~SyntheticBinary() { 119 static_assert(std::is_trivially_destructible<VLogSite>::value, ""); 120 absl::log_internal::SetVModuleListHeadForTestOnly(nullptr); 121 } 122 123 size_t num_sites() const { return num_sites_; } 124 size_t num_new_files() const { return num_new_files_; } 125 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 { 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 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 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