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

Side by Side Diff: base/debug/activity_analyzer.cc

Issue 2754483002: Add analyzer support for multiple processes. (Closed)
Patch Set: addressed review comments by manzagop Created 3 years, 8 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/debug/activity_analyzer.h ('k') | base/debug/activity_analyzer_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/debug/activity_analyzer.h" 5 #include "base/debug/activity_analyzer.h"
6 6
7 #include <algorithm>
8
7 #include "base/files/file.h" 9 #include "base/files/file.h"
8 #include "base/files/file_path.h" 10 #include "base/files/file_path.h"
9 #include "base/files/memory_mapped_file.h" 11 #include "base/files/memory_mapped_file.h"
12 #include "base/lazy_instance.h"
10 #include "base/logging.h" 13 #include "base/logging.h"
11 #include "base/memory/ptr_util.h" 14 #include "base/memory/ptr_util.h"
12 #include "base/stl_util.h" 15 #include "base/stl_util.h"
13 #include "base/strings/string_util.h" 16 #include "base/strings/string_util.h"
14 17
15 namespace base { 18 namespace base {
16 namespace debug { 19 namespace debug {
17 20
21 namespace {
22 // An empty snapshot that can be returned when there otherwise is none.
23 LazyInstance<ActivityUserData::Snapshot>::Leaky g_empty_user_data_snapshot;
24 } // namespace
25
18 ThreadActivityAnalyzer::Snapshot::Snapshot() {} 26 ThreadActivityAnalyzer::Snapshot::Snapshot() {}
19 ThreadActivityAnalyzer::Snapshot::~Snapshot() {} 27 ThreadActivityAnalyzer::Snapshot::~Snapshot() {}
20 28
21 ThreadActivityAnalyzer::ThreadActivityAnalyzer( 29 ThreadActivityAnalyzer::ThreadActivityAnalyzer(
22 const ThreadActivityTracker& tracker) 30 const ThreadActivityTracker& tracker)
23 : activity_snapshot_valid_(tracker.CreateSnapshot(&activity_snapshot_)) {} 31 : activity_snapshot_valid_(tracker.CreateSnapshot(&activity_snapshot_)) {}
24 32
25 ThreadActivityAnalyzer::ThreadActivityAnalyzer(void* base, size_t size) 33 ThreadActivityAnalyzer::ThreadActivityAnalyzer(void* base, size_t size)
26 : ThreadActivityAnalyzer(ThreadActivityTracker(base, size)) {} 34 : ThreadActivityAnalyzer(ThreadActivityTracker(base, size)) {}
27 35
(...skipping 13 matching lines...) Expand all
41 if (!IsValid()) 49 if (!IsValid())
42 return; 50 return;
43 51
44 // User-data is held at the global scope even though it's referenced at the 52 // User-data is held at the global scope even though it's referenced at the
45 // thread scope. 53 // thread scope.
46 activity_snapshot_.user_data_stack.clear(); 54 activity_snapshot_.user_data_stack.clear();
47 for (auto& activity : activity_snapshot_.activity_stack) { 55 for (auto& activity : activity_snapshot_.activity_stack) {
48 // The global GetUserDataSnapshot will return an empty snapshot if the ref 56 // The global GetUserDataSnapshot will return an empty snapshot if the ref
49 // or id is not valid. 57 // or id is not valid.
50 activity_snapshot_.user_data_stack.push_back(global->GetUserDataSnapshot( 58 activity_snapshot_.user_data_stack.push_back(global->GetUserDataSnapshot(
51 activity.user_data_ref, activity.user_data_id)); 59 activity_snapshot_.process_id, activity.user_data_ref,
60 activity.user_data_id));
52 } 61 }
53 } 62 }
54 63
55 GlobalActivityAnalyzer::GlobalActivityAnalyzer( 64 GlobalActivityAnalyzer::GlobalActivityAnalyzer(
56 std::unique_ptr<PersistentMemoryAllocator> allocator) 65 std::unique_ptr<PersistentMemoryAllocator> allocator)
57 : allocator_(std::move(allocator)), allocator_iterator_(allocator_.get()) {} 66 : allocator_(std::move(allocator)), allocator_iterator_(allocator_.get()) {}
58 67
59 GlobalActivityAnalyzer::~GlobalActivityAnalyzer() {} 68 GlobalActivityAnalyzer::~GlobalActivityAnalyzer() {}
60 69
61 #if !defined(OS_NACL) 70 #if !defined(OS_NACL)
62 // static 71 // static
63 std::unique_ptr<GlobalActivityAnalyzer> GlobalActivityAnalyzer::CreateWithFile( 72 std::unique_ptr<GlobalActivityAnalyzer> GlobalActivityAnalyzer::CreateWithFile(
64 const FilePath& file_path) { 73 const FilePath& file_path) {
65 // Map the file read-write so it can guarantee consistency between 74 // Map the file read-write so it can guarantee consistency between
66 // the analyzer and any trackers that my still be active. 75 // the analyzer and any trackers that my still be active.
67 std::unique_ptr<MemoryMappedFile> mmfile(new MemoryMappedFile()); 76 std::unique_ptr<MemoryMappedFile> mmfile(new MemoryMappedFile());
68 mmfile->Initialize(file_path, MemoryMappedFile::READ_WRITE); 77 mmfile->Initialize(file_path, MemoryMappedFile::READ_WRITE);
69 if (!mmfile->IsValid()) 78 if (!mmfile->IsValid())
70 return nullptr; 79 return nullptr;
71 80
72 if (!FilePersistentMemoryAllocator::IsFileAcceptable(*mmfile, true)) 81 if (!FilePersistentMemoryAllocator::IsFileAcceptable(*mmfile, true))
73 return nullptr; 82 return nullptr;
74 83
75 return WrapUnique( 84 return WrapUnique(
76 new GlobalActivityAnalyzer(MakeUnique<FilePersistentMemoryAllocator>( 85 new GlobalActivityAnalyzer(MakeUnique<FilePersistentMemoryAllocator>(
77 std::move(mmfile), 0, 0, base::StringPiece(), true))); 86 std::move(mmfile), 0, 0, base::StringPiece(), true)));
78 } 87 }
79 #endif // !defined(OS_NACL) 88 #endif // !defined(OS_NACL)
80 89
81 ThreadActivityAnalyzer* GlobalActivityAnalyzer::GetFirstAnalyzer() { 90 int64_t GlobalActivityAnalyzer::GetFirstProcess() {
82 PrepareAllAnalyzers(); 91 PrepareAllAnalyzers();
92 return GetNextProcess();
93 }
94
95 int64_t GlobalActivityAnalyzer::GetNextProcess() {
96 if (process_ids_.empty())
97 return 0;
98 int64_t pid = process_ids_.back();
99 process_ids_.pop_back();
100 return pid;
101 }
102
103 ThreadActivityAnalyzer* GlobalActivityAnalyzer::GetFirstAnalyzer(int64_t pid) {
83 analyzers_iterator_ = analyzers_.begin(); 104 analyzers_iterator_ = analyzers_.begin();
105 analyzers_iterator_pid_ = pid;
84 if (analyzers_iterator_ == analyzers_.end()) 106 if (analyzers_iterator_ == analyzers_.end())
85 return nullptr; 107 return nullptr;
86 return analyzers_iterator_->second.get(); 108 int64_t create_stamp;
109 if (analyzers_iterator_->second->GetProcessId(&create_stamp) == pid &&
110 create_stamp <= analysis_stamp_) {
111 return analyzers_iterator_->second.get();
112 }
113 return GetNextAnalyzer();
87 } 114 }
88 115
89 ThreadActivityAnalyzer* GlobalActivityAnalyzer::GetNextAnalyzer() { 116 ThreadActivityAnalyzer* GlobalActivityAnalyzer::GetNextAnalyzer() {
90 DCHECK(analyzers_iterator_ != analyzers_.end()); 117 DCHECK(analyzers_iterator_ != analyzers_.end());
91 ++analyzers_iterator_; 118 int64_t create_stamp;
92 if (analyzers_iterator_ == analyzers_.end()) 119 do {
93 return nullptr; 120 ++analyzers_iterator_;
121 if (analyzers_iterator_ == analyzers_.end())
122 return nullptr;
123 } while (analyzers_iterator_->second->GetProcessId(&create_stamp) !=
124 analyzers_iterator_pid_ ||
125 create_stamp > analysis_stamp_);
94 return analyzers_iterator_->second.get(); 126 return analyzers_iterator_->second.get();
95 } 127 }
96 128
97 ThreadActivityAnalyzer* GlobalActivityAnalyzer::GetAnalyzerForThread( 129 ThreadActivityAnalyzer* GlobalActivityAnalyzer::GetAnalyzerForThread(
98 const ThreadKey& key) { 130 const ThreadKey& key) {
99 auto found = analyzers_.find(key); 131 auto found = analyzers_.find(key);
100 if (found == analyzers_.end()) 132 if (found == analyzers_.end())
101 return nullptr; 133 return nullptr;
102 return found->second.get(); 134 return found->second.get();
103 } 135 }
104 136
105 ActivityUserData::Snapshot GlobalActivityAnalyzer::GetUserDataSnapshot( 137 ActivityUserData::Snapshot GlobalActivityAnalyzer::GetUserDataSnapshot(
138 int64_t pid,
106 uint32_t ref, 139 uint32_t ref,
107 uint32_t id) { 140 uint32_t id) {
108 ActivityUserData::Snapshot snapshot; 141 ActivityUserData::Snapshot snapshot;
109 142
110 void* memory = allocator_->GetAsArray<char>( 143 void* memory = allocator_->GetAsArray<char>(
111 ref, GlobalActivityTracker::kTypeIdUserDataRecord, 144 ref, GlobalActivityTracker::kTypeIdUserDataRecord,
112 PersistentMemoryAllocator::kSizeAny); 145 PersistentMemoryAllocator::kSizeAny);
113 if (memory) { 146 if (memory) {
114 size_t size = allocator_->GetAllocSize(ref); 147 size_t size = allocator_->GetAllocSize(ref);
115 const ActivityUserData user_data(memory, size); 148 const ActivityUserData user_data(memory, size);
116 user_data.CreateSnapshot(&snapshot); 149 user_data.CreateSnapshot(&snapshot);
117 if (user_data.id() != id) { 150 int64_t process_id;
151 int64_t create_stamp;
152 if (!ActivityUserData::GetOwningProcessId(memory, &process_id,
153 &create_stamp) ||
154 process_id != pid || user_data.id() != id) {
118 // This allocation has been overwritten since it was created. Return an 155 // This allocation has been overwritten since it was created. Return an
119 // empty snapshot because whatever was captured is incorrect. 156 // empty snapshot because whatever was captured is incorrect.
120 snapshot.clear(); 157 snapshot.clear();
121 } 158 }
122 } 159 }
123 160
124 return snapshot; 161 return snapshot;
125 } 162 }
126 163
127 ActivityUserData::Snapshot GlobalActivityAnalyzer::GetGlobalUserDataSnapshot() { 164 const ActivityUserData::Snapshot&
128 ActivityUserData::Snapshot snapshot; 165 GlobalActivityAnalyzer::GetProcessDataSnapshot(int64_t pid) {
166 auto iter = process_data_.find(pid);
167 if (iter == process_data_.end())
168 return g_empty_user_data_snapshot.Get();
169 if (iter->second.create_stamp > analysis_stamp_)
170 return g_empty_user_data_snapshot.Get();
171 DCHECK_EQ(pid, iter->second.process_id);
172 return iter->second.data;
173 }
174
175 const ActivityUserData::Snapshot&
176 GlobalActivityAnalyzer::GetGlobalDataSnapshot() {
177 global_data_snapshot_.clear();
129 178
130 PersistentMemoryAllocator::Reference ref = 179 PersistentMemoryAllocator::Reference ref =
131 PersistentMemoryAllocator::Iterator(allocator_.get()) 180 PersistentMemoryAllocator::Iterator(allocator_.get())
132 .GetNextOfType(GlobalActivityTracker::kTypeIdGlobalDataRecord); 181 .GetNextOfType(GlobalActivityTracker::kTypeIdGlobalDataRecord);
133 void* memory = allocator_->GetAsArray<char>( 182 void* memory = allocator_->GetAsArray<char>(
134 ref, GlobalActivityTracker::kTypeIdGlobalDataRecord, 183 ref, GlobalActivityTracker::kTypeIdGlobalDataRecord,
135 PersistentMemoryAllocator::kSizeAny); 184 PersistentMemoryAllocator::kSizeAny);
136 if (memory) { 185 if (memory) {
137 size_t size = allocator_->GetAllocSize(ref); 186 size_t size = allocator_->GetAllocSize(ref);
138 const ActivityUserData global_data(memory, size); 187 const ActivityUserData global_data(memory, size);
139 global_data.CreateSnapshot(&snapshot); 188 global_data.CreateSnapshot(&global_data_snapshot_);
140 } 189 }
141 190
142 return snapshot; 191 return global_data_snapshot_;
143 } 192 }
144 193
145 std::vector<std::string> GlobalActivityAnalyzer::GetLogMessages() { 194 std::vector<std::string> GlobalActivityAnalyzer::GetLogMessages() {
146 std::vector<std::string> messages; 195 std::vector<std::string> messages;
147 PersistentMemoryAllocator::Reference ref; 196 PersistentMemoryAllocator::Reference ref;
148 197
149 PersistentMemoryAllocator::Iterator iter(allocator_.get()); 198 PersistentMemoryAllocator::Iterator iter(allocator_.get());
150 while ((ref = iter.GetNextOfType( 199 while ((ref = iter.GetNextOfType(
151 GlobalActivityTracker::kTypeIdGlobalLogMessage)) != 0) { 200 GlobalActivityTracker::kTypeIdGlobalLogMessage)) != 0) {
152 const char* message = allocator_->GetAsArray<char>( 201 const char* message = allocator_->GetAsArray<char>(
(...skipping 25 matching lines...) Expand all
178 227
179 return modules; 228 return modules;
180 } 229 }
181 230
182 GlobalActivityAnalyzer::ProgramLocation 231 GlobalActivityAnalyzer::ProgramLocation
183 GlobalActivityAnalyzer::GetProgramLocationFromAddress(uint64_t address) { 232 GlobalActivityAnalyzer::GetProgramLocationFromAddress(uint64_t address) {
184 // TODO(bcwhite): Implement this. 233 // TODO(bcwhite): Implement this.
185 return { 0, 0 }; 234 return { 0, 0 };
186 } 235 }
187 236
237 GlobalActivityAnalyzer::UserDataSnapshot::UserDataSnapshot() {}
238 GlobalActivityAnalyzer::UserDataSnapshot::UserDataSnapshot(
239 const UserDataSnapshot& rhs) = default;
240 GlobalActivityAnalyzer::UserDataSnapshot::UserDataSnapshot(
241 UserDataSnapshot&& rhs) = default;
242 GlobalActivityAnalyzer::UserDataSnapshot::~UserDataSnapshot() {}
243
188 void GlobalActivityAnalyzer::PrepareAllAnalyzers() { 244 void GlobalActivityAnalyzer::PrepareAllAnalyzers() {
245 // Record the time when analysis started.
246 analysis_stamp_ = base::Time::Now().ToInternalValue();
247
189 // Fetch all the records. This will retrieve only ones created since the 248 // Fetch all the records. This will retrieve only ones created since the
190 // last run since the PMA iterator will continue from where it left off. 249 // last run since the PMA iterator will continue from where it left off.
191 uint32_t type; 250 uint32_t type;
192 PersistentMemoryAllocator::Reference ref; 251 PersistentMemoryAllocator::Reference ref;
193 while ((ref = allocator_iterator_.GetNext(&type)) != 0) { 252 while ((ref = allocator_iterator_.GetNext(&type)) != 0) {
194 switch (type) { 253 switch (type) {
195 case GlobalActivityTracker::kTypeIdActivityTracker: 254 case GlobalActivityTracker::kTypeIdActivityTracker:
196 case GlobalActivityTracker::kTypeIdActivityTrackerFree: 255 case GlobalActivityTracker::kTypeIdActivityTrackerFree:
197 // Free or not, add it to the list of references for later analysis. 256 case GlobalActivityTracker::kTypeIdProcessDataRecord:
198 tracker_references_.insert(ref); 257 case GlobalActivityTracker::kTypeIdProcessDataRecordFree:
258 case PersistentMemoryAllocator::kTypeIdTransitioning:
259 // Active, free, or transitioning: add it to the list of references
260 // for later analysis.
261 memory_references_.insert(ref);
199 break; 262 break;
200 } 263 }
201 } 264 }
202 265
203 // Go through all the known references and create analyzers for them with 266 // Clear out any old information.
267 analyzers_.clear();
268 process_data_.clear();
269 process_ids_.clear();
270 std::set<int64_t> seen_pids;
271
272 // Go through all the known references and create objects for them with
204 // snapshots of the current state. 273 // snapshots of the current state.
205 analyzers_.clear(); 274 for (PersistentMemoryAllocator::Reference memory_ref : memory_references_) {
206 for (PersistentMemoryAllocator::Reference tracker_ref : tracker_references_) { 275 // Get the actual data segment for the tracker. Any type will do since it
207 // Get the actual data segment for the tracker. This can fail if the 276 // is checked below.
208 // record has been marked "free" since the type will not match. 277 void* const base = allocator_->GetAsArray<char>(
209 void* base = allocator_->GetAsArray<char>( 278 memory_ref, PersistentMemoryAllocator::kTypeIdAny,
210 tracker_ref, GlobalActivityTracker::kTypeIdActivityTracker,
211 PersistentMemoryAllocator::kSizeAny); 279 PersistentMemoryAllocator::kSizeAny);
280 const size_t size = allocator_->GetAllocSize(memory_ref);
212 if (!base) 281 if (!base)
213 continue; 282 continue;
214 283
215 // Create the analyzer on the data. This will capture a snapshot of the 284 switch (allocator_->GetType(memory_ref)) {
216 // tracker state. This can fail if the tracker is somehow corrupted or is 285 case GlobalActivityTracker::kTypeIdActivityTracker: {
217 // in the process of shutting down. 286 // Create the analyzer on the data. This will capture a snapshot of the
218 std::unique_ptr<ThreadActivityAnalyzer> analyzer(new ThreadActivityAnalyzer( 287 // tracker state. This can fail if the tracker is somehow corrupted or
219 base, allocator_->GetAllocSize(tracker_ref))); 288 // is in the process of shutting down.
220 if (!analyzer->IsValid()) 289 std::unique_ptr<ThreadActivityAnalyzer> analyzer(
221 continue; 290 new ThreadActivityAnalyzer(base, size));
222 analyzer->AddGlobalInformation(this); 291 if (!analyzer->IsValid())
292 continue;
293 analyzer->AddGlobalInformation(this);
223 294
224 // Add this analyzer to the map of known ones, indexed by a unique thread 295 // Track PIDs.
225 // identifier. 296 int64_t pid = analyzer->GetProcessId();
226 DCHECK(!base::ContainsKey(analyzers_, analyzer->GetThreadKey())); 297 if (seen_pids.find(pid) == seen_pids.end()) {
227 analyzer->allocator_reference_ = ref; 298 process_ids_.push_back(pid);
228 analyzers_[analyzer->GetThreadKey()] = std::move(analyzer); 299 seen_pids.insert(pid);
300 }
301
302 // Add this analyzer to the map of known ones, indexed by a unique
303 // thread
304 // identifier.
305 DCHECK(!base::ContainsKey(analyzers_, analyzer->GetThreadKey()));
306 analyzer->allocator_reference_ = ref;
307 analyzers_[analyzer->GetThreadKey()] = std::move(analyzer);
308 } break;
309
310 case GlobalActivityTracker::kTypeIdProcessDataRecord: {
311 // Get the PID associated with this data record.
312 int64_t process_id;
313 int64_t create_stamp;
314 ActivityUserData::GetOwningProcessId(base, &process_id, &create_stamp);
315 DCHECK(!base::ContainsKey(process_data_, process_id));
316
317 // Create a snapshot of the data. This can fail if the data is somehow
318 // corrupted or the process shutdown and the memory being released.
319 UserDataSnapshot& snapshot = process_data_[process_id];
320 snapshot.process_id = process_id;
321 snapshot.create_stamp = create_stamp;
322 const ActivityUserData process_data(base, size);
323 if (!process_data.CreateSnapshot(&snapshot.data))
324 break;
325
326 // Check that nothing changed. If it did, forget what was recorded.
327 ActivityUserData::GetOwningProcessId(base, &process_id, &create_stamp);
328 if (process_id != snapshot.process_id ||
329 create_stamp != snapshot.create_stamp) {
330 process_data_.erase(process_id);
331 break;
332 }
333
334 // Track PIDs.
335 if (seen_pids.find(process_id) == seen_pids.end()) {
336 process_ids_.push_back(process_id);
337 seen_pids.insert(process_id);
338 }
339 } break;
340 }
229 } 341 }
342
343 // Reverse the list of PIDs so that they get popped in the order found.
344 std::reverse(process_ids_.begin(), process_ids_.end());
230 } 345 }
231 346
232 } // namespace debug 347 } // namespace debug
233 } // namespace base 348 } // namespace base
OLDNEW
« no previous file with comments | « base/debug/activity_analyzer.h ('k') | base/debug/activity_analyzer_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698