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

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

Issue 2754483002: Add analyzer support for multiple processes. (Closed)
Patch Set: rebased Created 3 years, 9 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
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();
84 if (analyzers_iterator_ == analyzers_.end()) 105 if (analyzers_iterator_ == analyzers_.end())
85 return nullptr; 106 return nullptr;
107 int64_t create_stamp;
108 if (analyzers_iterator_->second->GetProcessId(&create_stamp) == pid &&
109 create_stamp <= analysis_stamp_) {
110 return analyzers_iterator_->second.get();
111 }
112 return GetNextAnalyzer(pid);
113 }
114
115 ThreadActivityAnalyzer* GlobalActivityAnalyzer::GetNextAnalyzer(int64_t pid) {
116 DCHECK(analyzers_iterator_ != analyzers_.end());
117 int64_t create_stamp;
118 do {
119 ++analyzers_iterator_;
120 if (analyzers_iterator_ == analyzers_.end())
121 return nullptr;
122 } while (analyzers_iterator_->second->GetProcessId(&create_stamp) != pid &&
123 create_stamp <= analysis_stamp_);
manzagop (departed) 2017/03/21 21:10:05 Not sure I follow this condition. Should it be "wh
bcwhite 2017/03/29 22:00:51 Done.
86 return analyzers_iterator_->second.get(); 124 return analyzers_iterator_->second.get();
87 } 125 }
88 126
89 ThreadActivityAnalyzer* GlobalActivityAnalyzer::GetNextAnalyzer() {
90 DCHECK(analyzers_iterator_ != analyzers_.end());
91 ++analyzers_iterator_;
92 if (analyzers_iterator_ == analyzers_.end())
93 return nullptr;
94 return analyzers_iterator_->second.get();
95 }
96
97 ThreadActivityAnalyzer* GlobalActivityAnalyzer::GetAnalyzerForThread( 127 ThreadActivityAnalyzer* GlobalActivityAnalyzer::GetAnalyzerForThread(
98 const ThreadKey& key) { 128 const ThreadKey& key) {
99 auto found = analyzers_.find(key); 129 auto found = analyzers_.find(key);
100 if (found == analyzers_.end()) 130 if (found == analyzers_.end())
101 return nullptr; 131 return nullptr;
102 return found->second.get(); 132 return found->second.get();
103 } 133 }
104 134
105 ActivityUserData::Snapshot GlobalActivityAnalyzer::GetUserDataSnapshot( 135 ActivityUserData::Snapshot GlobalActivityAnalyzer::GetUserDataSnapshot(
136 int64_t pid,
106 uint32_t ref, 137 uint32_t ref,
107 uint32_t id) { 138 uint32_t id) {
108 ActivityUserData::Snapshot snapshot; 139 ActivityUserData::Snapshot snapshot;
109 140
110 void* memory = allocator_->GetAsArray<char>( 141 void* memory = allocator_->GetAsArray<char>(
111 ref, GlobalActivityTracker::kTypeIdUserDataRecord, 142 ref, GlobalActivityTracker::kTypeIdUserDataRecord,
112 PersistentMemoryAllocator::kSizeAny); 143 PersistentMemoryAllocator::kSizeAny);
113 if (memory) { 144 if (memory) {
114 size_t size = allocator_->GetAllocSize(ref); 145 size_t size = allocator_->GetAllocSize(ref);
115 const ActivityUserData user_data(memory, size); 146 const ActivityUserData user_data(memory, size);
116 user_data.CreateSnapshot(&snapshot); 147 user_data.CreateSnapshot(&snapshot);
117 if (user_data.id() != id) { 148 ProcessId process_id;
149 int64_t create_stamp;
150 if (!ActivityUserData::GetOwningProcessId(memory, &process_id,
151 &create_stamp) ||
152 process_id != pid || user_data.id() != id) {
118 // This allocation has been overwritten since it was created. Return an 153 // This allocation has been overwritten since it was created. Return an
119 // empty snapshot because whatever was captured is incorrect. 154 // empty snapshot because whatever was captured is incorrect.
120 snapshot.clear(); 155 snapshot.clear();
121 } 156 }
122 } 157 }
123 158
124 return snapshot; 159 return snapshot;
125 } 160 }
126 161
127 ActivityUserData::Snapshot GlobalActivityAnalyzer::GetGlobalUserDataSnapshot() { 162 const ActivityUserData::Snapshot&
128 ActivityUserData::Snapshot snapshot; 163 GlobalActivityAnalyzer::GetProcessDataSnapshot(int64_t pid) {
164 auto iter = process_data_.find(pid);
165 if (iter == process_data_.end())
166 return g_empty_user_data_snapshot.Get();
167 if (iter->second.create_stamp > analysis_stamp_)
168 return g_empty_user_data_snapshot.Get();
169 DCHECK_EQ(pid, iter->second.process_id);
170 return iter->second.data;
171 }
172
173 const ActivityUserData::Snapshot&
174 GlobalActivityAnalyzer::GetGlobalDataSnapshot() {
175 global_data_snapshot_.clear();
129 176
130 PersistentMemoryAllocator::Reference ref = 177 PersistentMemoryAllocator::Reference ref =
131 PersistentMemoryAllocator::Iterator(allocator_.get()) 178 PersistentMemoryAllocator::Iterator(allocator_.get())
132 .GetNextOfType(GlobalActivityTracker::kTypeIdGlobalDataRecord); 179 .GetNextOfType(GlobalActivityTracker::kTypeIdGlobalDataRecord);
133 void* memory = allocator_->GetAsArray<char>( 180 void* memory = allocator_->GetAsArray<char>(
134 ref, GlobalActivityTracker::kTypeIdGlobalDataRecord, 181 ref, GlobalActivityTracker::kTypeIdGlobalDataRecord,
135 PersistentMemoryAllocator::kSizeAny); 182 PersistentMemoryAllocator::kSizeAny);
136 if (memory) { 183 if (memory) {
137 size_t size = allocator_->GetAllocSize(ref); 184 size_t size = allocator_->GetAllocSize(ref);
138 const ActivityUserData global_data(memory, size); 185 const ActivityUserData global_data(memory, size);
139 global_data.CreateSnapshot(&snapshot); 186 global_data.CreateSnapshot(&global_data_snapshot_);
140 } 187 }
141 188
142 return snapshot; 189 return global_data_snapshot_;
143 } 190 }
144 191
145 std::vector<std::string> GlobalActivityAnalyzer::GetLogMessages() { 192 std::vector<std::string> GlobalActivityAnalyzer::GetLogMessages() {
146 std::vector<std::string> messages; 193 std::vector<std::string> messages;
147 PersistentMemoryAllocator::Reference ref; 194 PersistentMemoryAllocator::Reference ref;
148 195
149 PersistentMemoryAllocator::Iterator iter(allocator_.get()); 196 PersistentMemoryAllocator::Iterator iter(allocator_.get());
150 while ((ref = iter.GetNextOfType( 197 while ((ref = iter.GetNextOfType(
151 GlobalActivityTracker::kTypeIdGlobalLogMessage)) != 0) { 198 GlobalActivityTracker::kTypeIdGlobalLogMessage)) != 0) {
152 const char* message = allocator_->GetAsArray<char>( 199 const char* message = allocator_->GetAsArray<char>(
(...skipping 25 matching lines...) Expand all
178 225
179 return modules; 226 return modules;
180 } 227 }
181 228
182 GlobalActivityAnalyzer::ProgramLocation 229 GlobalActivityAnalyzer::ProgramLocation
183 GlobalActivityAnalyzer::GetProgramLocationFromAddress(uint64_t address) { 230 GlobalActivityAnalyzer::GetProgramLocationFromAddress(uint64_t address) {
184 // TODO(bcwhite): Implement this. 231 // TODO(bcwhite): Implement this.
185 return { 0, 0 }; 232 return { 0, 0 };
186 } 233 }
187 234
235 GlobalActivityAnalyzer::UserDataSnapshot::UserDataSnapshot() {}
236 GlobalActivityAnalyzer::UserDataSnapshot::UserDataSnapshot(
237 const UserDataSnapshot& rhs) = default;
238 GlobalActivityAnalyzer::UserDataSnapshot::UserDataSnapshot(
239 UserDataSnapshot&& rhs) = default;
240 GlobalActivityAnalyzer::UserDataSnapshot::~UserDataSnapshot() {}
241
188 void GlobalActivityAnalyzer::PrepareAllAnalyzers() { 242 void GlobalActivityAnalyzer::PrepareAllAnalyzers() {
243 // Record the time when analysis started.
244 analysis_stamp_ = base::Time::Now().ToInternalValue();
245
189 // Fetch all the records. This will retrieve only ones created since the 246 // 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. 247 // last run since the PMA iterator will continue from where it left off.
191 uint32_t type; 248 uint32_t type;
192 PersistentMemoryAllocator::Reference ref; 249 PersistentMemoryAllocator::Reference ref;
193 while ((ref = allocator_iterator_.GetNext(&type)) != 0) { 250 while ((ref = allocator_iterator_.GetNext(&type)) != 0) {
194 switch (type) { 251 switch (type) {
195 case GlobalActivityTracker::kTypeIdActivityTracker: 252 case GlobalActivityTracker::kTypeIdActivityTracker:
196 case GlobalActivityTracker::kTypeIdActivityTrackerFree: 253 case GlobalActivityTracker::kTypeIdActivityTrackerFree:
197 // Free or not, add it to the list of references for later analysis. 254 case GlobalActivityTracker::kTypeIdProcessDataRecord:
198 tracker_references_.insert(ref); 255 case GlobalActivityTracker::kTypeIdProcessDataRecordFree:
256 case PersistentMemoryAllocator::kTypeIdTransitioning:
257 // Active, free, or transitioning: add it to the list of references
258 // for later analysis.
259 memory_references_.insert(ref);
199 break; 260 break;
200 } 261 }
201 } 262 }
202 263
203 // Go through all the known references and create analyzers for them with 264 // Clear out any old information.
265 analyzers_.clear();
266 process_data_.clear();
267 process_ids_.clear();
268 std::set<int64_t> seen_pids;
269
270 // Go through all the known references and create objects for them with
204 // snapshots of the current state. 271 // snapshots of the current state.
205 analyzers_.clear(); 272 for (PersistentMemoryAllocator::Reference memory_ref : memory_references_) {
206 for (PersistentMemoryAllocator::Reference tracker_ref : tracker_references_) {
207 // Get the actual data segment for the tracker. This can fail if the 273 // Get the actual data segment for the tracker. This can fail if the
208 // record has been marked "free" since the type will not match. 274 // record has been marked "free" since the type will not match.
manzagop (departed) 2017/03/21 21:10:05 Update comment: retrieval of kTypeIdAny can't fail
bcwhite 2017/03/29 22:00:51 Done.
209 void* base = allocator_->GetAsArray<char>( 275 void* const base = allocator_->GetAsArray<char>(
210 tracker_ref, GlobalActivityTracker::kTypeIdActivityTracker, 276 memory_ref, 0, PersistentMemoryAllocator::kSizeAny);
manzagop (departed) 2017/03/21 21:10:05 Is 0 the same as kTypeIdAny?
bcwhite 2017/03/29 22:00:51 Done.
211 PersistentMemoryAllocator::kSizeAny); 277 const size_t size = allocator_->GetAllocSize(memory_ref);
212 if (!base) 278 if (!base)
213 continue; 279 continue;
214 280
215 // Create the analyzer on the data. This will capture a snapshot of the 281 switch (allocator_->GetType(memory_ref)) {
216 // tracker state. This can fail if the tracker is somehow corrupted or is 282 case GlobalActivityTracker::kTypeIdActivityTracker: {
217 // in the process of shutting down. 283 // Create the analyzer on the data. This will capture a snapshot of the
218 std::unique_ptr<ThreadActivityAnalyzer> analyzer(new ThreadActivityAnalyzer( 284 // tracker state. This can fail if the tracker is somehow corrupted or
219 base, allocator_->GetAllocSize(tracker_ref))); 285 // is in the process of shutting down.
220 if (!analyzer->IsValid()) 286 std::unique_ptr<ThreadActivityAnalyzer> analyzer(
221 continue; 287 new ThreadActivityAnalyzer(base, size));
222 analyzer->AddGlobalInformation(this); 288 if (!analyzer->IsValid())
289 continue;
290 analyzer->AddGlobalInformation(this);
223 291
224 // Add this analyzer to the map of known ones, indexed by a unique thread 292 // Track PIDs.
225 // identifier. 293 int64_t pid = analyzer->GetProcessId();
226 DCHECK(!base::ContainsKey(analyzers_, analyzer->GetThreadKey())); 294 if (seen_pids.find(pid) == seen_pids.end()) {
227 analyzer->allocator_reference_ = ref; 295 process_ids_.push_back(pid);
228 analyzers_[analyzer->GetThreadKey()] = std::move(analyzer); 296 seen_pids.insert(pid);
297 }
298
299 // Add this analyzer to the map of known ones, indexed by a unique
300 // thread
301 // identifier.
302 DCHECK(!base::ContainsKey(analyzers_, analyzer->GetThreadKey()));
303 analyzer->allocator_reference_ = ref;
304 analyzers_[analyzer->GetThreadKey()] = std::move(analyzer);
305 } break;
306
307 case GlobalActivityTracker::kTypeIdProcessDataRecord: {
manzagop (departed) 2017/03/21 21:10:05 Looks like a process that had no threads won't be
bcwhite 2017/03/29 22:00:51 Done.
308 // Get the PID associated with this data record.
309 ProcessId process_id;
310 int64_t create_stamp;
311 ActivityUserData::GetOwningProcessId(base, &process_id, &create_stamp);
312
313 // Create a snapshot of the data. This can fail if the data is somehow
314 // corrupted or the process shutdown and the memory being released.
315 UserDataSnapshot& snapshot = process_data_[process_id];
316 snapshot.process_id = process_id;
317 snapshot.create_stamp = create_stamp;
318 const ActivityUserData process_data(base, size);
319 if (!process_data.CreateSnapshot(&snapshot.data))
320 break;
321
322 // Check that nothing changed. If it did, forget what was recorded.
323 ActivityUserData::GetOwningProcessId(base, &process_id, &create_stamp);
324 if (process_id != snapshot.process_id ||
325 create_stamp != snapshot.create_stamp) {
326 process_data_.erase(process_id);
327 }
328 } break;
329 }
229 } 330 }
331
332 // Reverse the list of PIDs so that they get popped in the order found.
manzagop (departed) 2017/03/21 21:10:05 Is the order important? We don't seem to care abou
bcwhite 2017/03/29 22:00:51 There has to be some list of PIDs though it could
manzagop (departed) 2017/03/30 18:13:24 The retrieval by creation order sounds worth addin
bcwhite 2017/03/30 22:20:51 Done.
333 std::reverse(process_ids_.begin(), process_ids_.end());
230 } 334 }
231 335
232 } // namespace debug 336 } // namespace debug
233 } // namespace base 337 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698