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

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: addressed review comments Created 4 years, 7 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
« no previous file with comments | « base/base.gypi ('k') | base/debug/activity_tracker.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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
33 // Enables the global activity tracker according to a field trial setting.
34 BASE_EXPORT void SetupGlobalActivityTrackerFieldTrial();
35
36
37 // This class manages tracking a stack of activities for a single thread in
38 // a persistent manner. However, in order to support an operational mode where
39 // another thread is analyzing this data in real-time, atomic operations are
40 // used where necessary to guarantee a consistent view from the outside.
41 class BASE_EXPORT ThreadActivityTracker {
42 public:
43 enum ActivityType : uint8_t {
44 ACT_TASK,
45 ACT_LOCK,
46 ACT_EVENT,
47 };
48
49 struct StackEntry {
50 int64_t time_ticks;
51 uint8_t activity_type;
52 intptr_t source_address;
53 intptr_t method_address;
54 uint64_t sequence_id;
55 };
56
57 class BASE_EXPORT ScopedActivity {
58 public:
59 ScopedActivity(ThreadActivityTracker* tracker,
60 const void* source,
61 ActivityType activity,
62 intptr_t method,
63 uint64_t sequence)
64 : tracker_(tracker), source_(source) {
65 if (tracker_)
66 tracker_->PushActivity(source, activity, method, sequence);
67 }
68 ~ScopedActivity() {
69 if (tracker_)
70 tracker_->PopActivity(source_);
71 }
72
73 private:
74 ThreadActivityTracker* const tracker_;
75 const void* const source_;
76 };
77
78 // A ThreadActivityTracker runs on top of memory that is managed externally.
79 // It must be large enough for the internal header and a few StackEntry
80 // blocks. See SizeForStackDepth().
81 ThreadActivityTracker(void* base, size_t size);
82 virtual ~ThreadActivityTracker();
83
84 // Indicate that a method of the given (arbitrary) identifier has started.
85 void PushActivity(const void* source,
86 ActivityType activity,
87 intptr_t method,
88 uint64_t sequence);
89
90 // Indicate that a method of the given (arbitrary) identifier has finished.
91 void PopActivity(const void* source);
92
93 // Returns whether the current data is valid or not. It is not valid if
94 // corruption is detected in the header or other data structures. Fetching
95 // a copy of the stack will return nothing if the data is not valid.
96 bool is_valid() { return valid_; }
97
98 // Creates an "analysis" object for this thread tracker. The operation of
99 // the returned object is only valid as long as the tracker from which it
100 // was created continues to live.
101 std::unique_ptr<ThreadActivityAnalyzer> CreateAnalyzer();
manzagop (departed) 2016/05/20 20:24:22 I'm not sure we need this, as I don't think tracke
bcwhite 2016/05/20 20:41:18 They do for testing. :-) It could be CreateAnaly
Sigurður Ásgeirsson 2016/05/24 14:11:50 You generally want to start with the MVI - minimum
bcwhite 2016/05/26 15:35:39 Done.
102
103 // Calculates the memory size required for a given stack depth, including
104 // the internal header structure for the stack.
105 static size_t SizeForStackDepth(int stack_depth);
106
107 protected:
108 struct Header;
109
110 // Gets the header structure so derived classes can do analysis on it.
111 Header* header() { return header_; }
112
113 // Gets the stack so derived classes can do analysis on it.
114 StackEntry* stack() { return stack_; }
115
116 // Gets the number of slots in the stack.
117 uint32_t stack_slots() { return stack_slots_; }
118
119 private:
120 friend class ActivityTrackerTest;
121
122 Header* const header_;
123 StackEntry* const stack_;
124 const uint32_t stack_slots_;
125
126 bool valid_ = false;
127
128 base::ThreadChecker thread_checker_;
129
130 DISALLOW_COPY_AND_ASSIGN(ThreadActivityTracker);
131 };
132
133
134 // Be sure not to create multiple Analyzers for given tracker data as parallel
135 // operation could lead to inconsistencies from concurrent synchronization with
136 // an active tracker.
137 class BASE_EXPORT ThreadActivityAnalyzer : private ThreadActivityTracker {
manzagop (departed) 2016/05/20 20:24:22 Would it be cleaner for the analyzer not to derive
bcwhite 2016/05/20 20:41:18 Perhaps. This re-uses the initialization and vali
Sigurður Ásgeirsson 2016/05/24 14:11:50 no private inheritance in C++: https://google.gith
Sigurður Ásgeirsson 2016/05/24 14:11:50 Private inheritance is verboten in Chromium and Go
bcwhite 2016/05/26 15:35:39 Acknowledged.
138 public:
139 ThreadActivityAnalyzer(void* base, size_t size);
140 ~ThreadActivityAnalyzer() override;
141
142 // Gets a copy of the current stack contents. The return value is the current
143 // depth of the stack which may be greater than the number of StackEntry
144 // records returned. If so, the returned stack has the "base" of the stack
145 // with later entries omitted.
146 uint32_t SnapshotStack(std::vector<StackEntry>* snapshot);
147 };
148
149
150 class BASE_EXPORT GlobalActivityTracker {
151 public:
152 class BASE_EXPORT ScopedThreadActivity
153 : public ThreadActivityTracker::ScopedActivity {
154 public:
155 ScopedThreadActivity(const void* source,
156 ThreadActivityTracker::ActivityType activity,
157 intptr_t method,
158 uint64_t sequence)
159 : ThreadActivityTracker::ScopedActivity(GetOrCreateTracker(),
160 source,
161 activity,
162 method,
163 sequence) {}
164
165 private:
166 static ThreadActivityTracker* GetOrCreateTracker() {
167 GlobalActivityTracker* global_tracker = Get();
168 if (!global_tracker)
169 return nullptr;
170 return global_tracker->GetOrCreateTrackerForCurrentThread();
171 }
172 };
173
174 ~GlobalActivityTracker();
175
176 static void CreateWithAllocator(
177 std::unique_ptr<PersistentMemoryAllocator> allocator,
178 int stack_depth);
179
180 static void CreateWithLocalMemory(size_t size,
181 uint64_t id,
182 StringPiece name,
183 int stack_depth);
184
185 static void CreateWithFile(const FilePath& file_path,
186 size_t size,
187 uint64_t id,
188 StringPiece name,
189 int stack_depth);
190
191 // Gets the global activity-tracker or null if none exists.
192 static GlobalActivityTracker* Get() { return g_tracker_; }
193
194 // Gets the persistent-memory-allocator in which data is stored. Callers
195 // can store additional records here to pass additional information to
196 // the analysis process.
197 PersistentMemoryAllocator* allocator() { return allocator_.get(); }
198
199 // Gets the thread's activity-tracker, assuming it already exists. This
200 // is inline for performance reasons. Ownership remains with the global
201 // tracker.
202 ThreadActivityTracker* GetTrackerForCurrentThread() {
203 void* tracker = this_thread_tracker_.Get();
204 DCHECK(tracker);
205 return reinterpret_cast<ThreadActivityTracker*>(tracker);
206 }
207
208 // Gets the thread's activity-tracker or creates one if none exists. This
209 // is inline for performance reasons. Ownership remains with the global
210 // tracker.
211 ThreadActivityTracker* GetOrCreateTrackerForCurrentThread() {
212 void* tracker = this_thread_tracker_.Get();
213 if (tracker)
214 return reinterpret_cast<ThreadActivityTracker*>(tracker);
215 return CreateTrackerForCurrentThread();
216 }
217
218 // Creates an activity-tracker for the current thread.
219 ThreadActivityTracker* CreateTrackerForCurrentThread();
220
221 // Releases the activity-tracker for the current thread (for testing only).
222 void ReleaseTrackerForCurrentThreadForTesting();
223
224 private:
225 friend class ActivityTrackerTest;
226
227 class ManagedActivityTracker : public ThreadActivityTracker {
228 public:
229 ManagedActivityTracker(PersistentMemoryAllocator::Reference mem_reference,
230 void* base,
231 size_t size);
232 ~ManagedActivityTracker() override;
233
234 private:
235 const PersistentMemoryAllocator::Reference mem_reference_;
236 void* const mem_base_;
237 };
238
239 GlobalActivityTracker(std::unique_ptr<PersistentMemoryAllocator> allocator,
240 int stack_depth);
241
242 // Returns the memory used by an activity-tracker managed by this class.
243 void ReturnTrackerMemory(ManagedActivityTracker* tracker,
244 PersistentMemoryAllocator::Reference mem_reference,
245 void* mem_base);
246
247 static void OnTLSDestroy(void* value);
248
249 std::unique_ptr<PersistentMemoryAllocator> allocator_;
250 const size_t stack_memory_;
251
252 base::ThreadLocalStorage::Slot this_thread_tracker_;
253
254 Lock lock_;
255 std::set<ManagedActivityTracker*> thread_trackers_;
256 std::vector<PersistentMemoryAllocator::Reference> available_memories_;
257
258 static GlobalActivityTracker* g_tracker_;
259 };
260
261 class BASE_EXPORT ScopedTaskActivity
262 : public GlobalActivityTracker::ScopedThreadActivity {
263 public:
264 ScopedTaskActivity(const base::PendingTask& task);
265 };
266
267 } // namespace debug
268 } // namespace base
269
270 #endif // BASE_METRICS_ACTIVITY_TRACKER_H_
OLDNEW
« no previous file with comments | « base/base.gypi ('k') | base/debug/activity_tracker.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698