123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194 |
- //===-- sanitizer_stackdepotbase.h ------------------------------*- C++ -*-===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- //
- // Implementation of a mapping from arbitrary values to unique 32-bit
- // identifiers.
- //===----------------------------------------------------------------------===//
- #ifndef SANITIZER_STACKDEPOTBASE_H
- #define SANITIZER_STACKDEPOTBASE_H
- #include <stdio.h>
- #include "sanitizer_atomic.h"
- #include "sanitizer_flat_map.h"
- #include "sanitizer_internal_defs.h"
- #include "sanitizer_mutex.h"
- namespace __sanitizer {
- template <class Node, int kReservedBits, int kTabSizeLog>
- class StackDepotBase {
- static constexpr u32 kIdSizeLog =
- sizeof(u32) * 8 - Max(kReservedBits, 1 /* At least 1 bit for locking. */);
- static constexpr u32 kNodesSize1Log = kIdSizeLog / 2;
- static constexpr u32 kNodesSize2Log = kIdSizeLog - kNodesSize1Log;
- static constexpr int kTabSize = 1 << kTabSizeLog; // Hash table size.
- static constexpr u32 kUnlockMask = (1ull << kIdSizeLog) - 1;
- static constexpr u32 kLockMask = ~kUnlockMask;
- public:
- typedef typename Node::args_type args_type;
- typedef typename Node::handle_type handle_type;
- typedef typename Node::hash_type hash_type;
- static constexpr u64 kNodesSize1 = 1ull << kNodesSize1Log;
- static constexpr u64 kNodesSize2 = 1ull << kNodesSize2Log;
- // Maps stack trace to an unique id.
- u32 Put(args_type args, bool *inserted = nullptr);
- // Retrieves a stored stack trace by the id.
- args_type Get(u32 id);
- StackDepotStats GetStats() const {
- return {
- atomic_load_relaxed(&n_uniq_ids),
- nodes.MemoryUsage() + Node::allocated(),
- };
- }
- void LockAll();
- void UnlockAll();
- void PrintAll();
- void TestOnlyUnmap() {
- nodes.TestOnlyUnmap();
- internal_memset(this, 0, sizeof(*this));
- }
- private:
- friend Node;
- u32 find(u32 s, args_type args, hash_type hash) const;
- static u32 lock(atomic_uint32_t *p);
- static void unlock(atomic_uint32_t *p, u32 s);
- atomic_uint32_t tab[kTabSize]; // Hash table of Node's.
- atomic_uint32_t n_uniq_ids;
- TwoLevelMap<Node, kNodesSize1, kNodesSize2> nodes;
- friend class StackDepotReverseMap;
- };
- template <class Node, int kReservedBits, int kTabSizeLog>
- u32 StackDepotBase<Node, kReservedBits, kTabSizeLog>::find(
- u32 s, args_type args, hash_type hash) const {
- // Searches linked list s for the stack, returns its id.
- for (; s;) {
- const Node &node = nodes[s];
- if (node.eq(hash, args))
- return s;
- s = node.link;
- }
- return 0;
- }
- template <class Node, int kReservedBits, int kTabSizeLog>
- u32 StackDepotBase<Node, kReservedBits, kTabSizeLog>::lock(atomic_uint32_t *p) {
- // Uses the pointer lsb as mutex.
- for (int i = 0;; i++) {
- u32 cmp = atomic_load(p, memory_order_relaxed);
- if ((cmp & kLockMask) == 0 &&
- atomic_compare_exchange_weak(p, &cmp, cmp | kLockMask,
- memory_order_acquire))
- return cmp;
- if (i < 10)
- proc_yield(10);
- else
- internal_sched_yield();
- }
- }
- template <class Node, int kReservedBits, int kTabSizeLog>
- void StackDepotBase<Node, kReservedBits, kTabSizeLog>::unlock(
- atomic_uint32_t *p, u32 s) {
- DCHECK_EQ(s & kLockMask, 0);
- atomic_store(p, s, memory_order_release);
- }
- template <class Node, int kReservedBits, int kTabSizeLog>
- u32 StackDepotBase<Node, kReservedBits, kTabSizeLog>::Put(args_type args,
- bool *inserted) {
- if (inserted)
- *inserted = false;
- if (!LIKELY(Node::is_valid(args)))
- return 0;
- hash_type h = Node::hash(args);
- atomic_uint32_t *p = &tab[h % kTabSize];
- u32 v = atomic_load(p, memory_order_consume);
- u32 s = v & kUnlockMask;
- // First, try to find the existing stack.
- u32 node = find(s, args, h);
- if (LIKELY(node))
- return node;
- // If failed, lock, retry and insert new.
- u32 s2 = lock(p);
- if (s2 != s) {
- node = find(s2, args, h);
- if (node) {
- unlock(p, s2);
- return node;
- }
- }
- s = atomic_fetch_add(&n_uniq_ids, 1, memory_order_relaxed) + 1;
- CHECK_EQ(s & kUnlockMask, s);
- CHECK_EQ(s & (((u32)-1) >> kReservedBits), s);
- Node &new_node = nodes[s];
- new_node.store(s, args, h);
- new_node.link = s2;
- unlock(p, s);
- if (inserted) *inserted = true;
- return s;
- }
- template <class Node, int kReservedBits, int kTabSizeLog>
- typename StackDepotBase<Node, kReservedBits, kTabSizeLog>::args_type
- StackDepotBase<Node, kReservedBits, kTabSizeLog>::Get(u32 id) {
- if (id == 0)
- return args_type();
- CHECK_EQ(id & (((u32)-1) >> kReservedBits), id);
- if (!nodes.contains(id))
- return args_type();
- const Node &node = nodes[id];
- return node.load(id);
- }
- template <class Node, int kReservedBits, int kTabSizeLog>
- void StackDepotBase<Node, kReservedBits, kTabSizeLog>::LockAll() {
- for (int i = 0; i < kTabSize; ++i) {
- lock(&tab[i]);
- }
- }
- template <class Node, int kReservedBits, int kTabSizeLog>
- void StackDepotBase<Node, kReservedBits, kTabSizeLog>::UnlockAll() {
- for (int i = 0; i < kTabSize; ++i) {
- atomic_uint32_t *p = &tab[i];
- uptr s = atomic_load(p, memory_order_relaxed);
- unlock(p, s & kUnlockMask);
- }
- }
- template <class Node, int kReservedBits, int kTabSizeLog>
- void StackDepotBase<Node, kReservedBits, kTabSizeLog>::PrintAll() {
- for (int i = 0; i < kTabSize; ++i) {
- atomic_uint32_t *p = &tab[i];
- u32 s = atomic_load(p, memory_order_consume) & kUnlockMask;
- for (; s;) {
- const Node &node = nodes[s];
- Printf("Stack for id %u:\n", s);
- node.load(s).Print();
- s = node.link;
- }
- }
- }
- } // namespace __sanitizer
- #endif // SANITIZER_STACKDEPOTBASE_H
|