• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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