1 // Copyright 2015 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef BASE_TRACE_EVENT_HEAP_PROFILER_ALLOCATION_CONTEXT_TRACKER_H_ 6 #define BASE_TRACE_EVENT_HEAP_PROFILER_ALLOCATION_CONTEXT_TRACKER_H_ 7 8 #include <atomic> 9 #include <vector> 10 11 #include "base/base_export.h" 12 13 namespace base { 14 namespace trace_event { 15 16 // AllocationContextTracker is a thread-local object. Its main purpose is to 17 // keep track of context pointers for memory allocation samples. See 18 // |AllocationContext|. 19 // 20 // A thread-local instance of the context tracker is initialized lazily when it 21 // is first accessed. 22 class BASE_EXPORT AllocationContextTracker { 23 public: 24 enum class CaptureMode : int32_t { 25 DISABLED, // Don't capture anything 26 NATIVE_STACK, // Backtrace has full native backtraces from stack unwinding 27 }; 28 29 // Globally sets capturing mode. 30 // TODO(primiano): How to guard against *_STACK -> DISABLED -> *_STACK? 31 static void SetCaptureMode(CaptureMode mode); 32 33 // Returns global capturing mode. capture_mode()34 inline static CaptureMode capture_mode() { 35 // A little lag after heap profiling is enabled or disabled is fine, it is 36 // more important that the check is as cheap as possible when capturing is 37 // not enabled, so do not issue a memory barrier in the fast path. 38 if (capture_mode_.load(std::memory_order_relaxed) == CaptureMode::DISABLED) 39 return CaptureMode::DISABLED; 40 41 // In the slow path, an acquire load is required to pair with the release 42 // store in |SetCaptureMode|. This is to ensure that the TLS slot for 43 // the thread-local allocation context tracker has been initialized if 44 // |capture_mode| returns something other than DISABLED. 45 return capture_mode_.load(std::memory_order_acquire); 46 } 47 48 // Returns the thread-local instance, creating one if necessary. Returns 49 // always a valid instance, unless it is called re-entrantly, in which case 50 // returns nullptr in the nested calls. 51 static AllocationContextTracker* GetInstanceForCurrentThread(); 52 53 // Set the thread name in the AllocationContextTracker of the current thread 54 // if capture is enabled. 55 static void SetCurrentThreadName(const char* name); 56 57 AllocationContextTracker(const AllocationContextTracker&) = delete; 58 AllocationContextTracker& operator=(const AllocationContextTracker&) = delete; 59 60 // Push and pop current task's context. A stack is used to support nested 61 // tasks and the top of the stack will be used in allocation context. 62 void PushCurrentTaskContext(const char* context); 63 void PopCurrentTaskContext(const char* context); 64 65 // Returns most recent task context added by ScopedTaskExecutionTracker. 66 // TODO(https://crbug.com/1378619): Audit callers of TaskContext() to see if 67 // any are useful. If not, remove AllocationContextTracker entirely. TaskContext()68 const char* TaskContext() const { 69 return task_contexts_.empty() ? nullptr : task_contexts_.back(); 70 } 71 72 ~AllocationContextTracker(); 73 74 private: 75 AllocationContextTracker(); 76 77 static std::atomic<CaptureMode> capture_mode_; 78 79 // The thread name is used as the first entry in the pseudo stack. 80 const char* thread_name_ = nullptr; 81 82 // Stack of tasks' contexts. 83 std::vector<const char*> task_contexts_; 84 }; 85 86 } // namespace trace_event 87 } // namespace base 88 89 #endif // BASE_TRACE_EVENT_HEAP_PROFILER_ALLOCATION_CONTEXT_TRACKER_H_ 90