cord_analysis.cc
Go to the documentation of this file.
1 // Copyright 2021 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 
16 
17 #include <cstddef>
18 #include <cstdint>
19 
20 #include "absl/base/attributes.h"
21 #include "absl/base/config.h"
22 #include "absl/container/inlined_vector.h"
24 #include "absl/strings/internal/cord_internal.h"
27 #include "absl/strings/internal/cord_rep_flat.h"
28 #include "absl/strings/internal/cord_rep_ring.h"
29 //
30 #include "absl/base/macros.h"
31 #include "absl/base/port.h"
32 #include "absl/functional/function_ref.h"
33 
34 namespace absl {
36 namespace cord_internal {
37 namespace {
38 
39 // Accounting mode for analyzing memory usage.
40 enum class Mode { kTotal, kFairShare };
41 
42 // CordRepRef holds a `const CordRep*` reference in rep, and depending on mode,
43 // holds a 'fraction' representing a cumulative inverse refcount weight.
44 template <Mode mode>
45 struct CordRepRef {
46  // Instantiates a CordRepRef instance.
47  explicit CordRepRef(const CordRep* r) : rep(r) {}
48 
49  // Creates a child reference holding the provided child.
50  // Overloaded to add cumulative reference count for kFairShare.
51  CordRepRef Child(const CordRep* child) const { return CordRepRef(child); }
52 
53  const CordRep* rep;
54 };
55 
56 // RawUsage holds the computed total number of bytes.
57 template <Mode mode>
58 struct RawUsage {
59  size_t total = 0;
60 
61  // Add 'size' to total, ignoring the CordRepRef argument.
62  void Add(size_t size, CordRepRef<mode>) { total += size; }
63 };
64 
65 // Returns n / refcount avoiding a div for the common refcount == 1.
66 template <typename refcount_t>
67 double MaybeDiv(double d, refcount_t refcount) {
68  return refcount == 1 ? d : d / refcount;
69 }
70 
71 // Overloaded 'kFairShare' specialization for CordRepRef. This class holds a
72 // `fraction` value which represents a cumulative inverse refcount weight.
73 // For example, a top node with a reference count of 2 will have a fraction
74 // value of 1/2 = 0.5, representing the 'fair share' of memory it references.
75 // A node below such a node with a reference count of 5 then has a fraction of
76 // 0.5 / 5 = 0.1 representing the fair share of memory below that node, etc.
77 template <>
78 struct CordRepRef<Mode::kFairShare> {
79  // Creates a CordRepRef with the provided rep and top (parent) fraction.
80  explicit CordRepRef(const CordRep* r, double frac = 1.0)
81  : rep(r), fraction(MaybeDiv(frac, r->refcount.Get())) {}
82 
83  // Returns a CordRepRef with a fraction of `this->fraction / child.refcount`
84  CordRepRef Child(const CordRep* child) const {
85  return CordRepRef(child, fraction);
86  }
87 
88  const CordRep* rep;
89  double fraction;
90 };
91 
92 // Overloaded 'kFairShare' specialization for RawUsage
93 template <>
94 struct RawUsage<Mode::kFairShare> {
95  double total = 0;
96 
97  // Adds `size` multiplied by `rep.fraction` to the total size.
98  void Add(size_t size, CordRepRef<Mode::kFairShare> rep) {
99  total += static_cast<double>(size) * rep.fraction;
100  }
101 };
102 
103 // Computes the estimated memory size of the provided data edge.
104 // External reps are assumed 'heap allocated at their exact size'.
105 template <Mode mode>
106 void AnalyzeDataEdge(CordRepRef<mode> rep, RawUsage<mode>& raw_usage) {
107  assert(IsDataEdge(rep.rep));
108 
109  // Consume all substrings
110  if (rep.rep->tag == SUBSTRING) {
111  raw_usage.Add(sizeof(CordRepSubstring), rep);
112  rep = rep.Child(rep.rep->substring()->child);
113  }
114 
115  // Consume FLAT / EXTERNAL
116  const size_t size =
117  rep.rep->tag >= FLAT
118  ? rep.rep->flat()->AllocatedSize()
119  : rep.rep->length + sizeof(CordRepExternalImpl<intptr_t>);
120  raw_usage.Add(size, rep);
121 }
122 
123 // Computes the memory size of the provided Ring tree.
124 template <Mode mode>
125 void AnalyzeRing(CordRepRef<mode> rep, RawUsage<mode>& raw_usage) {
126  const CordRepRing* ring = rep.rep->ring();
127  raw_usage.Add(CordRepRing::AllocSize(ring->capacity()), rep);
128  ring->ForEach([&](CordRepRing::index_type pos) {
129  AnalyzeDataEdge(rep.Child(ring->entry_child(pos)), raw_usage);
130  });
131 }
132 
133 // Computes the memory size of the provided Btree tree.
134 template <Mode mode>
135 void AnalyzeBtree(CordRepRef<mode> rep, RawUsage<mode>& raw_usage) {
136  raw_usage.Add(sizeof(CordRepBtree), rep);
137  const CordRepBtree* tree = rep.rep->btree();
138  if (tree->height() > 0) {
139  for (CordRep* edge : tree->Edges()) {
140  AnalyzeBtree(rep.Child(edge), raw_usage);
141  }
142  } else {
143  for (CordRep* edge : tree->Edges()) {
144  AnalyzeDataEdge(rep.Child(edge), raw_usage);
145  }
146  }
147 }
148 
149 template <Mode mode>
150 size_t GetEstimatedUsage(const CordRep* rep) {
151  // Zero initialized memory usage totals.
152  RawUsage<mode> raw_usage;
153 
154  // Capture top level node and refcount into a CordRepRef.
155  CordRepRef<mode> repref(rep);
156 
157  // Consume the top level CRC node if present.
158  if (repref.rep->tag == CRC) {
159  raw_usage.Add(sizeof(CordRepCrc), repref);
160  repref = repref.Child(repref.rep->crc()->child);
161  }
162 
163  if (IsDataEdge(repref.rep)) {
164  AnalyzeDataEdge(repref, raw_usage);
165  } else if (repref.rep->tag == BTREE) {
166  AnalyzeBtree(repref, raw_usage);
167  } else if (repref.rep->tag == RING) {
168  AnalyzeRing(repref, raw_usage);
169  } else {
170  assert(false);
171  }
172 
173  return static_cast<size_t>(raw_usage.total);
174 }
175 
176 } // namespace
177 
179  return GetEstimatedUsage<Mode::kTotal>(rep);
180 }
181 
183  return GetEstimatedUsage<Mode::kFairShare>(rep);
184 }
185 
186 } // namespace cord_internal
188 } // namespace absl
cord_data_edge.h
pos
int pos
Definition: libuv/docs/code/tty-gravity/main.c:11
total
size_t total
Definition: cord_analysis.cc:59
absl::cord_internal::CordRepRing::index_type
uint32_t index_type
Definition: abseil-cpp/absl/strings/internal/cord_rep_ring.h:81
google::protobuf::python::cdescriptor_pool::Add
static PyObject * Add(PyObject *self, PyObject *file_descriptor_proto)
Definition: bloaty/third_party/protobuf/python/google/protobuf/pyext/descriptor_pool.cc:621
ABSL_NAMESPACE_END
#define ABSL_NAMESPACE_END
Definition: third_party/abseil-cpp/absl/base/config.h:171
absl::cord_internal::CordRep
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:209
absl::CordMemoryAccounting::kFairShare
@ kFairShare
absl::synchronization_internal::Get
static GraphId Get(const IdMap &id, int num)
Definition: abseil-cpp/absl/synchronization/internal/graphcycles_test.cc:44
absl::cord_internal::CordRep::tag
uint8_t tag
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:232
absl::cord_internal::CordRep::ring
CordRepRing * ring()
Definition: abseil-cpp/absl/strings/internal/cord_rep_ring.h:572
refcount
size_t refcount
Definition: abseil-cpp/absl/strings/internal/cordz_info.cc:122
ABSL_NAMESPACE_BEGIN
#define ABSL_NAMESPACE_BEGIN
Definition: third_party/abseil-cpp/absl/base/config.h:170
absl::cord_internal::FLAT
@ FLAT
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:194
cord_analysis.h
cord_rep_btree.h
absl::cord_internal::CordRepFlat::AllocatedSize
size_t AllocatedSize() const
Definition: abseil-cpp/absl/strings/internal/cord_rep_flat.h:169
googletest-filter-unittest.child
child
Definition: bloaty/third_party/googletest/googletest/test/googletest-filter-unittest.py:62
absl::cord_internal::GetEstimatedFairShareMemoryUsage
size_t GetEstimatedFairShareMemoryUsage(const CordRep *rep)
Definition: cord_analysis.cc:182
absl::cord_internal::RING
@ RING
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:182
absl::cord_internal::CordRep::length
size_t length
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:228
absl::cord_internal::BTREE
@ BTREE
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:181
absl::cord_internal::CordRep::btree
CordRepBtree * btree()
Definition: cord_rep_btree.h:589
absl::cord_internal::CordRepRing::AllocSize
static constexpr size_t AllocSize(size_t capacity)
Definition: abseil-cpp/absl/strings/internal/cord_rep_ring.h:488
fix_build_deps.r
r
Definition: fix_build_deps.py:491
absl::cord_internal::SUBSTRING
@ SUBSTRING
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:179
absl::CordMemoryAccounting::kTotal
@ kTotal
rep
const CordRep * rep
Definition: cord_analysis.cc:53
absl::cord_internal::GetEstimatedMemoryUsage
size_t GetEstimatedMemoryUsage(const CordRep *rep)
Definition: cord_analysis.cc:178
absl::cord_internal::CordRepSubstring::child
CordRep * child
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:282
absl::cord_internal::CRC
@ CRC
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:180
absl::cord_internal::IsDataEdge
bool IsDataEdge(const CordRep *edge)
Definition: cord_data_edge.h:32
absl
Definition: abseil-cpp/absl/algorithm/algorithm.h:31
make_curve25519_tables.d
int d
Definition: make_curve25519_tables.py:53
size
voidpf void uLong size
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:136
absl::cord_internal::CordRep::substring
CordRepSubstring * substring()
Definition: abseil-cpp/absl/strings/internal/cord_internal.h:614
cord_rep_crc.h
absl::cord_internal::CordRep::flat
CordRepFlat * flat()
Definition: abseil-cpp/absl/strings/internal/cord_rep_flat.h:173


grpc
Author(s):
autogenerated on Fri May 16 2025 02:58:03