blob: a8fc881eb860a84b87b786b786e5cf97907491d8 [file] [log] [blame]
bcwhited9705962016-08-10 03:10:031// 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#include "base/debug/activity_analyzer.h"
6
manzagop0793c6c2017-04-23 12:10:377#include <utility>
bcwhitee7aca062017-03-31 16:21:538
Hans Wennborgc3cffa62020-04-27 10:09:129#include "base/check_op.h"
Jan Wilken Dörrieb5a41c32020-12-09 18:55:4710#include "base/containers/contains.h"
bcwhited9705962016-08-10 03:10:0311#include "base/files/file.h"
12#include "base/files/file_path.h"
13#include "base/files/memory_mapped_file.h"
Brian White6d5a1552019-06-21 17:42:0414#include "base/metrics/histogram_functions.h"
manzagop0793c6c2017-04-23 12:10:3715#include "base/metrics/histogram_macros.h"
Lei Zhange3e126d782020-01-07 21:36:0016#include "base/no_destructor.h"
Anton Bikineeva61fb572020-10-18 08:54:4417#include "base/ranges/algorithm.h"
bcwhited9705962016-08-10 03:10:0318#include "base/strings/string_util.h"
19
20namespace base {
21namespace debug {
22
bcwhitee7aca062017-03-31 16:21:5323namespace {
Lei Zhange3e126d782020-01-07 21:36:0024
25const ActivityUserData::Snapshot& GetEmptyUserDataSnapshot() {
26 // An empty snapshot that can be returned when there otherwise is none.
27 static const NoDestructor<ActivityUserData::Snapshot> empty_snapshot;
28 return *empty_snapshot;
29}
manzagop0793c6c2017-04-23 12:10:3730
manzagop0793c6c2017-04-23 12:10:3731// DO NOT CHANGE VALUES. This is logged persistently in a histogram.
32enum AnalyzerCreationError {
33 kInvalidMemoryMappedFile,
34 kPmaBadFile,
35 kPmaUninitialized,
36 kPmaDeleted,
37 kPmaCorrupt,
38 kAnalyzerCreationErrorMax // Keep this last.
39};
40
41void LogAnalyzerCreationError(AnalyzerCreationError error) {
Brian White6d5a1552019-06-21 17:42:0442 UmaHistogramEnumeration("ActivityTracker.Collect.AnalyzerCreationError",
43 error, kAnalyzerCreationErrorMax);
manzagop0793c6c2017-04-23 12:10:3744}
manzagop0793c6c2017-04-23 12:10:3745
bcwhitee7aca062017-03-31 16:21:5346} // namespace
47
Chris Watkinsbb7211c2017-11-29 07:16:3848ThreadActivityAnalyzer::Snapshot::Snapshot() = default;
49ThreadActivityAnalyzer::Snapshot::~Snapshot() = default;
bcwhite587c3252016-12-09 03:37:5650
bcwhited9705962016-08-10 03:10:0351ThreadActivityAnalyzer::ThreadActivityAnalyzer(
52 const ThreadActivityTracker& tracker)
bcwhite587c3252016-12-09 03:37:5653 : activity_snapshot_valid_(tracker.CreateSnapshot(&activity_snapshot_)) {}
bcwhited9705962016-08-10 03:10:0354
55ThreadActivityAnalyzer::ThreadActivityAnalyzer(void* base, size_t size)
56 : ThreadActivityAnalyzer(ThreadActivityTracker(base, size)) {}
57
58ThreadActivityAnalyzer::ThreadActivityAnalyzer(
59 PersistentMemoryAllocator* allocator,
60 PersistentMemoryAllocator::Reference reference)
piman03cd21b2016-11-22 21:03:2961 : ThreadActivityAnalyzer(allocator->GetAsArray<char>(
bcwhited9705962016-08-10 03:10:0362 reference,
piman03cd21b2016-11-22 21:03:2963 GlobalActivityTracker::kTypeIdActivityTracker,
bcwhitede229b42017-01-26 18:28:1864 PersistentMemoryAllocator::kSizeAny),
bcwhited9705962016-08-10 03:10:0365 allocator->GetAllocSize(reference)) {}
66
Chris Watkinsbb7211c2017-11-29 07:16:3867ThreadActivityAnalyzer::~ThreadActivityAnalyzer() = default;
bcwhited9705962016-08-10 03:10:0368
bcwhite587c3252016-12-09 03:37:5669void ThreadActivityAnalyzer::AddGlobalInformation(
70 GlobalActivityAnalyzer* global) {
71 if (!IsValid())
72 return;
73
74 // User-data is held at the global scope even though it's referenced at the
75 // thread scope.
76 activity_snapshot_.user_data_stack.clear();
77 for (auto& activity : activity_snapshot_.activity_stack) {
78 // The global GetUserDataSnapshot will return an empty snapshot if the ref
79 // or id is not valid.
80 activity_snapshot_.user_data_stack.push_back(global->GetUserDataSnapshot(
bcwhitee7aca062017-03-31 16:21:5381 activity_snapshot_.process_id, activity.user_data_ref,
82 activity.user_data_id));
bcwhite587c3252016-12-09 03:37:5683 }
84}
85
bcwhited9705962016-08-10 03:10:0386GlobalActivityAnalyzer::GlobalActivityAnalyzer(
87 std::unique_ptr<PersistentMemoryAllocator> allocator)
manzagop27f48052017-08-17 20:32:1388 : allocator_(std::move(allocator)),
89 analysis_stamp_(0LL),
90 allocator_iterator_(allocator_.get()) {
manzagop0793c6c2017-04-23 12:10:3791 DCHECK(allocator_);
92}
bcwhited9705962016-08-10 03:10:0393
Chris Watkinsbb7211c2017-11-29 07:16:3894GlobalActivityAnalyzer::~GlobalActivityAnalyzer() = default;
bcwhited9705962016-08-10 03:10:0395
Brian White32db29f2017-11-23 16:53:2496// static
97std::unique_ptr<GlobalActivityAnalyzer>
98GlobalActivityAnalyzer::CreateWithAllocator(
99 std::unique_ptr<PersistentMemoryAllocator> allocator) {
100 if (allocator->GetMemoryState() ==
101 PersistentMemoryAllocator::MEMORY_UNINITIALIZED) {
102 LogAnalyzerCreationError(kPmaUninitialized);
103 return nullptr;
104 }
105 if (allocator->GetMemoryState() ==
106 PersistentMemoryAllocator::MEMORY_DELETED) {
107 LogAnalyzerCreationError(kPmaDeleted);
108 return nullptr;
109 }
110 if (allocator->IsCorrupt()) {
111 LogAnalyzerCreationError(kPmaCorrupt);
112 return nullptr;
113 }
114
David Benjamindd436292018-10-11 16:28:00115 return std::make_unique<GlobalActivityAnalyzer>(std::move(allocator));
Brian White32db29f2017-11-23 16:53:24116}
117
bcwhited9705962016-08-10 03:10:03118#if !defined(OS_NACL)
119// static
120std::unique_ptr<GlobalActivityAnalyzer> GlobalActivityAnalyzer::CreateWithFile(
121 const FilePath& file_path) {
122 // Map the file read-write so it can guarantee consistency between
123 // the analyzer and any trackers that my still be active.
124 std::unique_ptr<MemoryMappedFile> mmfile(new MemoryMappedFile());
Charlie Harrison0a81d0f2018-10-05 19:00:02125 if (!mmfile->Initialize(file_path, MemoryMappedFile::READ_WRITE)) {
manzagop0793c6c2017-04-23 12:10:37126 LogAnalyzerCreationError(kInvalidMemoryMappedFile);
bcwhited9705962016-08-10 03:10:03127 return nullptr;
manzagop0793c6c2017-04-23 12:10:37128 }
bcwhited9705962016-08-10 03:10:03129
manzagop0793c6c2017-04-23 12:10:37130 if (!FilePersistentMemoryAllocator::IsFileAcceptable(*mmfile, true)) {
131 LogAnalyzerCreationError(kPmaBadFile);
bcwhited9705962016-08-10 03:10:03132 return nullptr;
manzagop0793c6c2017-04-23 12:10:37133 }
bcwhited9705962016-08-10 03:10:03134
Brian White32db29f2017-11-23 16:53:24135 return CreateWithAllocator(std::make_unique<FilePersistentMemoryAllocator>(
136 std::move(mmfile), 0, 0, StringPiece(), /*readonly=*/true));
bcwhited9705962016-08-10 03:10:03137}
138#endif // !defined(OS_NACL)
139
Brian White32db29f2017-11-23 16:53:24140// static
141std::unique_ptr<GlobalActivityAnalyzer>
142GlobalActivityAnalyzer::CreateWithSharedMemory(
Alex Ilin61d7bcf2019-02-26 11:24:42143 base::ReadOnlySharedMemoryMapping mapping) {
144 if (!mapping.IsValid() ||
145 !ReadOnlySharedPersistentMemoryAllocator::IsSharedMemoryAcceptable(
146 mapping)) {
Brian White32db29f2017-11-23 16:53:24147 return nullptr;
148 }
Alex Ilin61d7bcf2019-02-26 11:24:42149 return CreateWithAllocator(
150 std::make_unique<ReadOnlySharedPersistentMemoryAllocator>(
151 std::move(mapping), 0, StringPiece()));
Brian White32db29f2017-11-23 16:53:24152}
153
bcwhitee7aca062017-03-31 16:21:53154int64_t GlobalActivityAnalyzer::GetFirstProcess() {
bcwhited9705962016-08-10 03:10:03155 PrepareAllAnalyzers();
bcwhitee7aca062017-03-31 16:21:53156 return GetNextProcess();
157}
158
159int64_t GlobalActivityAnalyzer::GetNextProcess() {
160 if (process_ids_.empty())
161 return 0;
162 int64_t pid = process_ids_.back();
163 process_ids_.pop_back();
164 return pid;
165}
166
167ThreadActivityAnalyzer* GlobalActivityAnalyzer::GetFirstAnalyzer(int64_t pid) {
bcwhited9705962016-08-10 03:10:03168 analyzers_iterator_ = analyzers_.begin();
bcwhitee7aca062017-03-31 16:21:53169 analyzers_iterator_pid_ = pid;
bcwhited9705962016-08-10 03:10:03170 if (analyzers_iterator_ == analyzers_.end())
171 return nullptr;
bcwhitee7aca062017-03-31 16:21:53172 int64_t create_stamp;
173 if (analyzers_iterator_->second->GetProcessId(&create_stamp) == pid &&
174 create_stamp <= analysis_stamp_) {
175 return analyzers_iterator_->second.get();
176 }
177 return GetNextAnalyzer();
bcwhited9705962016-08-10 03:10:03178}
179
180ThreadActivityAnalyzer* GlobalActivityAnalyzer::GetNextAnalyzer() {
181 DCHECK(analyzers_iterator_ != analyzers_.end());
bcwhitee7aca062017-03-31 16:21:53182 int64_t create_stamp;
183 do {
184 ++analyzers_iterator_;
185 if (analyzers_iterator_ == analyzers_.end())
186 return nullptr;
187 } while (analyzers_iterator_->second->GetProcessId(&create_stamp) !=
188 analyzers_iterator_pid_ ||
189 create_stamp > analysis_stamp_);
bcwhited9705962016-08-10 03:10:03190 return analyzers_iterator_->second.get();
191}
192
193ThreadActivityAnalyzer* GlobalActivityAnalyzer::GetAnalyzerForThread(
194 const ThreadKey& key) {
195 auto found = analyzers_.find(key);
196 if (found == analyzers_.end())
197 return nullptr;
198 return found->second.get();
199}
200
bcwhite587c3252016-12-09 03:37:56201ActivityUserData::Snapshot GlobalActivityAnalyzer::GetUserDataSnapshot(
bcwhitee7aca062017-03-31 16:21:53202 int64_t pid,
bcwhite587c3252016-12-09 03:37:56203 uint32_t ref,
204 uint32_t id) {
205 ActivityUserData::Snapshot snapshot;
206
207 void* memory = allocator_->GetAsArray<char>(
208 ref, GlobalActivityTracker::kTypeIdUserDataRecord,
209 PersistentMemoryAllocator::kSizeAny);
210 if (memory) {
211 size_t size = allocator_->GetAllocSize(ref);
212 const ActivityUserData user_data(memory, size);
213 user_data.CreateSnapshot(&snapshot);
bcwhitee7aca062017-03-31 16:21:53214 int64_t process_id;
215 int64_t create_stamp;
216 if (!ActivityUserData::GetOwningProcessId(memory, &process_id,
217 &create_stamp) ||
218 process_id != pid || user_data.id() != id) {
bcwhite587c3252016-12-09 03:37:56219 // This allocation has been overwritten since it was created. Return an
220 // empty snapshot because whatever was captured is incorrect.
221 snapshot.clear();
222 }
223 }
224
225 return snapshot;
226}
227
bcwhitee7aca062017-03-31 16:21:53228const ActivityUserData::Snapshot&
229GlobalActivityAnalyzer::GetProcessDataSnapshot(int64_t pid) {
230 auto iter = process_data_.find(pid);
231 if (iter == process_data_.end())
Lei Zhange3e126d782020-01-07 21:36:00232 return GetEmptyUserDataSnapshot();
bcwhitee7aca062017-03-31 16:21:53233 if (iter->second.create_stamp > analysis_stamp_)
Lei Zhange3e126d782020-01-07 21:36:00234 return GetEmptyUserDataSnapshot();
bcwhitee7aca062017-03-31 16:21:53235 DCHECK_EQ(pid, iter->second.process_id);
236 return iter->second.data;
237}
238
bcwhite7a30eb42016-12-02 21:23:40239std::vector<std::string> GlobalActivityAnalyzer::GetLogMessages() {
240 std::vector<std::string> messages;
241 PersistentMemoryAllocator::Reference ref;
242
243 PersistentMemoryAllocator::Iterator iter(allocator_.get());
244 while ((ref = iter.GetNextOfType(
245 GlobalActivityTracker::kTypeIdGlobalLogMessage)) != 0) {
246 const char* message = allocator_->GetAsArray<char>(
247 ref, GlobalActivityTracker::kTypeIdGlobalLogMessage,
248 PersistentMemoryAllocator::kSizeAny);
249 if (message)
250 messages.push_back(message);
251 }
252
253 return messages;
254}
255
bcwhitede229b42017-01-26 18:28:18256std::vector<GlobalActivityTracker::ModuleInfo>
manzagop27f48052017-08-17 20:32:13257GlobalActivityAnalyzer::GetModules(int64_t pid) {
bcwhitede229b42017-01-26 18:28:18258 std::vector<GlobalActivityTracker::ModuleInfo> modules;
259
260 PersistentMemoryAllocator::Iterator iter(allocator_.get());
261 const GlobalActivityTracker::ModuleInfoRecord* record;
262 while (
263 (record =
264 iter.GetNextOfObject<GlobalActivityTracker::ModuleInfoRecord>()) !=
265 nullptr) {
manzagop27f48052017-08-17 20:32:13266 int64_t process_id;
267 int64_t create_stamp;
268 if (!OwningProcess::GetOwningProcessId(&record->owner, &process_id,
269 &create_stamp) ||
270 pid != process_id || create_stamp > analysis_stamp_) {
271 continue;
272 }
bcwhitede229b42017-01-26 18:28:18273 GlobalActivityTracker::ModuleInfo info;
274 if (record->DecodeTo(&info, allocator_->GetAllocSize(
275 allocator_->GetAsReference(record)))) {
276 modules.push_back(std::move(info));
277 }
278 }
279
280 return modules;
281}
282
bcwhite21f6c572016-11-10 15:46:45283GlobalActivityAnalyzer::ProgramLocation
284GlobalActivityAnalyzer::GetProgramLocationFromAddress(uint64_t address) {
285 // TODO(bcwhite): Implement this.
286 return { 0, 0 };
287}
288
manzagop0793c6c2017-04-23 12:10:37289bool GlobalActivityAnalyzer::IsDataComplete() const {
290 DCHECK(allocator_);
291 return !allocator_->IsFull();
292}
293
Chris Watkinsbb7211c2017-11-29 07:16:38294GlobalActivityAnalyzer::UserDataSnapshot::UserDataSnapshot() = default;
bcwhitee7aca062017-03-31 16:21:53295GlobalActivityAnalyzer::UserDataSnapshot::UserDataSnapshot(
296 const UserDataSnapshot& rhs) = default;
297GlobalActivityAnalyzer::UserDataSnapshot::UserDataSnapshot(
298 UserDataSnapshot&& rhs) = default;
Chris Watkinsbb7211c2017-11-29 07:16:38299GlobalActivityAnalyzer::UserDataSnapshot::~UserDataSnapshot() = default;
bcwhitee7aca062017-03-31 16:21:53300
bcwhited9705962016-08-10 03:10:03301void GlobalActivityAnalyzer::PrepareAllAnalyzers() {
bcwhitee7aca062017-03-31 16:21:53302 // Record the time when analysis started.
303 analysis_stamp_ = base::Time::Now().ToInternalValue();
304
bcwhited9705962016-08-10 03:10:03305 // Fetch all the records. This will retrieve only ones created since the
306 // last run since the PMA iterator will continue from where it left off.
307 uint32_t type;
308 PersistentMemoryAllocator::Reference ref;
309 while ((ref = allocator_iterator_.GetNext(&type)) != 0) {
310 switch (type) {
311 case GlobalActivityTracker::kTypeIdActivityTracker:
312 case GlobalActivityTracker::kTypeIdActivityTrackerFree:
bcwhitee7aca062017-03-31 16:21:53313 case GlobalActivityTracker::kTypeIdProcessDataRecord:
314 case GlobalActivityTracker::kTypeIdProcessDataRecordFree:
315 case PersistentMemoryAllocator::kTypeIdTransitioning:
316 // Active, free, or transitioning: add it to the list of references
317 // for later analysis.
318 memory_references_.insert(ref);
bcwhited9705962016-08-10 03:10:03319 break;
320 }
321 }
322
bcwhitee7aca062017-03-31 16:21:53323 // Clear out any old information.
bcwhited9705962016-08-10 03:10:03324 analyzers_.clear();
bcwhitee7aca062017-03-31 16:21:53325 process_data_.clear();
326 process_ids_.clear();
327 std::set<int64_t> seen_pids;
328
329 // Go through all the known references and create objects for them with
330 // snapshots of the current state.
331 for (PersistentMemoryAllocator::Reference memory_ref : memory_references_) {
332 // Get the actual data segment for the tracker. Any type will do since it
333 // is checked below.
334 void* const base = allocator_->GetAsArray<char>(
335 memory_ref, PersistentMemoryAllocator::kTypeIdAny,
piman03cd21b2016-11-22 21:03:29336 PersistentMemoryAllocator::kSizeAny);
bcwhitee7aca062017-03-31 16:21:53337 const size_t size = allocator_->GetAllocSize(memory_ref);
bcwhited9705962016-08-10 03:10:03338 if (!base)
339 continue;
340
bcwhitee7aca062017-03-31 16:21:53341 switch (allocator_->GetType(memory_ref)) {
342 case GlobalActivityTracker::kTypeIdActivityTracker: {
343 // Create the analyzer on the data. This will capture a snapshot of the
344 // tracker state. This can fail if the tracker is somehow corrupted or
345 // is in the process of shutting down.
346 std::unique_ptr<ThreadActivityAnalyzer> analyzer(
347 new ThreadActivityAnalyzer(base, size));
348 if (!analyzer->IsValid())
349 continue;
350 analyzer->AddGlobalInformation(this);
bcwhited9705962016-08-10 03:10:03351
bcwhitee7aca062017-03-31 16:21:53352 // Track PIDs.
353 int64_t pid = analyzer->GetProcessId();
354 if (seen_pids.find(pid) == seen_pids.end()) {
355 process_ids_.push_back(pid);
356 seen_pids.insert(pid);
357 }
358
359 // Add this analyzer to the map of known ones, indexed by a unique
360 // thread
361 // identifier.
Jan Wilken Dörrief61e74c2019-06-07 08:20:02362 DCHECK(!base::Contains(analyzers_, analyzer->GetThreadKey()));
bcwhitee7aca062017-03-31 16:21:53363 analyzer->allocator_reference_ = ref;
364 analyzers_[analyzer->GetThreadKey()] = std::move(analyzer);
365 } break;
366
367 case GlobalActivityTracker::kTypeIdProcessDataRecord: {
368 // Get the PID associated with this data record.
369 int64_t process_id;
370 int64_t create_stamp;
371 ActivityUserData::GetOwningProcessId(base, &process_id, &create_stamp);
Jan Wilken Dörrief61e74c2019-06-07 08:20:02372 DCHECK(!base::Contains(process_data_, process_id));
bcwhitee7aca062017-03-31 16:21:53373
374 // Create a snapshot of the data. This can fail if the data is somehow
375 // corrupted or the process shutdown and the memory being released.
376 UserDataSnapshot& snapshot = process_data_[process_id];
377 snapshot.process_id = process_id;
378 snapshot.create_stamp = create_stamp;
379 const ActivityUserData process_data(base, size);
380 if (!process_data.CreateSnapshot(&snapshot.data))
381 break;
382
383 // Check that nothing changed. If it did, forget what was recorded.
384 ActivityUserData::GetOwningProcessId(base, &process_id, &create_stamp);
385 if (process_id != snapshot.process_id ||
386 create_stamp != snapshot.create_stamp) {
387 process_data_.erase(process_id);
388 break;
389 }
390
391 // Track PIDs.
392 if (seen_pids.find(process_id) == seen_pids.end()) {
393 process_ids_.push_back(process_id);
394 seen_pids.insert(process_id);
395 }
396 } break;
397 }
bcwhited9705962016-08-10 03:10:03398 }
bcwhitee7aca062017-03-31 16:21:53399
400 // Reverse the list of PIDs so that they get popped in the order found.
Anton Bikineeva61fb572020-10-18 08:54:44401 ranges::reverse(process_ids_);
bcwhited9705962016-08-10 03:10:03402}
403
404} // namespace debug
405} // namespace base