19 #include "gmock/gmock.h"
20 #include "gtest/gtest.h"
21 #include "absl/base/config.h"
22 #include "absl/strings/cord.h"
23 #include "absl/strings/internal/cord_internal.h"
26 #include "absl/strings/internal/cord_rep_flat.h"
27 #include "absl/strings/internal/cord_rep_ring.h"
28 #include "absl/strings/internal/cordz_info.h"
29 #include "absl/strings/internal/cordz_sample_token.h"
30 #include "absl/strings/internal/cordz_statistics.h"
31 #include "absl/strings/internal/cordz_update_scope.h"
32 #include "absl/strings/internal/cordz_update_tracker.h"
33 #include "absl/synchronization/internal/thread_pool.h"
34 #include "absl/synchronization/notification.h"
38 namespace cord_internal {
42 if (
s) *
s <<
"CordzStatistics{...}";
50 CordRepFlat* Flat(
size_t size) {
65 CordRepExternal* External(
int length = 512) {
66 return static_cast<CordRepExternal*
>(
71 CordRepSubstring* Substring(CordRep*
rep) {
72 auto* substring =
new CordRepSubstring;
75 substring->child =
rep;
81 std::vector<CordRep*>
refs;
91 T* NeedsUnref(
T*
rep) {
109 template <
typename T>
110 size_t SizeOf(
const T*
rep) {
115 size_t SizeOf(
const CordRepFlat*
rep) {
116 return rep->AllocatedSize();
120 size_t SizeOf(
const CordRepExternal*
rep) {
122 return sizeof(CordRepExternalImpl<intptr_t>) +
rep->
length;
126 size_t SizeOf(
const CordRepRing*
rep) {
131 double FairShareImpl(CordRep*
rep,
size_t ref) {
158 size_t FairShare(CordRep*
rep,
size_t ref = 1) {
159 return static_cast<size_t>(FairShareImpl(
rep,
ref));
163 CordzStatistics SampleCord(CordRep*
rep) {
164 InlineData cord(
rep);
166 CordzStatistics
stats = cord.cordz_info()->GetCordzStatistics();
167 cord.cordz_info()->Untrack();
171 MATCHER_P(EqStatistics,
stats,
"Statistics equal expected values") {
174 #define STATS_MATCHER_EXPECT_EQ(member) \
175 if (stats.member != arg.member) { \
176 *result_listener << "\n stats." << #member \
177 << ": actual = " << arg.member << ", expected " \
198 #undef STATS_MATCHER_EXPECT_EQ
203 TEST(CordzInfoStatisticsTest, Flat) {
205 auto* flat =
ref.NeedsUnref(Flat(512));
207 CordzStatistics expected;
208 expected.size = flat->length;
209 expected.estimated_memory_usage = SizeOf(flat);
210 expected.estimated_fair_share_memory_usage = expected.estimated_memory_usage;
211 expected.node_count = 1;
212 expected.node_counts.flat = 1;
213 expected.node_counts.flat_512 = 1;
215 EXPECT_THAT(SampleCord(flat), EqStatistics(expected));
218 TEST(CordzInfoStatisticsTest, SharedFlat) {
220 auto* flat =
ref.Ref(
ref.NeedsUnref(Flat(64)));
222 CordzStatistics expected;
223 expected.size = flat->length;
224 expected.estimated_memory_usage = SizeOf(flat);
225 expected.estimated_fair_share_memory_usage = SizeOf(flat) / 2;
226 expected.node_count = 1;
227 expected.node_counts.flat = 1;
228 expected.node_counts.flat_64 = 1;
230 EXPECT_THAT(SampleCord(flat), EqStatistics(expected));
233 TEST(CordzInfoStatisticsTest, External) {
235 auto* external =
ref.NeedsUnref(External());
237 CordzStatistics expected;
238 expected.size = external->length;
239 expected.estimated_memory_usage = SizeOf(external);
240 expected.estimated_fair_share_memory_usage = SizeOf(external);
241 expected.node_count = 1;
242 expected.node_counts.external = 1;
244 EXPECT_THAT(SampleCord(external), EqStatistics(expected));
247 TEST(CordzInfoStatisticsTest, SharedExternal) {
249 auto* external =
ref.Ref(
ref.NeedsUnref(External()));
251 CordzStatistics expected;
252 expected.size = external->length;
253 expected.estimated_memory_usage = SizeOf(external);
254 expected.estimated_fair_share_memory_usage = SizeOf(external) / 2;
255 expected.node_count = 1;
256 expected.node_counts.external = 1;
258 EXPECT_THAT(SampleCord(external), EqStatistics(expected));
261 TEST(CordzInfoStatisticsTest, Substring) {
263 auto* flat = Flat(1024);
264 auto* substring =
ref.NeedsUnref(Substring(flat));
266 CordzStatistics expected;
267 expected.size = substring->length;
268 expected.estimated_memory_usage = SizeOf(substring) + SizeOf(flat);
269 expected.estimated_fair_share_memory_usage = expected.estimated_memory_usage;
270 expected.node_count = 2;
271 expected.node_counts.flat = 1;
272 expected.node_counts.flat_1k = 1;
273 expected.node_counts.substring = 1;
275 EXPECT_THAT(SampleCord(substring), EqStatistics(expected));
278 TEST(CordzInfoStatisticsTest, SharedSubstring) {
280 auto* flat =
ref.Ref(Flat(511), 2);
281 auto* substring =
ref.Ref(
ref.NeedsUnref(Substring(flat)));
283 CordzStatistics expected;
284 expected.size = substring->length;
285 expected.estimated_memory_usage = SizeOf(flat) + SizeOf(substring);
286 expected.estimated_fair_share_memory_usage =
287 SizeOf(substring) / 2 + SizeOf(flat) / 6;
288 expected.node_count = 2;
289 expected.node_counts.flat = 1;
290 expected.node_counts.flat_512 = 1;
291 expected.node_counts.substring = 1;
293 EXPECT_THAT(SampleCord(substring), EqStatistics(expected));
297 TEST(CordzInfoStatisticsTest, Ring) {
299 auto* flat1 = Flat(240);
300 auto* flat2 = Flat(2000);
301 auto* flat3 = Flat(70);
302 auto* external = External(3000);
308 CordzStatistics expected;
309 expected.size = ring->length;
310 expected.estimated_memory_usage = SizeOf(ring) + SizeOf(flat1) +
311 SizeOf(flat2) + SizeOf(flat3) +
313 expected.estimated_fair_share_memory_usage = expected.estimated_memory_usage;
314 expected.node_count = 5;
315 expected.node_counts.flat = 3;
316 expected.node_counts.flat_128 = 1;
317 expected.node_counts.flat_256 = 1;
318 expected.node_counts.external = 1;
319 expected.node_counts.ring = 1;
321 EXPECT_THAT(SampleCord(ring), EqStatistics(expected));
324 TEST(CordzInfoStatisticsTest, SharedSubstringRing) {
326 auto* flat1 =
ref.Ref(Flat(240));
327 auto* flat2 = Flat(200);
328 auto* flat3 = Flat(70);
329 auto* external =
ref.Ref(External(3000), 5);
334 auto* substring =
ref.Ref(
ref.NeedsUnref(Substring(ring)));
337 CordzStatistics expected;
338 expected.size = substring->length;
339 expected.estimated_memory_usage = SizeOf(ring) + SizeOf(flat1) +
340 SizeOf(flat2) + SizeOf(flat3) +
341 SizeOf(external) + SizeOf(substring);
342 expected.estimated_fair_share_memory_usage = FairShare(substring);
343 expected.node_count = 6;
344 expected.node_counts.flat = 3;
345 expected.node_counts.flat_128 = 1;
346 expected.node_counts.flat_256 = 2;
347 expected.node_counts.external = 1;
348 expected.node_counts.ring = 1;
349 expected.node_counts.substring = 1;
351 EXPECT_THAT(SampleCord(substring), EqStatistics(expected));
354 TEST(CordzInfoStatisticsTest, BtreeLeaf) {
357 auto* flat1 = Flat(2000);
358 auto* flat2 = Flat(200);
359 auto* substr = Substring(flat2);
360 auto* external = External(3000);
366 size_t flat3_size = 0;
367 for (
size_t i = 0;
i < flat3_count; ++
i) {
368 auto* flat3 = Flat(70);
369 flat3_size += SizeOf(flat3);
372 ref.NeedsUnref(tree);
374 CordzStatistics expected;
375 expected.size = tree->length;
376 expected.estimated_memory_usage = SizeOf(tree) + SizeOf(flat1) +
377 SizeOf(flat2) + SizeOf(substr) +
378 flat3_size + SizeOf(external);
379 expected.estimated_fair_share_memory_usage = expected.estimated_memory_usage;
380 expected.node_count = 1 + 3 + 1 + flat3_count;
381 expected.node_counts.flat = 2 + flat3_count;
382 expected.node_counts.flat_128 = flat3_count;
383 expected.node_counts.flat_256 = 1;
384 expected.node_counts.external = 1;
385 expected.node_counts.substring = 1;
386 expected.node_counts.btree = 1;
388 EXPECT_THAT(SampleCord(tree), EqStatistics(expected));
391 TEST(CordzInfoStatisticsTest, BtreeNodeShared) {
393 static constexpr
int leaf_count = 3;
397 CordRepBtree* tree =
nullptr;
399 for (
int i = 0;
i < leaf_count; ++
i) {
400 auto* flat1 =
ref.Ref(Flat(2000), 9);
401 mem_size += SizeOf(flat1);
408 auto* flat2 = Flat(200);
409 auto* substr = Substring(flat2);
410 mem_size += SizeOf(flat2) + SizeOf(substr);
413 auto* external = External(30);
414 mem_size += SizeOf(external);
417 for (
size_t i = 0;
i < flat3_count; ++
i) {
418 auto* flat3 = Flat(70);
419 mem_size += SizeOf(flat3);
424 mem_size += SizeOf(tree);
426 mem_size += SizeOf(tree->Edges().back()->btree());
429 ref.NeedsUnref(tree);
433 ref.Ref(tree->Edges().front(), 4);
435 CordzStatistics expected;
436 expected.size = tree->length;
437 expected.estimated_memory_usage = SizeOf(tree) + mem_size;
438 expected.estimated_fair_share_memory_usage = FairShare(tree);
440 expected.node_count = 1 + leaf_count * (1 + 3 + 1 + flat3_count);
441 expected.node_counts.flat = leaf_count * (2 + flat3_count);
442 expected.node_counts.flat_128 = leaf_count * flat3_count;
443 expected.node_counts.flat_256 = leaf_count;
444 expected.node_counts.external = leaf_count;
445 expected.node_counts.substring = leaf_count;
446 expected.node_counts.btree = 1 + leaf_count;
448 EXPECT_THAT(SampleCord(tree), EqStatistics(expected));
451 TEST(CordzInfoStatisticsTest, Crc) {
453 auto* left = Flat(1000);
456 CordzStatistics expected;
457 expected.size = left->length;
458 expected.estimated_memory_usage = SizeOf(crc) + SizeOf(left);
459 expected.estimated_fair_share_memory_usage = expected.estimated_memory_usage;
460 expected.node_count = 2;
461 expected.node_counts.flat = 1;
462 expected.node_counts.flat_1k = 1;
463 expected.node_counts.crc = 1;
465 EXPECT_THAT(SampleCord(crc), EqStatistics(expected));
468 TEST(CordzInfoStatisticsTest, ThreadSafety) {
471 int64_t sampled_node_count = 0;
477 pool.Schedule([&]() {
478 while (!
stop.HasBeenNotified()) {
480 absl::SleepFor(absl::Microseconds(10));
481 CordzSampleToken token;
482 for (const CordzInfo& cord_info : token) {
483 CordzStatistics stats = cord_info.GetCordzStatistics();
484 sampled_node_count += stats.node_count;
491 pool.Schedule([&]() {
496 std::minstd_rand
gen;
497 std::uniform_int_distribution<int> coin_toss(0, 1);
499 while (!
stop.HasBeenNotified()) {
500 for (InlineData& cord : cords) {
502 if (coin_toss(
gen) != 0) {
503 if (cord.is_tree()) {
505 if (coin_toss(
gen) != 0) {
508 CordzUpdateScope scope(cord.cordz_info(),
510 scope.SetCordRep(
nullptr);
513 cord.set_inline_size(0);
516 CordRep*
rep = Flat(256);
517 if (coin_toss(
gen) != 0) {
518 if (coin_toss(
gen) != 0) {
527 if (coin_toss(
gen) != 0) {
534 for (InlineData& cord : cords) {
535 if (cord.is_tree()) {
549 std::cout <<
"Sampled " << sampled_node_count <<
" nodes\n";