abseil-cpp/absl/synchronization/internal/graphcycles.cc
Go to the documentation of this file.
1 // Copyright 2017 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 // GraphCycles provides incremental cycle detection on a dynamic
16 // graph using the following algorithm:
17 //
18 // A dynamic topological sort algorithm for directed acyclic graphs
19 // David J. Pearce, Paul H. J. Kelly
20 // Journal of Experimental Algorithmics (JEA) JEA Homepage archive
21 // Volume 11, 2006, Article No. 1.7
22 //
23 // Brief summary of the algorithm:
24 //
25 // (1) Maintain a rank for each node that is consistent
26 // with the topological sort of the graph. I.e., path from x to y
27 // implies rank[x] < rank[y].
28 // (2) When a new edge (x->y) is inserted, do nothing if rank[x] < rank[y].
29 // (3) Otherwise: adjust ranks in the neighborhood of x and y.
30 
31 #include "absl/base/attributes.h"
32 // This file is a no-op if the required LowLevelAlloc support is missing.
33 #include "absl/base/internal/low_level_alloc.h"
34 #ifndef ABSL_LOW_LEVEL_ALLOC_MISSING
35 
36 #include "absl/synchronization/internal/graphcycles.h"
37 
38 #include <algorithm>
39 #include <array>
40 #include <limits>
41 #include "absl/base/internal/hide_ptr.h"
42 #include "absl/base/internal/raw_logging.h"
43 #include "absl/base/internal/spinlock.h"
44 
45 // Do not use STL. This module does not use standard memory allocation.
46 
47 namespace absl {
49 namespace synchronization_internal {
50 
51 namespace {
52 
53 // Avoid LowLevelAlloc's default arena since it calls malloc hooks in
54 // which people are doing things like acquiring Mutexes.
58 
59 static void InitArenaIfNecessary() {
60  arena_mu.Lock();
61  if (arena == nullptr) {
63  }
64  arena_mu.Unlock();
65 }
66 
67 // Number of inlined elements in Vec. Hash table implementation
68 // relies on this being a power of two.
69 static const uint32_t kInline = 8;
70 
71 // A simple LowLevelAlloc based resizable vector with inlined storage
72 // for a few elements. T must be a plain type since constructor
73 // and destructor are not run on elements of type T managed by Vec.
74 template <typename T>
75 class Vec {
76  public:
77  Vec() { Init(); }
78  ~Vec() { Discard(); }
79 
80  void clear() {
81  Discard();
82  Init();
83  }
84 
85  bool empty() const { return size_ == 0; }
86  uint32_t size() const { return size_; }
87  T* begin() { return ptr_; }
88  T* end() { return ptr_ + size_; }
89  const T& operator[](uint32_t i) const { return ptr_[i]; }
90  T& operator[](uint32_t i) { return ptr_[i]; }
91  const T& back() const { return ptr_[size_-1]; }
92  void pop_back() { size_--; }
93 
94  void push_back(const T& v) {
95  if (size_ == capacity_) Grow(size_ + 1);
96  ptr_[size_] = v;
97  size_++;
98  }
99 
100  void resize(uint32_t n) {
101  if (n > capacity_) Grow(n);
102  size_ = n;
103  }
104 
105  void fill(const T& val) {
106  for (uint32_t i = 0; i < size(); i++) {
107  ptr_[i] = val;
108  }
109  }
110 
111  // Guarantees src is empty at end.
112  // Provided for the hash table resizing code below.
113  void MoveFrom(Vec<T>* src) {
114  if (src->ptr_ == src->space_) {
115  // Need to actually copy
116  resize(src->size_);
117  std::copy(src->ptr_, src->ptr_ + src->size_, ptr_);
118  src->size_ = 0;
119  } else {
120  Discard();
121  ptr_ = src->ptr_;
122  size_ = src->size_;
123  capacity_ = src->capacity_;
124  src->Init();
125  }
126  }
127 
128  private:
129  T* ptr_;
130  T space_[kInline];
133 
134  void Init() {
135  ptr_ = space_;
136  size_ = 0;
137  capacity_ = kInline;
138  }
139 
140  void Discard() {
142  }
143 
144  void Grow(uint32_t n) {
145  while (capacity_ < n) {
146  capacity_ *= 2;
147  }
148  size_t request = static_cast<size_t>(capacity_) * sizeof(T);
149  T* copy = static_cast<T*>(
152  Discard();
153  ptr_ = copy;
154  }
155 
156  Vec(const Vec&) = delete;
157  Vec& operator=(const Vec&) = delete;
158 };
159 
160 // A hash set of non-negative int32_t that uses Vec for its underlying storage.
161 class NodeSet {
162  public:
163  NodeSet() { Init(); }
164 
165  void clear() { Init(); }
166  bool contains(int32_t v) const { return table_[FindIndex(v)] == v; }
167 
168  bool insert(int32_t v) {
169  uint32_t i = FindIndex(v);
170  if (table_[i] == v) {
171  return false;
172  }
173  if (table_[i] == kEmpty) {
174  // Only inserting over an empty cell increases the number of occupied
175  // slots.
176  occupied_++;
177  }
178  table_[i] = v;
179  // Double when 75% full.
180  if (occupied_ >= table_.size() - table_.size()/4) Grow();
181  return true;
182  }
183 
184  void erase(uint32_t v) {
185  uint32_t i = FindIndex(v);
186  if (static_cast<uint32_t>(table_[i]) == v) {
187  table_[i] = kDel;
188  }
189  }
190 
191  // Iteration: is done via HASH_FOR_EACH
192  // Example:
193  // HASH_FOR_EACH(elem, node->out) { ... }
194 #define HASH_FOR_EACH(elem, eset) \
195  for (int32_t elem, _cursor = 0; (eset).Next(&_cursor, &elem); )
196  bool Next(int32_t* cursor, int32_t* elem) {
197  while (static_cast<uint32_t>(*cursor) < table_.size()) {
198  int32_t v = table_[*cursor];
199  (*cursor)++;
200  if (v >= 0) {
201  *elem = v;
202  return true;
203  }
204  }
205  return false;
206  }
207 
208  private:
209  enum : int32_t { kEmpty = -1, kDel = -2 };
210  Vec<int32_t> table_;
211  uint32_t occupied_; // Count of non-empty slots (includes deleted slots)
212 
213  static uint32_t Hash(uint32_t a) { return a * 41; }
214 
215  // Return index for storing v. May return an empty index or deleted index
216  int FindIndex(int32_t v) const {
217  // Search starting at hash index.
218  const uint32_t mask = table_.size() - 1;
219  uint32_t i = Hash(v) & mask;
220  int deleted_index = -1; // If >= 0, index of first deleted element we see
221  while (true) {
222  int32_t e = table_[i];
223  if (v == e) {
224  return i;
225  } else if (e == kEmpty) {
226  // Return any previously encountered deleted slot.
227  return (deleted_index >= 0) ? deleted_index : i;
228  } else if (e == kDel && deleted_index < 0) {
229  // Keep searching since v might be present later.
230  deleted_index = i;
231  }
232  i = (i + 1) & mask; // Linear probing; quadratic is slightly slower.
233  }
234  }
235 
236  void Init() {
237  table_.clear();
238  table_.resize(kInline);
239  table_.fill(kEmpty);
240  occupied_ = 0;
241  }
242 
243  void Grow() {
244  Vec<int32_t> copy;
245  copy.MoveFrom(&table_);
246  occupied_ = 0;
247  table_.resize(copy.size() * 2);
248  table_.fill(kEmpty);
249 
250  for (const auto& e : copy) {
251  if (e >= 0) insert(e);
252  }
253  }
254 
255  NodeSet(const NodeSet&) = delete;
256  NodeSet& operator=(const NodeSet&) = delete;
257 };
258 
259 // We encode a node index and a node version in GraphId. The version
260 // number is incremented when the GraphId is freed which automatically
261 // invalidates all copies of the GraphId.
262 
263 inline GraphId MakeId(int32_t index, uint32_t version) {
264  GraphId g;
265  g.handle =
266  (static_cast<uint64_t>(version) << 32) | static_cast<uint32_t>(index);
267  return g;
268 }
269 
270 inline int32_t NodeIndex(GraphId id) {
271  return static_cast<uint32_t>(id.handle & 0xfffffffful);
272 }
273 
274 inline uint32_t NodeVersion(GraphId id) {
275  return static_cast<uint32_t>(id.handle >> 32);
276 }
277 
278 struct Node {
279  int32_t rank; // rank number assigned by Pearce-Kelly algorithm
280  uint32_t version; // Current version number
281  int32_t next_hash; // Next entry in hash table
282  bool visited; // Temporary marker used by depth-first-search
283  uintptr_t masked_ptr; // User-supplied pointer
284  NodeSet in; // List of immediate predecessor nodes in graph
285  NodeSet out; // List of immediate successor nodes in graph
286  int priority; // Priority of recorded stack trace.
287  int nstack; // Depth of recorded stack trace.
288  void* stack[40]; // stack[0,nstack-1] holds stack trace for node.
289 };
290 
291 // Hash table for pointer to node index lookups.
292 class PointerMap {
293  public:
294  explicit PointerMap(const Vec<Node*>* nodes) : nodes_(nodes) {
295  table_.fill(-1);
296  }
297 
298  int32_t Find(void* ptr) {
299  auto masked = base_internal::HidePtr(ptr);
300  for (int32_t i = table_[Hash(ptr)]; i != -1;) {
301  Node* n = (*nodes_)[i];
302  if (n->masked_ptr == masked) return i;
303  i = n->next_hash;
304  }
305  return -1;
306  }
307 
308  void Add(void* ptr, int32_t i) {
309  int32_t* head = &table_[Hash(ptr)];
310  (*nodes_)[i]->next_hash = *head;
311  *head = i;
312  }
313 
314  int32_t Remove(void* ptr) {
315  // Advance through linked list while keeping track of the
316  // predecessor slot that points to the current entry.
317  auto masked = base_internal::HidePtr(ptr);
318  for (int32_t* slot = &table_[Hash(ptr)]; *slot != -1; ) {
319  int32_t index = *slot;
320  Node* n = (*nodes_)[index];
321  if (n->masked_ptr == masked) {
322  *slot = n->next_hash; // Remove n from linked list
323  n->next_hash = -1;
324  return index;
325  }
326  slot = &n->next_hash;
327  }
328  return -1;
329  }
330 
331  private:
332  // Number of buckets in hash table for pointer lookups.
333  static constexpr uint32_t kHashTableSize = 8171; // should be prime
334 
335  const Vec<Node*>* nodes_;
336  std::array<int32_t, kHashTableSize> table_;
337 
338  static uint32_t Hash(void* ptr) {
339  return reinterpret_cast<uintptr_t>(ptr) % kHashTableSize;
340  }
341 };
342 
343 } // namespace
344 
346  Vec<Node*> nodes_;
347  Vec<int32_t> free_nodes_; // Indices for unused entries in nodes_
348  PointerMap ptrmap_;
349 
350  // Temporary state.
351  Vec<int32_t> deltaf_; // Results of forward DFS
352  Vec<int32_t> deltab_; // Results of backward DFS
353  Vec<int32_t> list_; // All nodes to reprocess
354  Vec<int32_t> merged_; // Rank values to assign to list_ entries
355  Vec<int32_t> stack_; // Emulates recursion stack for depth-first searches
356 
357  Rep() : ptrmap_(&nodes_) {}
358 };
359 
361  Node* n = rep->nodes_[NodeIndex(id)];
362  return (n->version == NodeVersion(id)) ? n : nullptr;
363 }
364 
366  InitArenaIfNecessary();
368  Rep;
369 }
370 
372  for (auto* node : rep_->nodes_) {
373  node->Node::~Node();
375  }
376  rep_->Rep::~Rep();
378 }
379 
381  Rep* r = rep_;
382  NodeSet ranks; // Set of ranks seen so far.
383  for (uint32_t x = 0; x < r->nodes_.size(); x++) {
384  Node* nx = r->nodes_[x];
385  void* ptr = base_internal::UnhidePtr<void>(nx->masked_ptr);
386  if (ptr != nullptr && static_cast<uint32_t>(r->ptrmap_.Find(ptr)) != x) {
387  ABSL_RAW_LOG(FATAL, "Did not find live node in hash table %u %p", x, ptr);
388  }
389  if (nx->visited) {
390  ABSL_RAW_LOG(FATAL, "Did not clear visited marker on node %u", x);
391  }
392  if (!ranks.insert(nx->rank)) {
393  ABSL_RAW_LOG(FATAL, "Duplicate occurrence of rank %d", nx->rank);
394  }
395  HASH_FOR_EACH(y, nx->out) {
396  Node* ny = r->nodes_[y];
397  if (nx->rank >= ny->rank) {
398  ABSL_RAW_LOG(FATAL, "Edge %u->%d has bad rank assignment %d->%d", x, y,
399  nx->rank, ny->rank);
400  }
401  }
402  }
403  return true;
404 }
405 
407  int32_t i = rep_->ptrmap_.Find(ptr);
408  if (i != -1) {
409  return MakeId(i, rep_->nodes_[i]->version);
410  } else if (rep_->free_nodes_.empty()) {
411  Node* n =
413  Node;
414  n->version = 1; // Avoid 0 since it is used by InvalidGraphId()
415  n->visited = false;
416  n->rank = rep_->nodes_.size();
417  n->masked_ptr = base_internal::HidePtr(ptr);
418  n->nstack = 0;
419  n->priority = 0;
420  rep_->nodes_.push_back(n);
421  rep_->ptrmap_.Add(ptr, n->rank);
422  return MakeId(n->rank, n->version);
423  } else {
424  // Preserve preceding rank since the set of ranks in use must be
425  // a permutation of [0,rep_->nodes_.size()-1].
426  int32_t r = rep_->free_nodes_.back();
427  rep_->free_nodes_.pop_back();
428  Node* n = rep_->nodes_[r];
429  n->masked_ptr = base_internal::HidePtr(ptr);
430  n->nstack = 0;
431  n->priority = 0;
432  rep_->ptrmap_.Add(ptr, r);
433  return MakeId(r, n->version);
434  }
435 }
436 
438  int32_t i = rep_->ptrmap_.Remove(ptr);
439  if (i == -1) {
440  return;
441  }
442  Node* x = rep_->nodes_[i];
443  HASH_FOR_EACH(y, x->out) {
444  rep_->nodes_[y]->in.erase(i);
445  }
446  HASH_FOR_EACH(y, x->in) {
447  rep_->nodes_[y]->out.erase(i);
448  }
449  x->in.clear();
450  x->out.clear();
451  x->masked_ptr = base_internal::HidePtr<void>(nullptr);
452  if (x->version == std::numeric_limits<uint32_t>::max()) {
453  // Cannot use x any more
454  } else {
455  x->version++; // Invalidates all copies of node.
456  rep_->free_nodes_.push_back(i);
457  }
458 }
459 
461  Node* n = FindNode(rep_, id);
462  return n == nullptr ? nullptr
463  : base_internal::UnhidePtr<void>(n->masked_ptr);
464 }
465 
467  return FindNode(rep_, node) != nullptr;
468 }
469 
471  Node* xn = FindNode(rep_, x);
472  return xn && FindNode(rep_, y) && xn->out.contains(NodeIndex(y));
473 }
474 
476  Node* xn = FindNode(rep_, x);
477  Node* yn = FindNode(rep_, y);
478  if (xn && yn) {
479  xn->out.erase(NodeIndex(y));
480  yn->in.erase(NodeIndex(x));
481  // No need to update the rank assignment since a previous valid
482  // rank assignment remains valid after an edge deletion.
483  }
484 }
485 
486 static bool ForwardDFS(GraphCycles::Rep* r, int32_t n, int32_t upper_bound);
487 static void BackwardDFS(GraphCycles::Rep* r, int32_t n, int32_t lower_bound);
488 static void Reorder(GraphCycles::Rep* r);
489 static void Sort(const Vec<Node*>&, Vec<int32_t>* delta);
490 static void MoveToList(
491  GraphCycles::Rep* r, Vec<int32_t>* src, Vec<int32_t>* dst);
492 
494  Rep* r = rep_;
495  const int32_t x = NodeIndex(idx);
496  const int32_t y = NodeIndex(idy);
497  Node* nx = FindNode(r, idx);
498  Node* ny = FindNode(r, idy);
499  if (nx == nullptr || ny == nullptr) return true; // Expired ids
500 
501  if (nx == ny) return false; // Self edge
502  if (!nx->out.insert(y)) {
503  // Edge already exists.
504  return true;
505  }
506 
507  ny->in.insert(x);
508 
509  if (nx->rank <= ny->rank) {
510  // New edge is consistent with existing rank assignment.
511  return true;
512  }
513 
514  // Current rank assignments are incompatible with the new edge. Recompute.
515  // We only need to consider nodes that fall in the range [ny->rank,nx->rank].
516  if (!ForwardDFS(r, y, nx->rank)) {
517  // Found a cycle. Undo the insertion and tell caller.
518  nx->out.erase(y);
519  ny->in.erase(x);
520  // Since we do not call Reorder() on this path, clear any visited
521  // markers left by ForwardDFS.
522  for (const auto& d : r->deltaf_) {
523  r->nodes_[d]->visited = false;
524  }
525  return false;
526  }
527  BackwardDFS(r, x, ny->rank);
528  Reorder(r);
529  return true;
530 }
531 
532 static bool ForwardDFS(GraphCycles::Rep* r, int32_t n, int32_t upper_bound) {
533  // Avoid recursion since stack space might be limited.
534  // We instead keep a stack of nodes to visit.
535  r->deltaf_.clear();
536  r->stack_.clear();
537  r->stack_.push_back(n);
538  while (!r->stack_.empty()) {
539  n = r->stack_.back();
540  r->stack_.pop_back();
541  Node* nn = r->nodes_[n];
542  if (nn->visited) continue;
543 
544  nn->visited = true;
545  r->deltaf_.push_back(n);
546 
547  HASH_FOR_EACH(w, nn->out) {
548  Node* nw = r->nodes_[w];
549  if (nw->rank == upper_bound) {
550  return false; // Cycle
551  }
552  if (!nw->visited && nw->rank < upper_bound) {
553  r->stack_.push_back(w);
554  }
555  }
556  }
557  return true;
558 }
559 
560 static void BackwardDFS(GraphCycles::Rep* r, int32_t n, int32_t lower_bound) {
561  r->deltab_.clear();
562  r->stack_.clear();
563  r->stack_.push_back(n);
564  while (!r->stack_.empty()) {
565  n = r->stack_.back();
566  r->stack_.pop_back();
567  Node* nn = r->nodes_[n];
568  if (nn->visited) continue;
569 
570  nn->visited = true;
571  r->deltab_.push_back(n);
572 
573  HASH_FOR_EACH(w, nn->in) {
574  Node* nw = r->nodes_[w];
575  if (!nw->visited && lower_bound < nw->rank) {
576  r->stack_.push_back(w);
577  }
578  }
579  }
580 }
581 
582 static void Reorder(GraphCycles::Rep* r) {
583  Sort(r->nodes_, &r->deltab_);
584  Sort(r->nodes_, &r->deltaf_);
585 
586  // Adds contents of delta lists to list_ (backwards deltas first).
587  r->list_.clear();
588  MoveToList(r, &r->deltab_, &r->list_);
589  MoveToList(r, &r->deltaf_, &r->list_);
590 
591  // Produce sorted list of all ranks that will be reassigned.
592  r->merged_.resize(r->deltab_.size() + r->deltaf_.size());
593  std::merge(r->deltab_.begin(), r->deltab_.end(),
594  r->deltaf_.begin(), r->deltaf_.end(),
595  r->merged_.begin());
596 
597  // Assign the ranks in order to the collected list.
598  for (uint32_t i = 0; i < r->list_.size(); i++) {
599  r->nodes_[r->list_[i]]->rank = r->merged_[i];
600  }
601 }
602 
603 static void Sort(const Vec<Node*>& nodes, Vec<int32_t>* delta) {
604  struct ByRank {
605  const Vec<Node*>* nodes;
606  bool operator()(int32_t a, int32_t b) const {
607  return (*nodes)[a]->rank < (*nodes)[b]->rank;
608  }
609  };
610  ByRank cmp;
611  cmp.nodes = &nodes;
612  std::sort(delta->begin(), delta->end(), cmp);
613 }
614 
615 static void MoveToList(
616  GraphCycles::Rep* r, Vec<int32_t>* src, Vec<int32_t>* dst) {
617  for (auto& v : *src) {
618  int32_t w = v;
619  v = r->nodes_[w]->rank; // Replace v entry with its rank
620  r->nodes_[w]->visited = false; // Prepare for future DFS calls
621  dst->push_back(w);
622  }
623 }
624 
625 int GraphCycles::FindPath(GraphId idx, GraphId idy, int max_path_len,
626  GraphId path[]) const {
627  Rep* r = rep_;
628  if (FindNode(r, idx) == nullptr || FindNode(r, idy) == nullptr) return 0;
629  const int32_t x = NodeIndex(idx);
630  const int32_t y = NodeIndex(idy);
631 
632  // Forward depth first search starting at x until we hit y.
633  // As we descend into a node, we push it onto the path.
634  // As we leave a node, we remove it from the path.
635  int path_len = 0;
636 
637  NodeSet seen;
638  r->stack_.clear();
639  r->stack_.push_back(x);
640  while (!r->stack_.empty()) {
641  int32_t n = r->stack_.back();
642  r->stack_.pop_back();
643  if (n < 0) {
644  // Marker to indicate that we are leaving a node
645  path_len--;
646  continue;
647  }
648 
649  if (path_len < max_path_len) {
650  path[path_len] = MakeId(n, rep_->nodes_[n]->version);
651  }
652  path_len++;
653  r->stack_.push_back(-1); // Will remove tentative path entry
654 
655  if (n == y) {
656  return path_len;
657  }
658 
659  HASH_FOR_EACH(w, r->nodes_[n]->out) {
660  if (seen.insert(w)) {
661  r->stack_.push_back(w);
662  }
663  }
664  }
665 
666  return 0;
667 }
668 
670  return FindPath(x, y, 0, nullptr) > 0;
671 }
672 
674  int (*get_stack_trace)(void** stack, int)) {
675  Node* n = FindNode(rep_, id);
676  if (n == nullptr || n->priority >= priority) {
677  return;
678  }
679  n->nstack = (*get_stack_trace)(n->stack, ABSL_ARRAYSIZE(n->stack));
680  n->priority = priority;
681 }
682 
684  Node* n = FindNode(rep_, id);
685  if (n == nullptr) {
686  *ptr = nullptr;
687  return 0;
688  } else {
689  *ptr = n->stack;
690  return n->nstack;
691  }
692 }
693 
694 } // namespace synchronization_internal
696 } // namespace absl
697 
698 #endif // ABSL_LOW_LEVEL_ALLOC_MISSING
absl::synchronization_internal::GraphCycles::InsertEdge
bool InsertEdge(GraphId source_node, GraphId dest_node)
Definition: abseil-cpp/absl/synchronization/internal/graphcycles.cc:493
ptr
char * ptr
Definition: abseil-cpp/absl/base/internal/low_level_alloc_test.cc:45
masked_ptr
uintptr_t masked_ptr
Definition: abseil-cpp/absl/synchronization/internal/graphcycles.cc:283
absl::synchronization_internal::GraphCycles::HasEdge
bool HasEdge(GraphId source_node, GraphId dest_node) const
Definition: abseil-cpp/absl/synchronization/internal/graphcycles.cc:470
absl::synchronization_internal::GraphCycles::rep_
Rep * rep_
Definition: abseil-cpp/absl/synchronization/internal/graphcycles.h:130
dst
static const char dst[]
Definition: test-fs-copyfile.c:37
Arena
struct Arena Arena
Definition: third_party/bloaty/third_party/protobuf/src/google/protobuf/arena.h:189
absl::synchronization_internal::GraphCycles::Rep::list_
Vec< int32_t > list_
Definition: abseil-cpp/absl/synchronization/internal/graphcycles.cc:353
priority
int priority
Definition: abseil-cpp/absl/synchronization/internal/graphcycles.cc:286
opencensus.proto.agent.common.v1.common_pb2.Node
Node
Definition: common_pb2.py:308
ABSL_CONST_INIT
#define ABSL_CONST_INIT
Definition: abseil-cpp/absl/base/attributes.h:716
absl::synchronization_internal::GraphCycles::UpdateStackTrace
void UpdateStackTrace(GraphId id, int priority, int(*get_stack_trace)(void **, int))
begin
char * begin
Definition: abseil-cpp/absl/strings/internal/str_format/float_conversion.cc:1007
absl::synchronization_internal::MoveToList
static void MoveToList(GraphCycles::Rep *r, Vec< int32_t > *src, Vec< int32_t > *dst)
Definition: abseil-cpp/absl/synchronization/internal/graphcycles.cc:615
google::protobuf::python::repeated_composite_container::Remove
static PyObject * Remove(PyObject *pself, PyObject *value)
Definition: bloaty/third_party/protobuf/python/google/protobuf/pyext/repeated_composite_container.cc:301
absl::synchronization_internal::GraphCycles::~GraphCycles
~GraphCycles()
Definition: abseil-cpp/absl/synchronization/internal/graphcycles.cc:371
absl::synchronization_internal::GraphCycles::GraphCycles
GraphCycles()
Definition: abseil-cpp/absl/synchronization/internal/graphcycles.cc:365
absl::synchronization_internal::GraphCycles::CheckInvariants
bool CheckInvariants() const
Definition: abseil-cpp/absl/synchronization/internal/graphcycles.cc:380
y
const double y
Definition: bloaty/third_party/googletest/googlemock/test/gmock-matchers_test.cc:3611
copy
static int copy(grpc_slice_buffer *input, grpc_slice_buffer *output)
Definition: message_compress.cc:145
absl::synchronization_internal::GraphCycles::HasNode
bool HasNode(GraphId node)
Definition: abseil-cpp/absl/synchronization/internal/graphcycles.cc:466
absl::base_internal::LowLevelAlloc::NewArena
static Arena * NewArena(int32_t flags)
Definition: abseil-cpp/absl/base/internal/low_level_alloc.cc:367
benchmark.request
request
Definition: benchmark.py:77
elem
Timer elem
Definition: event_engine/iomgr_event_engine/timer_heap_test.cc:109
absl::base_internal::SpinLock
Definition: third_party/abseil-cpp/absl/base/internal/spinlock.h:52
visited
bool visited
Definition: abseil-cpp/absl/synchronization/internal/graphcycles.cc:282
google::protobuf::python::cmessage::Init
static int Init(CMessage *self, PyObject *args, PyObject *kwargs)
Definition: bloaty/third_party/protobuf/python/google/protobuf/pyext/message.cc:1287
absl::synchronization_internal::GraphCycles::IsReachable
bool IsReachable(GraphId source_node, GraphId dest_node) const
Definition: abseil-cpp/absl/synchronization/internal/graphcycles.cc:669
version
Definition: version.py:1
check_documentation.path
path
Definition: check_documentation.py:57
a
int a
Definition: abseil-cpp/absl/container/internal/hash_policy_traits_test.cc:88
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::kConstInit
@ kConstInit
Definition: abseil-cpp/absl/base/const_init.h:70
nodes_
const Vec< Node * > * nodes_
Definition: abseil-cpp/absl/synchronization/internal/graphcycles.cc:335
occupied_
uint32_t occupied_
Definition: abseil-cpp/absl/synchronization/internal/graphcycles.cc:211
ABSL_ARRAYSIZE
#define ABSL_ARRAYSIZE(array)
Definition: abseil-cpp/absl/base/macros.h:44
ABSL_NAMESPACE_END
#define ABSL_NAMESPACE_END
Definition: third_party/abseil-cpp/absl/base/config.h:171
absl::synchronization_internal::BackwardDFS
static void BackwardDFS(GraphCycles::Rep *r, int32_t n, int32_t lower_bound)
Definition: abseil-cpp/absl/synchronization/internal/graphcycles.cc:560
absl::base_internal::Next
static AllocList * Next(int i, AllocList *prev, LowLevelAlloc::Arena *arena)
Definition: abseil-cpp/absl/base/internal/low_level_alloc.cc:453
space_
T space_[kInline]
Definition: abseil-cpp/absl/synchronization/internal/graphcycles.cc:130
T
#define T(upbtypeconst, upbtype, ctype, default_value)
absl::synchronization_internal::GraphId
Definition: abseil-cpp/absl/synchronization/internal/graphcycles.h:50
absl::synchronization_internal::GraphCycles::RemoveNode
void RemoveNode(void *ptr)
Definition: abseil-cpp/absl/synchronization/internal/graphcycles.cc:437
arena
grpc_core::ScopedArenaPtr arena
Definition: binder_transport_test.cc:237
uint32_t
unsigned int uint32_t
Definition: stdint-msvc2008.h:80
absl::synchronization_internal::GraphCycles::Rep::merged_
Vec< int32_t > merged_
Definition: abseil-cpp/absl/synchronization/internal/graphcycles.cc:354
ptr_
T * ptr_
Definition: abseil-cpp/absl/synchronization/internal/graphcycles.cc:129
absl::synchronization_internal::FindNode
static Node * FindNode(GraphCycles::Rep *rep, GraphId id)
Definition: abseil-cpp/absl/synchronization/internal/graphcycles.cc:360
absl::base_internal::HidePtr
uintptr_t HidePtr(T *ptr)
Definition: abseil-cpp/absl/base/internal/hide_ptr.h:36
absl::FormatConversionChar::e
@ e
ABSL_NAMESPACE_BEGIN
#define ABSL_NAMESPACE_BEGIN
Definition: third_party/abseil-cpp/absl/base/config.h:170
version
uint32_t version
Definition: abseil-cpp/absl/synchronization/internal/graphcycles.cc:280
end
char * end
Definition: abseil-cpp/absl/strings/internal/str_format/float_conversion.cc:1008
absl::synchronization_internal::GraphCycles::Rep::Rep
Rep()
Definition: abseil-cpp/absl/synchronization/internal/graphcycles.cc:357
absl::base_internal::LowLevelAlloc::Free
static void Free(void *s) ABSL_ATTRIBUTE_SECTION(malloc_hook)
Definition: abseil-cpp/absl/base/internal/low_level_alloc.cc:509
absl::synchronization_internal::GraphCycles::RemoveEdge
void RemoveEdge(GraphId source_node, GraphId dest_node)
Definition: abseil-cpp/absl/synchronization/internal/graphcycles.cc:475
capacity_
uint32_t capacity_
Definition: abseil-cpp/absl/synchronization/internal/graphcycles.cc:132
max
int max
Definition: bloaty/third_party/zlib/examples/enough.c:170
setup.v
v
Definition: third_party/bloaty/third_party/capstone/bindings/python/setup.py:42
absl::synchronization_internal::GraphCycles::Rep::stack_
Vec< int32_t > stack_
Definition: abseil-cpp/absl/synchronization/internal/graphcycles.cc:355
absl::synchronization_internal::GraphCycles::GetStackTrace
int GetStackTrace(GraphId id, void ***ptr)
Definition: abseil-cpp/absl/synchronization/internal/graphcycles.cc:683
uint64_t
unsigned __int64 uint64_t
Definition: stdint-msvc2008.h:90
nstack
int nstack
Definition: abseil-cpp/absl/synchronization/internal/graphcycles.cc:287
absl::synchronization_internal::GraphCycles::Ptr
void * Ptr(GraphId id)
Definition: abseil-cpp/absl/synchronization/internal/graphcycles.cc:460
stack
void * stack[40]
Definition: abseil-cpp/absl/synchronization/internal/graphcycles.cc:288
rank
int32_t rank
Definition: abseil-cpp/absl/synchronization/internal/graphcycles.cc:279
absl::synchronization_internal::GraphCycles::Rep::ptrmap_
PointerMap ptrmap_
Definition: abseil-cpp/absl/synchronization/internal/graphcycles.cc:348
x
int x
Definition: bloaty/third_party/googletest/googlemock/test/gmock-matchers_test.cc:3610
uintptr_t
_W64 unsigned int uintptr_t
Definition: stdint-msvc2008.h:119
tests.google.protobuf.internal.message_test.cmp
cmp
Definition: bloaty/third_party/protobuf/python/compatibility_tests/v2.5.0/tests/google/protobuf/internal/message_test.py:61
b
uint64_t b
Definition: abseil-cpp/absl/container/internal/layout_test.cc:53
g
struct @717 g
absl::synchronization_internal::Reorder
static void Reorder(GraphCycles::Rep *r)
Definition: abseil-cpp/absl/synchronization/internal/graphcycles.cc:582
n
int n
Definition: abseil-cpp/absl/container/btree_test.cc:1080
setup.idx
idx
Definition: third_party/bloaty/third_party/capstone/bindings/python/setup.py:197
absl::synchronization_internal::Sort
static void Sort(const Vec< Node * > &, Vec< int32_t > *delta)
Definition: abseil-cpp/absl/synchronization/internal/graphcycles.cc:603
absl::synchronization_internal::GraphCycles::Rep::deltab_
Vec< int32_t > deltab_
Definition: abseil-cpp/absl/synchronization/internal/graphcycles.cc:352
google_benchmark.example.empty
def empty(state)
Definition: example.py:31
next_hash
int32_t next_hash
Definition: abseil-cpp/absl/synchronization/internal/graphcycles.cc:281
kHashTableSize
static constexpr uint32_t kHashTableSize
Definition: abseil-cpp/absl/synchronization/internal/graphcycles.cc:333
absl::synchronization_internal::GraphCycles::Rep::nodes_
Vec< Node * > nodes_
Definition: abseil-cpp/absl/synchronization/internal/graphcycles.cc:346
FATAL
#define FATAL(msg)
Definition: task.h:88
absl::base_internal::SCHEDULE_KERNEL_ONLY
@ SCHEDULE_KERNEL_ONLY
Definition: abseil-cpp/absl/base/internal/scheduling_mode.h:50
insert
static void insert(upb_table *t, lookupkey_t key, upb_tabkey tabkey, upb_value val, uint32_t hash, hashfunc_t *hashfunc, eqlfunc_t *eql)
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/upb.c:1431
size_
uint32_t size_
Definition: abseil-cpp/absl/synchronization/internal/graphcycles.cc:131
table_
Vec< int32_t > table_
Definition: abseil-cpp/absl/synchronization/internal/graphcycles.cc:210
absl::synchronization_internal::GraphCycles::Rep::deltaf_
Vec< int32_t > deltaf_
Definition: abseil-cpp/absl/synchronization/internal/graphcycles.cc:351
absl::container_internal::kEmpty
@ kEmpty
Definition: bloaty/third_party/abseil-cpp/absl/container/internal/raw_hash_set.h:261
index
int index
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/protobuf.h:1184
absl::container_internal::internal_layout::adl_barrier::Find
constexpr size_t Find(Needle, Needle, Ts...)
Definition: abseil-cpp/absl/container/internal/layout.h:269
fix_build_deps.r
r
Definition: fix_build_deps.py:491
absl::synchronization_internal::ForwardDFS
static bool ForwardDFS(GraphCycles::Rep *r, int32_t n, int32_t upper_bound)
Definition: abseil-cpp/absl/synchronization/internal/graphcycles.cc:532
rep
const CordRep * rep
Definition: cord_analysis.cc:53
HASH_FOR_EACH
#define HASH_FOR_EACH(elem, eset)
Definition: abseil-cpp/absl/synchronization/internal/graphcycles.cc:194
absl::synchronization_internal::GraphCycles::Rep::free_nodes_
Vec< int32_t > free_nodes_
Definition: abseil-cpp/absl/synchronization/internal/graphcycles.cc:347
fill
int fill
Definition: abseil-cpp/absl/base/internal/low_level_alloc_test.cc:47
absl::synchronization_internal::GraphCycles::Rep
Definition: abseil-cpp/absl/synchronization/internal/graphcycles.cc:345
absl::synchronization_internal::GraphCycles::GetId
GraphId GetId(void *ptr)
Definition: abseil-cpp/absl/synchronization/internal/graphcycles.cc:406
contains
static int contains(grpc_timer_heap *pq, grpc_timer *el)
Definition: iomgr/timer_heap_test.cc:43
absl
Definition: abseil-cpp/absl/algorithm/algorithm.h:31
in
NodeSet in
Definition: abseil-cpp/absl/synchronization/internal/graphcycles.cc:284
absl::out
char * out
Definition: abseil-cpp/absl/synchronization/mutex.h:1048
size
voidpf void uLong size
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:136
generate-asm-lcov.merge
def merge(callgrind_files, srcs)
Definition: generate-asm-lcov.py:50
int32_t
signed int int32_t
Definition: stdint-msvc2008.h:77
seen
bool * seen
Definition: async_end2end_test.cc:198
ABSL_RAW_LOG
#define ABSL_RAW_LOG(severity,...)
Definition: abseil-cpp/absl/base/internal/raw_logging.h:44
absl::synchronization_internal::GraphCycles::FindPath
int FindPath(GraphId source, GraphId dest, int max_path_len, GraphId path[]) const
Definition: abseil-cpp/absl/synchronization/internal/graphcycles.cc:625
absl::base_internal::LowLevelAlloc::AllocWithArena
static void * AllocWithArena(size_t request, Arena *arena) ABSL_ATTRIBUTE_SECTION(malloc_hook)
Definition: abseil-cpp/absl/base/internal/low_level_alloc.cc:610
i
uint64_t i
Definition: abseil-cpp/absl/container/btree_benchmark.cc:230
absl::Hash
absl::hash_internal::Hash< T > Hash
Definition: abseil-cpp/absl/hash/hash.h:247


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