range_map.h
Go to the documentation of this file.
1 // Copyright 2016 Google Inc. All Rights Reserved.
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 // http://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 // RagneMap maps
16 //
17 // [uint64_t, uint64_t) -> std::string, [optional other range base]
18 //
19 // where ranges must be non-overlapping.
20 //
21 // This is used to map the address space (either pointer offsets or file
22 // offsets).
23 //
24 // The other range base allows us to use this RangeMap to translate addresses
25 // from this domain to another one (like vm_addr -> file_addr or vice versa).
26 //
27 // This type is only exposed in the .h file for unit testing purposes.
28 
29 #ifndef BLOATY_RANGE_MAP_H_
30 #define BLOATY_RANGE_MAP_H_
31 
32 #include <assert.h>
33 #include <stdint.h>
34 
35 #include <exception>
36 #include <map>
37 #include <stdexcept>
38 #include <vector>
39 
40 #include "absl/strings/str_cat.h"
41 
42 namespace bloaty {
43 
44 class RangeMapTest;
45 
46 class RangeMap {
47  public:
48  RangeMap() = default;
49  RangeMap(RangeMap&& other) = default;
50  RangeMap& operator=(RangeMap&& other) = default;
51  RangeMap(RangeMap& other) = delete;
52  RangeMap& operator=(RangeMap& other) = delete;
53 
54  // Adds a range to this map.
55  void AddRange(uint64_t addr, uint64_t size, const std::string& val);
56 
57  // Adds a range to this map (in domain D1) that also corresponds to a
58  // different range in a different map (in domain D2). The correspondance will
59  // be noted to allow us to translate into the other domain later.
61  const std::string& val);
62 
63  // Adds a range to this map (in domain D1), and also adds corresponding ranges
64  // to |other| (in domain D2), using |translator| (in domain D1) to translate
65  // D1->D2. The translation is performed using information from previous
66  // AddDualRange() calls on |translator|.
67  //
68  // Returns true if the entire range [addr, size] was present in the
69  // |translator| map. (This does not necessarily mean that every part of the
70  // range was actually translated). If the return value is false, then the
71  // contents of |this| and |other| are undefined (Bloaty will bail in this
72  // case).
74  const std::string& val,
75  const RangeMap& translator, bool verbose,
76  RangeMap* other);
77 
78  // Collapses adjacent ranges with the same label. This reduces memory usage
79  // and removes redundant noise from the output when dumping a full memory map
80  // (in normal Bloaty output it makes no difference, because all labels with
81  // the same name are added together).
82  //
83  // TODO(haberman): see if we can do this at insertion time instead, so it
84  // doesn't require a second pass.
85  void Compress();
86 
87  // Returns whether this RangeMap fully covers the given range.
88  bool CoversRange(uint64_t addr, uint64_t size) const;
89 
90  // Returns the maximum address contained in this map.
91  uint64_t GetMaxAddress() const;
92 
93  // Translates |addr| into the other domain, returning |true| if this was
94  // successful.
95  bool Translate(uint64_t addr, uint64_t *translated) const;
96 
97  // Looks for a range within this map that contains |addr|. If found, returns
98  // true and sets |label| to the corresponding label, and |offset| to the
99  // offset from the beginning of this range.
100  bool TryGetLabel(uint64_t addr, std::string* label) const;
102  std::string* label) const;
103 
104  // Looks for a range that starts exactly on |addr|. If it exists, returns
105  // true and sets |size| to its size.
106  bool TryGetSize(uint64_t addr, uint64_t* size) const;
107 
108  std::string DebugString() const;
109 
111  uint64_t other_start,
112  const std::string& label) {
113  std::string end =
115  std::string ret = absl::StrCat("[", absl::Hex(addr), ", ", end,
116  "] (size=", absl::Hex(size), "): ", label);
117  if (other_start != UINT64_MAX) {
118  absl::StrAppend(&ret, ", other_start=", absl::Hex(other_start));
119  }
120  return ret;
121  }
122 
123  template <class T>
125  if (it == mappings_.end()) {
126  return "[end]";
127  } else {
128  return EntryDebugString(it->first, it->second.size,
129  it->second.other_start, it->second.label);
130  }
131  }
132 
133  template <class Func>
134  static void ComputeRollup(const std::vector<const RangeMap*>& range_maps,
135  Func func);
136 
137  template <class Func>
138  void ForEachRange(Func func) const {
139  for (auto iter = mappings_.begin(); iter != mappings_.end(); ++iter) {
140  func(iter->first, RangeEnd(iter) - iter->first);
141  }
142  }
143 
144  template <class Func>
146  for (auto iter = FindContaining(start); iter != mappings_.end(); ++iter) {
147  if (!func(iter->second.label, iter->first,
148  RangeEnd(iter) - iter->first)) {
149  return;
150  }
151  }
152  }
153 
154  static constexpr uint64_t kUnknownSize = UINT64_MAX;
155 
156  private:
157  friend class RangeMapTest;
159 
160  struct Entry {
161  Entry(const std::string& label_, uint64_t size_, uint64_t other_)
162  : label(label_), size(size_), other_start(other_) {}
165  uint64_t other_start; // kNoTranslation if there is no mapping.
166 
167  bool HasTranslation() const { return other_start != kNoTranslation; }
168  bool HasFallbackLabel() const { return !label.empty() && label[0] == '['; }
169 
170  // We assume that short regions that were unattributed (have fallback
171  // labels) are actually padding. We could probably make this heuristic
172  // a bit more robust.
173  bool IsShortFallback() const { return size <= 16 && HasFallbackLabel(); }
174  };
175 
176  typedef std::map<uint64_t, Entry> Map;
178 
179  template <class T>
180  void CheckConsistency(T iter) const {
181  assert(iter->first + iter->second.size > iter->first);
182  assert(iter == mappings_.begin() ||
183  RangeEnd(std::prev(iter)) <= iter->first);
184  assert(std::next(iter) == mappings_.end() ||
186  }
187 
188  template <class T>
190  return addr >= iter->first && addr < RangeEnd(iter);
191  }
192 
193  template <class T>
195  if (iter->second.size == kUnknownSize) {
196  return iter->first == addr;
197  } else {
198  return addr >= iter->first && addr < RangeEnd(iter);
199  }
200  }
201 
202  template <class T>
204  uint64_t end);
205 
206  // When the size is unknown return |unknown| for the end.
207  uint64_t RangeEndUnknownLimit(Map::const_iterator iter,
208  uint64_t unknown) const {
209  if (iter->second.size == kUnknownSize) {
210  Map::const_iterator next = std::next(iter);
211  if (IterIsEnd(next) || next->first > unknown) {
212  return unknown;
213  } else {
214  return next->first;
215  }
216  } else {
217  uint64_t ret = iter->first + iter->second.size;
218  assert(ret > iter->first);
219  return ret;
220  }
221  }
222 
223  uint64_t RangeEnd(Map::const_iterator iter) const {
225  }
226 
227  bool IterIsEnd(Map::const_iterator iter) const {
228  return iter == mappings_.end();
229  }
230 
231  template <class T>
233 
234  template <class T>
236  uint64_t* trimmed_addr,
237  uint64_t* translated_addr,
238  uint64_t* trimmed_size) const;
239 
240  // Finds the entry that contains |addr|. If no such mapping exists, returns
241  // mappings_.end().
242  Map::const_iterator FindContaining(uint64_t addr) const;
243 
244  // Finds the entry that contains |addr|, or the very next entry (which may be
245  // mappings_.end()).
247  Map::const_iterator FindContainingOrAfter(uint64_t addr) const;
248 };
249 
250 template <class Func>
251 void RangeMap::ComputeRollup(const std::vector<const RangeMap*>& range_maps,
252  Func func) {
253  assert(range_maps.size() > 0);
254  std::vector<Map::const_iterator> iters;
255 
256  if (range_maps[0]->mappings_.empty()) {
257  for (int i = 0; i < range_maps.size(); i++) {
258  const RangeMap* range_map = range_maps[i];
259  if (!range_map->mappings_.empty()) {
260  printf(
261  "Error, range (%s) exists at index %d, but base map is empty\n",
262  range_map->EntryDebugString(range_map->mappings_.begin()).c_str(),
263  i);
264  assert(false);
265  throw std::runtime_error("Range extends beyond base map.");
266  }
267  }
268  return;
269  }
270 
271  iters.reserve(range_maps.size());
272  for (auto range_map : range_maps) {
273  iters.push_back(range_map->mappings_.begin());
274  }
275 
276  // Iterate over all ranges in parallel to perform this transformation:
277  //
278  // ----- ----- ----- ---------------
279  // | | 1 A,X,1
280  // | X ----- ---------------
281  // | | | A,X,2
282  // A ----- | ---------------
283  // | | | |
284  // | | 2 -----> |
285  // | Y | A,Y,2
286  // | | | |
287  // ----- | | ---------------
288  // B | | B,Y,2
289  // ----- ----- ----- ---------------
290  //
291  //
292  // ----- ----- ----- ---------------
293  // C Z 3 C,Z,3
294  // ----- ----- ----- ---------------
295  //
296  // All input maps must cover exactly the same domain.
297 
298  // Outer loop: once per continuous (gapless) region.
299  while (true) {
300  std::vector<std::string> keys;
301  uint64_t current = 0;
302 
303  if (range_maps[0]->IterIsEnd(iters[0])) {
304  // Termination condition: all iterators must be at end.
305  for (int i = 0; i < range_maps.size(); i++) {
306  if (!range_maps[i]->IterIsEnd(iters[i])) {
307  printf(
308  "Error, range (%s) extends beyond final base map range "
309  "(%s)\n",
310  range_maps[i]->EntryDebugString(iters[i]).c_str(),
311  range_maps[0]->EntryDebugString(std::prev(iters[0])).c_str());
312  assert(false);
313  throw std::runtime_error("Range extends beyond base map.");
314  }
315  }
316  return;
317  } else {
318  // Starting a new continuous range: all iterators must start at the same
319  // place.
320  current = iters[0]->first;
321  for (int i = 0; i < range_maps.size(); i++) {
322  if (range_maps[i]->IterIsEnd(iters[i])) {
323  printf(
324  "Error, no more ranges for index %d but we need one "
325  "to match (%s)\n",
326  i, range_maps[0]->EntryDebugString(iters[0]).c_str());
327  assert(false);
328  throw std::runtime_error("No more ranges.");
329  } else if (iters[i]->first != current) {
330  printf(
331  "Error, range (%s) doesn't match the beginning of base range "
332  "(%s)\n",
333  range_maps[i]->EntryDebugString(iters[i]).c_str(),
334  range_maps[0]->EntryDebugString(iters[0]).c_str());
335  assert(false);
336  throw std::runtime_error("No more ranges.");
337  }
338  keys.push_back(iters[i]->second.label);
339  }
340  }
341 
342  bool continuous = true;
343 
344  // Inner loop: once per range within the continuous region.
345  while (continuous) {
346  uint64_t next_break = UINT64_MAX;
347 
348  for (int i = 0; i < iters.size(); i++) {
349  next_break = std::min(next_break, range_maps[i]->RangeEnd(iters[i]));
350  }
351 
352  func(keys, current, next_break);
353 
354  // Advance all iterators with ranges ending at next_break.
355  for (int i = 0; i < iters.size(); i++) {
356  const RangeMap& map = *range_maps[i];
357  Map::const_iterator& iter = iters[i];
358  uint64_t end = continuous ? map.RangeEnd(iter)
359  : map.RangeEndUnknownLimit(iter, next_break);
360 
361  if (end != next_break) {
362  continue;
363  }
364  ++iter;
365 
366  // Test for discontinuity.
367  if (map.IterIsEnd(iter) || iter->first != next_break) {
368  if (i > 0 && continuous) {
369  printf(
370  "Error, gap between ranges (%s) and (%s) fails to cover base "
371  "range (%s)\n",
372  map.EntryDebugString(std::prev(iter)).c_str(),
373  map.EntryDebugString(iter).c_str(),
374  range_maps[0]->EntryDebugString(iters[0]).c_str());
375  assert(false);
376  throw std::runtime_error("Entry range extends beyond base range");
377  }
378  assert(i == 0 || !continuous);
379  continuous = false;
380  } else {
381  assert(continuous);
382  keys[i] = iter->second.label;
383  }
384  }
385  current = next_break;
386  }
387  }
388 }
389 
390 } // namespace bloaty
391 
392 #endif // BLOATY_RANGE_MAP_H_
bloaty::RangeMap::EntryDebugString
static std::string EntryDebugString(uint64_t addr, uint64_t size, uint64_t other_start, const std::string &label)
Definition: range_map.h:110
bloaty::RangeMap::RangeEndUnknownLimit
uint64_t RangeEndUnknownLimit(Map::const_iterator iter, uint64_t unknown) const
Definition: range_map.h:207
bloaty
Definition: bloaty.cc:69
bloaty::RangeMap::TranslateAndTrimRangeWithEntry
bool TranslateAndTrimRangeWithEntry(T iter, uint64_t addr, uint64_t size, uint64_t *trimmed_addr, uint64_t *translated_addr, uint64_t *trimmed_size) const
Definition: range_map.cc:31
bloaty::RangeMap::IterIsEnd
bool IterIsEnd(Map::const_iterator iter) const
Definition: range_map.h:227
regen-readme.it
it
Definition: regen-readme.py:15
bloaty::RangeMap::GetMaxAddress
uint64_t GetMaxAddress() const
Definition: range_map.cc:323
absl::StrAppend
void StrAppend(std::string *dest, const AlphaNum &a)
Definition: abseil-cpp/absl/strings/str_cat.cc:193
Map
Definition: bloaty/third_party/protobuf/ruby/ext/google/protobuf_c/protobuf.h:451
absl::StrCat
std::string StrCat(const AlphaNum &a, const AlphaNum &b)
Definition: abseil-cpp/absl/strings/str_cat.cc:98
bloaty::RangeMap::kNoTranslation
static const uint64_t kNoTranslation
Definition: range_map.h:158
keys
const void * keys
Definition: abseil-cpp/absl/random/internal/randen.cc:49
bloaty::RangeMap::EntryContainsStrict
bool EntryContainsStrict(T iter, uint64_t addr) const
Definition: range_map.h:194
bloaty::RangeMap::FindContaining
Map::const_iterator FindContaining(uint64_t addr) const
Definition: range_map.cc:57
bloaty::RangeMap::MaybeSetLabel
void MaybeSetLabel(T iter, const std::string &label, uint64_t addr, uint64_t end)
Definition: range_map.cc:151
bloaty::RangeMap::kUnknownSize
static constexpr uint64_t kUnknownSize
Definition: range_map.h:154
bloaty::RangeMap::TryGetLabelForRange
bool TryGetLabelForRange(uint64_t addr, uint64_t size, std::string *label) const
Definition: range_map.cc:107
printf
_Use_decl_annotations_ int __cdecl printf(const char *_Format,...)
Definition: cs_driver.c:91
testing::internal::string
::std::string string
Definition: bloaty/third_party/protobuf/third_party/googletest/googletest/include/gtest/internal/gtest-port.h:881
UINT64_MAX
#define UINT64_MAX
Definition: stdint-msvc2008.h:143
bloaty::RangeMap::CoversRange
bool CoversRange(uint64_t addr, uint64_t size) const
Definition: range_map.cc:307
bloaty::RangeMap::AddRangeWithTranslation
bool AddRangeWithTranslation(uint64_t addr, uint64_t size, const std::string &val, const RangeMap &translator, bool verbose, RangeMap *other)
Definition: range_map.cc:253
bloaty::RangeMapTest
Definition: range_map_test.cc:24
bloaty::RangeMap::Entry::other_start
uint64_t other_start
Definition: range_map.h:165
bloaty::RangeMap::Entry::HasTranslation
bool HasTranslation() const
Definition: range_map.h:167
second
StrT second
Definition: cxa_demangle.cpp:4885
iterator
const typedef MCPhysReg * iterator
Definition: MCRegisterInfo.h:27
map
zval * map
Definition: php/ext/google/protobuf/encode_decode.c:480
bloaty::RangeMap::RangeEnd
uint64_t RangeEnd(Map::const_iterator iter) const
Definition: range_map.h:223
T
#define T(upbtypeconst, upbtype, ctype, default_value)
bloaty::RangeMap::Map
std::map< uint64_t, Entry > Map
Definition: range_map.h:176
bloaty::RangeMap
Definition: range_map.h:46
bloaty::RangeMap::DebugString
std::string DebugString() const
Definition: range_map.cc:138
absl::Hex
Definition: abseil-cpp/absl/strings/str_cat.h:134
bloaty::RangeMap::Entry::IsShortFallback
bool IsShortFallback() const
Definition: range_map.h:173
bloaty::RangeMap::AddDualRange
void AddDualRange(uint64_t addr, uint64_t size, uint64_t otheraddr, const std::string &val)
Definition: range_map.cc:181
start
static uint64_t start
Definition: benchmark-pound.c:74
bloaty::RangeMap::TranslateWithEntry
uint64_t TranslateWithEntry(T iter, uint64_t addr) const
Definition: range_map.cc:24
end
char * end
Definition: abseil-cpp/absl/strings/internal/str_format/float_conversion.cc:1008
gen_synthetic_protos.label
label
Definition: gen_synthetic_protos.py:102
gen_stats_data.c_str
def c_str(s, encoding='ascii')
Definition: gen_stats_data.py:38
absl::random_internal_nanobenchmark::Func
FuncOutput(*)(const void *, FuncInput) Func
Definition: abseil-cpp/absl/random/internal/nanobenchmark.h:68
bloaty::RangeMap::TryGetSize
bool TryGetSize(uint64_t addr, uint64_t *size) const
Definition: range_map.cc:128
bloaty::RangeMap::AddRange
void AddRange(uint64_t addr, uint64_t size, const std::string &val)
Definition: range_map.cc:146
bloaty::RangeMap::Compress
void Compress()
Definition: range_map.cc:291
bloaty::RangeMap::EntryContains
bool EntryContains(T iter, uint64_t addr) const
Definition: range_map.h:189
uint64_t
unsigned __int64 uint64_t
Definition: stdint-msvc2008.h:90
min
#define min(a, b)
Definition: qsort.h:83
bloaty::RangeMap::FindContainingOrAfter
Map::iterator FindContainingOrAfter(uint64_t addr)
Definition: range_map.cc:66
bloaty::RangeMap::CheckConsistency
void CheckConsistency(T iter) const
Definition: range_map.h:180
bloaty::RangeMap::Translate
bool Translate(uint64_t addr, uint64_t *translated) const
Definition: range_map.cc:87
stdint.h
bloaty::RangeMap::Entry::label
std::string label
Definition: range_map.h:163
verbose
bool verbose
Definition: bloaty/third_party/protobuf/conformance/conformance_cpp.cc:70
bloaty::RangeMap::Entry::HasFallbackLabel
bool HasFallbackLabel() const
Definition: range_map.h:168
bloaty::RangeMap::Entry::Entry
Entry(const std::string &label_, uint64_t size_, uint64_t other_)
Definition: range_map.h:161
bloaty::RangeMap::mappings_
Map mappings_
Definition: range_map.h:177
func
const EVP_CIPHER *(* func)(void)
Definition: cipher_extra.c:73
size_
size_t size_
Definition: memory_allocator.cc:56
bloaty::RangeMap::ForEachRange
void ForEachRange(Func func) const
Definition: range_map.h:138
bloaty::RangeMap::Entry::size
uint64_t size
Definition: range_map.h:164
ret
UniquePtr< SSL_SESSION > ret
Definition: ssl_x509.cc:1029
next
AllocList * next[kMaxLevel]
Definition: abseil-cpp/absl/base/internal/low_level_alloc.cc:100
bloaty::RangeMap::RangeMap
RangeMap()=default
first
StrT first
Definition: cxa_demangle.cpp:4884
bloaty::RangeMap::operator=
RangeMap & operator=(RangeMap &&other)=default
bloaty::RangeMap::Entry
Definition: range_map.h:160
iter
Definition: test_winkernel.cpp:47
bloaty::RangeMap::TryGetLabel
bool TryGetLabel(uint64_t addr, std::string *label) const
Definition: range_map.cc:97
size
voidpf void uLong size
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:136
addr
struct sockaddr_in addr
Definition: libuv/docs/code/tcp-echo-server/main.c:10
bloaty::RangeMap::ComputeRollup
static void ComputeRollup(const std::vector< const RangeMap * > &range_maps, Func func)
Definition: range_map.h:251
bloaty::RangeMap::EntryDebugString
std::string EntryDebugString(T it) const
Definition: range_map.h:124
i
uint64_t i
Definition: abseil-cpp/absl/container/btree_benchmark.cc:230
bloaty::RangeMap::ForEachRangeWithStart
void ForEachRangeWithStart(uint64_t start, Func func) const
Definition: range_map.h:145


grpc
Author(s):
autogenerated on Thu Mar 13 2025 03:00:59