Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(481)

Side by Side Diff: base/debug/activity_tracker.h

Issue 1980743002: Track thread activities in order to diagnose hangs. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@readwrite-mmf
Patch Set: added support for storing to disk Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 The Chromium Authors. All rights reserved.
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_METRICS_ACTIVITY_TRACKER_H_
6 #define BASE_METRICS_ACTIVITY_TRACKER_H_
7
8 #include <atomic>
9 #include <memory>
10 #include <set>
11 #include <vector>
12
13 #include "base/base_export.h"
14 #include "base/feature_list.h"
15 #include "base/files/file_path.h"
16 #include "base/metrics/persistent_memory_allocator.h"
17 #include "base/synchronization/lock.h"
18 #include "base/threading/thread_checker.h"
19 #include "base/threading/thread_local_storage.h"
20
21 namespace base {
22
23 struct PendingTask;
24
25 class Lock;
26 class MemoryMappedFile;
27
28 namespace debug {
29
30 class ThreadActivityAnalyzer;
31
32 // Enables the global activity tracker according to a field trial setting,
33 // using the specified |file| (without extension) for storing information
34 // from this run.
35 BASE_EXPORT void SetupGlobalActivityTrackerFieldTrial(const FilePath& file);
36
37
38 // This class manages tracking a stack of activities for a single thread in
39 // a persistent manner. However, in order to support an operational mode where
40 // another thread is analyzing this data in real-time, atomic operations are
41 // used where necessary to guarantee a consistent view from the outside.
42 class BASE_EXPORT ThreadActivityTracker {
43 public:
44 enum ActivityType : uint8_t {
45 ACT_TASK,
46 ACT_LOCK,
47 ACT_EVENT,
48 };
49
50 union StackEntryData {
51 struct {
52 uint64_t sequence_id;
53 } task;
54 struct {
55 uint64_t lock_id;
56 } lock;
57 struct {
58 } event;
59
60 static StackEntryData ForTask(uint64_t sequence) {
61 StackEntryData data;
62 data.task.sequence_id = sequence;
63 return data;
64 }
65
66 static StackEntryData ForLock(uint64_t lock) {
67 StackEntryData data;
68 data.lock.lock_id = 0;
69 return data;
70 }
71 };
72
73 struct StackEntry {
74 int64_t time_ticks;
75 intptr_t source_address;
76 uint8_t activity_type;
77 StackEntryData data;
78 };
79
80 class BASE_EXPORT ScopedActivity {
81 public:
82 ScopedActivity(ThreadActivityTracker* tracker,
83 const void* source,
84 ActivityType activity,
85 const StackEntryData& data)
86 : tracker_(tracker), source_(source) {
87 if (tracker_)
88 tracker_->PushActivity(source, activity, data);
89 }
90 ~ScopedActivity() {
91 if (tracker_)
92 tracker_->PopActivity(source_);
93 }
94
95 private:
96 ThreadActivityTracker* const tracker_;
97 const void* const source_;
98 };
99
100 // A ThreadActivityTracker runs on top of memory that is managed externally.
101 // It must be large enough for the internal header and a few StackEntry
102 // blocks. See SizeForStackDepth().
103 ThreadActivityTracker(void* base, size_t size);
104 virtual ~ThreadActivityTracker();
105
106 // Indicate that a method of the given (arbitrary) identifier has started.
107 void PushActivity(const void* source,
108 ActivityType activity,
109 const StackEntryData& data);
110
111 // Indicate that a method of the given (arbitrary) identifier has finished.
112 void PopActivity(const void* source);
113
114 // Returns whether the current data is valid or not. It is not valid if
115 // corruption is detected in the header or other data structures. Fetching
116 // a copy of the stack will return nothing if the data is not valid.
117 bool is_valid() { return valid_; }
118
119 // Calculates the memory size required for a given stack depth, including
120 // the internal header structure for the stack.
121 static size_t SizeForStackDepth(int stack_depth);
122
123 private:
124 friend class ThreadActivityAnalyzer;
125 friend class ActivityTrackerTest;
126
127 struct Header;
128
129 Header* const header_;
130 StackEntry* const stack_;
131 const uint32_t stack_slots_;
132
133 bool valid_ = false;
134
135 base::ThreadChecker thread_checker_;
136
137 DISALLOW_COPY_AND_ASSIGN(ThreadActivityTracker);
138 };
139
140
141 // Be sure not to create multiple Analyzers for given tracker data as parallel
142 // operation could lead to inconsistencies from concurrent synchronization with
143 // an active tracker.
144 class BASE_EXPORT ThreadActivityAnalyzer {
145 public:
146 using StackEntry = ThreadActivityTracker::StackEntry;
147
148 // Creates an analyzer for an existing activity-tracker. The passed tracker
149 // must live at least as long as the created object. The tracker may continue
150 // to be active even with an attached analyzer.
151 explicit ThreadActivityAnalyzer(ThreadActivityTracker* tracker);
152
153 // Creates an anaylzer for a block of memory held within a persistent-memory
154 // |allocator| at the given |reference|. The memory must live at least as
155 // long as the created object. It's permissable for a tracker to remain active
156 // on the memory from this thread, other threads, or even other processes.
157 // The reference must be to an object of type kTypeIdActivityTracker, above.
158 ThreadActivityAnalyzer(PersistentMemoryAllocator* allocator,
159 PersistentMemoryAllocator::Reference reference);
160
161 // Creates an anaylzer for a block of memory currently or previously in-use
162 // by an activity-tracker. The memory must live at least as long as the
163 // created object. It's permissable for a tracker to remain active on the
164 // memory from this thread, other threads, or even other processes.
165 ThreadActivityAnalyzer(void* base, size_t size);
166
167 ~ThreadActivityAnalyzer();
168
169 // Gets a copy of the current stack contents. The return value is the current
170 // depth of the stack which may be greater than the number of StackEntry
171 // records returned. If so, the returned stack has the "base" of the stack
172 // with later entries omitted.
173 uint32_t SnapshotStack(std::vector<StackEntry>* snapshot);
174
175 private:
176 ThreadActivityTracker tracker_;
177
178 DISALLOW_COPY_AND_ASSIGN(ThreadActivityAnalyzer);
179 };
180
181
182 class BASE_EXPORT GlobalActivityTracker {
183 public:
184 // Type identifiers used when storing in persistent memory so they can be
185 // identified during extraction; the first 4 bytes of the SHA1 of the name
186 // is used as a unique integer. A "version number" is added to the base
187 // so that, if the structure of that object changes, stored older versions
188 // will be safely ignored. These are public so that an external process
189 // can recognize records of this type within an allocator and use them to
190 // create ThreadActivityAnalyzer objects.
191 enum : uint32_t {
192 kTypeIdActivityTracker = 0x5D7381AF + 1, // SHA1(ActivityTracker) v1
193 kTypeIdActivityTrackerFree = 0x3F0272FB, // SHA1(ActivityTrackerFree)
194 };
195
196 class BASE_EXPORT ScopedThreadActivity
197 : public ThreadActivityTracker::ScopedActivity {
198 public:
199 ScopedThreadActivity(const void* source,
200 ThreadActivityTracker::ActivityType activity,
201 const ThreadActivityTracker::StackEntryData& data)
202 : ThreadActivityTracker::ScopedActivity(GetOrCreateTracker(),
203 source,
204 activity,
205 data) {}
206
207 private:
208 static ThreadActivityTracker* GetOrCreateTracker() {
209 GlobalActivityTracker* global_tracker = Get();
210 if (!global_tracker)
211 return nullptr;
212 return global_tracker->GetOrCreateTrackerForCurrentThread();
213 }
214 };
215
216 ~GlobalActivityTracker();
217
218 static void CreateWithAllocator(
219 std::unique_ptr<PersistentMemoryAllocator> allocator,
220 int stack_depth);
221
222 static void CreateWithLocalMemory(size_t size,
223 uint64_t id,
224 StringPiece name,
225 int stack_depth);
226
227 static void CreateWithFile(const FilePath& file_path,
228 size_t size,
229 uint64_t id,
230 StringPiece name,
231 int stack_depth);
232
233 // Gets the global activity-tracker or null if none exists.
234 static GlobalActivityTracker* Get() { return g_tracker_; }
235
236 // Gets the persistent-memory-allocator in which data is stored. Callers
237 // can store additional records here to pass additional information to
238 // the analysis process.
239 PersistentMemoryAllocator* allocator() { return allocator_.get(); }
240
241 // Gets the thread's activity-tracker, assuming it already exists. This
242 // is inline for performance reasons. Ownership remains with the global
243 // tracker.
244 ThreadActivityTracker* GetTrackerForCurrentThread() {
245 void* tracker = this_thread_tracker_.Get();
246 DCHECK(tracker);
247 return reinterpret_cast<ThreadActivityTracker*>(tracker);
248 }
249
250 // Gets the thread's activity-tracker or creates one if none exists. This
251 // is inline for performance reasons. Ownership remains with the global
252 // tracker.
253 ThreadActivityTracker* GetOrCreateTrackerForCurrentThread() {
254 void* tracker = this_thread_tracker_.Get();
255 if (tracker)
256 return reinterpret_cast<ThreadActivityTracker*>(tracker);
257 return CreateTrackerForCurrentThread();
258 }
259
260 // Creates an activity-tracker for the current thread.
261 ThreadActivityTracker* CreateTrackerForCurrentThread();
262
263 // Releases the activity-tracker for the current thread (for testing only).
264 void ReleaseTrackerForCurrentThreadForTesting();
265
266 private:
267 friend class ActivityTrackerTest;
268
269 class ManagedActivityTracker : public ThreadActivityTracker {
270 public:
271 ManagedActivityTracker(PersistentMemoryAllocator::Reference mem_reference,
272 void* base,
273 size_t size);
274 ~ManagedActivityTracker() override;
275
276 private:
277 const PersistentMemoryAllocator::Reference mem_reference_;
278 void* const mem_base_;
279 };
280
281 GlobalActivityTracker(std::unique_ptr<PersistentMemoryAllocator> allocator,
282 int stack_depth);
283
284 // Returns the memory used by an activity-tracker managed by this class.
285 void ReturnTrackerMemory(ManagedActivityTracker* tracker,
286 PersistentMemoryAllocator::Reference mem_reference,
287 void* mem_base);
288
289 static void OnTLSDestroy(void* value);
290
291 std::unique_ptr<PersistentMemoryAllocator> allocator_;
292 const size_t stack_memory_size_;
293
294 base::ThreadLocalStorage::Slot this_thread_tracker_;
295
296 Lock lock_;
297 std::set<ManagedActivityTracker*> thread_trackers_;
298 std::vector<PersistentMemoryAllocator::Reference> available_memories_;
299
300 static GlobalActivityTracker* g_tracker_;
301 };
302
303 class BASE_EXPORT ScopedTaskActivity
304 : public GlobalActivityTracker::ScopedThreadActivity {
305 public:
306 ScopedTaskActivity(const base::PendingTask& task);
307 };
308
309 } // namespace debug
310 } // namespace base
311
312 #endif // BASE_METRICS_ACTIVITY_TRACKER_H_
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698