1*700637cbSDimitry Andric /*===- RootAutodetector.h- auto-detect roots for ctxprof -----------------===*\ 2*700637cbSDimitry Andric |* 3*700637cbSDimitry Andric |* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*700637cbSDimitry Andric |* See https://llvm.org/LICENSE.txt for license information. 5*700637cbSDimitry Andric |* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*700637cbSDimitry Andric |* 7*700637cbSDimitry Andric \*===----------------------------------------------------------------------===*/ 8*700637cbSDimitry Andric 9*700637cbSDimitry Andric #ifndef CTX_PROFILE_ROOTAUTODETECTOR_H_ 10*700637cbSDimitry Andric #define CTX_PROFILE_ROOTAUTODETECTOR_H_ 11*700637cbSDimitry Andric 12*700637cbSDimitry Andric #include "sanitizer_common/sanitizer_dense_map.h" 13*700637cbSDimitry Andric #include "sanitizer_common/sanitizer_internal_defs.h" 14*700637cbSDimitry Andric #include "sanitizer_common/sanitizer_stacktrace.h" 15*700637cbSDimitry Andric #include "sanitizer_common/sanitizer_vector.h" 16*700637cbSDimitry Andric #include <pthread.h> 17*700637cbSDimitry Andric #include <sanitizer/common_interface_defs.h> 18*700637cbSDimitry Andric 19*700637cbSDimitry Andric using namespace __asan; 20*700637cbSDimitry Andric using namespace __sanitizer; 21*700637cbSDimitry Andric 22*700637cbSDimitry Andric namespace __ctx_profile { 23*700637cbSDimitry Andric 24*700637cbSDimitry Andric /// Capture all the stack traces observed for a specific thread. The "for a 25*700637cbSDimitry Andric /// specific thread" part is not enforced, but assumed in determineRoots. 26*700637cbSDimitry Andric class PerThreadCallsiteTrie { 27*700637cbSDimitry Andric protected: 28*700637cbSDimitry Andric /// A trie. A node is the address of a callsite in a function activation. A 29*700637cbSDimitry Andric /// child is a callsite in the activation made from the callsite 30*700637cbSDimitry Andric /// corresponding to the parent. 31*700637cbSDimitry Andric struct Trie final { 32*700637cbSDimitry Andric const uptr CallsiteAddress; 33*700637cbSDimitry Andric uint64_t Count = 0; 34*700637cbSDimitry Andric DenseMap<uptr, Trie> Children; 35*700637cbSDimitry Andric CallsiteAddressfinal36*700637cbSDimitry Andric Trie(uptr CallsiteAddress = 0) : CallsiteAddress(CallsiteAddress) {} 37*700637cbSDimitry Andric }; 38*700637cbSDimitry Andric Trie TheTrie; 39*700637cbSDimitry Andric 40*700637cbSDimitry Andric /// Return the runtime start address of the function that contains the call at 41*700637cbSDimitry Andric /// the runtime address CallsiteAddress. May be overriden for easy testing. 42*700637cbSDimitry Andric virtual uptr getFctStartAddr(uptr CallsiteAddress) const; 43*700637cbSDimitry Andric 44*700637cbSDimitry Andric public: 45*700637cbSDimitry Andric PerThreadCallsiteTrie(const PerThreadCallsiteTrie &) = delete; 46*700637cbSDimitry Andric PerThreadCallsiteTrie(PerThreadCallsiteTrie &&) = default; 47*700637cbSDimitry Andric PerThreadCallsiteTrie() = default; 48*700637cbSDimitry Andric 49*700637cbSDimitry Andric virtual ~PerThreadCallsiteTrie() = default; 50*700637cbSDimitry Andric 51*700637cbSDimitry Andric void insertStack(const StackTrace &ST); 52*700637cbSDimitry Andric 53*700637cbSDimitry Andric /// Return the runtime address of root functions, as determined for this 54*700637cbSDimitry Andric /// thread, together with the number of samples that included them. 55*700637cbSDimitry Andric DenseMap<uptr, uint64_t> determineRoots() const; 56*700637cbSDimitry Andric }; 57*700637cbSDimitry Andric 58*700637cbSDimitry Andric class RootAutoDetector final { 59*700637cbSDimitry Andric // A prime number. We may want to make this configurable at collection start. 60*700637cbSDimitry Andric static const uint64_t SampleRate = 6113; 61*700637cbSDimitry Andric const unsigned WaitSeconds; 62*700637cbSDimitry Andric pthread_t WorkerThread; 63*700637cbSDimitry Andric 64*700637cbSDimitry Andric struct PerThreadSamples { 65*700637cbSDimitry Andric PerThreadSamples(RootAutoDetector &Parent); 66*700637cbSDimitry Andric 67*700637cbSDimitry Andric PerThreadCallsiteTrie TrieRoot; 68*700637cbSDimitry Andric SpinMutex M; 69*700637cbSDimitry Andric }; 70*700637cbSDimitry Andric SpinMutex AllSamplesMutex; 71*700637cbSDimitry Andric SANITIZER_GUARDED_BY(AllSamplesMutex) 72*700637cbSDimitry Andric Vector<PerThreadSamples *> AllSamples; 73*700637cbSDimitry Andric atomic_uintptr_t &FunctionDataListHead; 74*700637cbSDimitry Andric atomic_uintptr_t &Self; 75*700637cbSDimitry Andric void collectStack(); 76*700637cbSDimitry Andric 77*700637cbSDimitry Andric public: RootAutoDetector(atomic_uintptr_t & FunctionDataListHead,atomic_uintptr_t & Self,unsigned WaitSeconds)78*700637cbSDimitry Andric RootAutoDetector(atomic_uintptr_t &FunctionDataListHead, 79*700637cbSDimitry Andric atomic_uintptr_t &Self, unsigned WaitSeconds) 80*700637cbSDimitry Andric : WaitSeconds(WaitSeconds), FunctionDataListHead(FunctionDataListHead), 81*700637cbSDimitry Andric Self(Self) {} 82*700637cbSDimitry Andric 83*700637cbSDimitry Andric // Samples the stack at `SampleRate` (rate observed independently on each 84*700637cbSDimitry Andric // thread) in thread local `PerThreadCallsiteTrie`s. 85*700637cbSDimitry Andric void sample(); 86*700637cbSDimitry Andric 87*700637cbSDimitry Andric // Start a thread waiting `WaitSeconds`, after which it uses the 88*700637cbSDimitry Andric // `PerThreadCallsiteTrie` data observed so far over all threads to determine 89*700637cbSDimitry Andric // roots. Marks those roots by traversing the linked list of FunctionData that 90*700637cbSDimitry Andric // starts at `FunctionDataListHead`, and assigning their `CtxRoot`. Finally, 91*700637cbSDimitry Andric // resets the `Self` atomic, so that other threads don't continue calling 92*700637cbSDimitry Andric // `sample`. 93*700637cbSDimitry Andric void start(); 94*700637cbSDimitry Andric 95*700637cbSDimitry Andric // join the waiting thread. 96*700637cbSDimitry Andric void join(); 97*700637cbSDimitry Andric }; 98*700637cbSDimitry Andric 99*700637cbSDimitry Andric } // namespace __ctx_profile 100*700637cbSDimitry Andric #endif 101