Space out GraphCycles ranks so that InsertEdge can often move just one node In debug builds, absl::Mutex deadlock detection records each lock-order edge with GraphCycles::InsertEdge(held, acquired), under a global lock. GraphCycles keeps node ranks in topological order: rank(x) < rank(y) for each edge x->y. When a new edge breaks this order, InsertEdge uses the Pearce-Kelly algorithm to detect a cycle or repair the ranks. Before this change, ranks were a dense permutation of [0, N), and each new slot got the next rank, above all existing nodes. So when a newly created mutex x is held while an older mutex y is acquired, which is common, the edge x->y often breaks the order. Pearce-Kelly then visits every descendant of y that ranks below x (nearly all of them, since x is new), and sorts and renumbers them, just to put one node in order. With no unused ranks between nodes, even moving one node means renumbering everything in between. This change leaves unused ranks between nodes, so that InsertEdge can often fix the order by moving just x or just y: - Ranks are now int64_t, and new slots get ranks 2^32 above the highest rank. All slots, including free slots, are kept in a doubly linked list sorted by rank. As before, a free slot keeps its rank (and now its place in the list), which is reused with the slot. - If rank(x) > rank(y), InsertEdge(x, y) first tries to move x below y, which requires all in-neighbors of x to rank below y. x moves to the midpoint between y and the slot just below y, or 2^32 below the lowest rank if x has no in-neighbors. If x cannot move, InsertEdge tries the symmetric move of y above x, which requires all out-neighbors of y to rank above x. If neither move works, Pearce-Kelly runs as before. - Ranks stay unique by construction: each new rank is strictly between the ranks of two adjacent slots in the list, or beyond the lowest or highest rank, so no other slot can have it. As before, the Pearce-Kelly reorder reassigns the ranks of the reordered nodes among them. It now also gives each one the list place that goes with its new rank. - A move never hides a cycle: the condition for moving x also proves that y cannot reach x, since every node reachable from y ranks at or above y, but every in-neighbor of x ranks below y. The same holds for moving y, so all cycle detection still happens in the Pearce-Kelly path. Why not simply give new nodes decreasing initial ranks (below all existing nodes)? That makes new -> old edges immediately ordered, but it inverts the order for old -> new edges, such as when a long-lived container mutex locks a newly created child mutex, or when a chain of mutexes is acquired in creation order. Every old -> new edge then triggers a Pearce-Kelly traversal and dense renumbering, making sequential chain construction (BM_StressTest) quadratic: O(N) per edge (114 us/node at N=2048 and 2.9 ms/node at N=32768, vs. under 0.5 us/node). Spacing ranks out and moving either endpoint handles both directions in O(degree) time. Limits and trade-offs: - InsertEdge does not try to move x if x has more than 16 in-neighbors to check, or y if y has more than 16 out-neighbors. If neither can move, it falls back to Pearce-Kelly. This bounds the cost of each attempt. - The 2^32 spacing leaves room for about 32 consecutive moves into the gap between two adjacent new slots. When the two ranks around a gap are less than 2 apart, Respace() first spreads out a run of slots around the gap, keeping their order. Starting with the two slots around the gap, the run doubles in size until its slots can be evenly spaced at least 2^16 apart between the ranks just outside it (-2^62 and 2^62 beyond the ends of the list). - Ranks beyond the lowest and highest ones stay within [-2^62, 2^62], which leaves room for about 2^30 moves (or new slots) at each end. When that runs out, all slots are respaced evenly across [-2^61, 2^61] in O(N) time, which leaves room for 2^29 more at each end. - Slot indices are still int32_t, and the ranks have room for 2^31 slots, so there is no new limit on node count. - Node grows by 16 bytes, for the 64-bit rank and two 32-bit list links (with alignment). It was already over 400 bytes, since it holds a 40-entry stack trace. New tests cover each kind of move, the fallbacks to Pearce-Kelly, and both kinds of respacing. A new test-only method, TestOnlySetRankStride(), lets a test make the ranks beyond the lowest and highest ones run out after a few moves, to exercise the respacing of all slots. PiperOrigin-RevId: 999040867 Change-Id: I3353404e681c094b3cbd4978f384c0415200b2ec
The repository contains the Abseil C++ library code. Abseil is an open-source collection of C++ code (compliant to C++17) designed to augment the C++ standard library.
Abseil is an open-source collection of C++ library code designed to augment the C++ standard library. The Abseil library code is collected from Google's own C++ code base, has been extensively tested and used in production, and is the same code we depend on in our daily coding lives.
In some cases, Abseil provides pieces missing from the C++ standard; in others, Abseil provides alternatives to the standard for special needs we've found through usage in the Google code base. We denote those cases clearly within the library code we provide you.
Abseil is not meant to be a competitor to the standard library; we've just found that many of these utilities serve a purpose within our code base, and we now want to provide those resources to the C++ community as a whole.
If you want to just get started, make sure you at least run through the Abseil Quickstart. The Quickstart contains information about setting up your development environment, downloading the Abseil code, running tests, and getting a simple binary working.
Bazel and CMake are the official build systems for Abseil. See the quickstart for more information on building Abseil using the Bazel build system. If you require CMake support, please check the CMake build instructions and CMake Quickstart.
Abseil follows Google's Foundational C++ Support Policy. See this table for a list of currently supported versions compilers, platforms, and build tools.
Abseil contains the following C++ library components:
base base library contains initialization code and other code which all other Abseil code depends on. Code within base may not depend on any other code (other than the C++ standard library).algorithm algorithm library contains additions to the C++ <algorithm> library and container-based versions of such algorithms.cleanup cleanup library contains the control-flow-construct-like type absl::Cleanup which is used for executing a callback on scope exit.container container library contains additional STL-style containers, including Abseil's unordered “Swiss table” containers.crc The crc library contains code for computing error-detecting cyclic redundancy checks on data.debugging debugging library contains code useful for enabling leak checks, and stacktrace and symbolization utilities.flags flags library contains code for handling command line flags for libraries and binaries built with Abseil.hash hash library contains the hashing framework and default hash functor implementations for hashable types in Abseil.log log library contains LOG and CHECK macros and facilities for writing logged messages out to disk, stderr, or user-extensible destinations.memory memory library contains memory management facilities that augment C++'s <memory> library.meta meta library contains type checks similar to those available in the C++ <type_traits> library.numeric numeric library contains 128-bit integer types as well as implementations of C++20's bitwise math functions.profiling profiling library contains utility code for profiling C++ entities. It is currently a private dependency of other Abseil libraries.random random library contains functions for generating pseudorandom values.status status library contains abstractions for error handling, specifically absl::Status and absl::StatusOr<T>.strings strings library contains a variety of strings routines and utilities.synchronization synchronization library contains concurrency primitives (Abseil's absl::Mutex class, an alternative to std::mutex) and a variety of synchronization abstractions.time time library contains abstractions for computing with absolute points in time, durations of time, and formatting and parsing time within time zones.types types library contains non-container utility types.utility utility library contains utility and helper code.Abseil recommends users “live-at-head” (update to the latest commit from the master branch as often as possible). However, we realize this philosophy doesn't work for every project, so we also provide Long Term Support Releases to which we backport fixes for severe bugs. See our release management document for more details.
The Abseil C++ library is licensed under the terms of the Apache license. See LICENSE for more information.
For more information about Abseil: