bcwhite | d970596 | 2016-08-10 03:10:03 | [diff] [blame] | 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 | #include "base/debug/activity_analyzer.h" |
| 6 | |
manzagop | 0793c6c | 2017-04-23 12:10:37 | [diff] [blame] | 7 | #include <utility> |
bcwhite | e7aca06 | 2017-03-31 16:21:53 | [diff] [blame] | 8 | |
Hans Wennborg | c3cffa6 | 2020-04-27 10:09:12 | [diff] [blame] | 9 | #include "base/check_op.h" |
Jan Wilken Dörrie | b5a41c3 | 2020-12-09 18:55:47 | [diff] [blame] | 10 | #include "base/containers/contains.h" |
bcwhite | d970596 | 2016-08-10 03:10:03 | [diff] [blame] | 11 | #include "base/files/file.h" |
| 12 | #include "base/files/file_path.h" |
| 13 | #include "base/files/memory_mapped_file.h" |
Brian White | 6d5a155 | 2019-06-21 17:42:04 | [diff] [blame] | 14 | #include "base/metrics/histogram_functions.h" |
manzagop | 0793c6c | 2017-04-23 12:10:37 | [diff] [blame] | 15 | #include "base/metrics/histogram_macros.h" |
Lei Zhang | e3e126d78 | 2020-01-07 21:36:00 | [diff] [blame] | 16 | #include "base/no_destructor.h" |
Anton Bikineev | a61fb57 | 2020-10-18 08:54:44 | [diff] [blame] | 17 | #include "base/ranges/algorithm.h" |
bcwhite | d970596 | 2016-08-10 03:10:03 | [diff] [blame] | 18 | #include "base/strings/string_util.h" |
| 19 | |
| 20 | namespace base { |
| 21 | namespace debug { |
| 22 | |
bcwhite | e7aca06 | 2017-03-31 16:21:53 | [diff] [blame] | 23 | namespace { |
Lei Zhang | e3e126d78 | 2020-01-07 21:36:00 | [diff] [blame] | 24 | |
| 25 | const 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 | } |
manzagop | 0793c6c | 2017-04-23 12:10:37 | [diff] [blame] | 30 | |
manzagop | 0793c6c | 2017-04-23 12:10:37 | [diff] [blame] | 31 | // DO NOT CHANGE VALUES. This is logged persistently in a histogram. |
| 32 | enum AnalyzerCreationError { |
| 33 | kInvalidMemoryMappedFile, |
| 34 | kPmaBadFile, |
| 35 | kPmaUninitialized, |
| 36 | kPmaDeleted, |
| 37 | kPmaCorrupt, |
| 38 | kAnalyzerCreationErrorMax // Keep this last. |
| 39 | }; |
| 40 | |
| 41 | void LogAnalyzerCreationError(AnalyzerCreationError error) { |
Brian White | 6d5a155 | 2019-06-21 17:42:04 | [diff] [blame] | 42 | UmaHistogramEnumeration("ActivityTracker.Collect.AnalyzerCreationError", |
| 43 | error, kAnalyzerCreationErrorMax); |
manzagop | 0793c6c | 2017-04-23 12:10:37 | [diff] [blame] | 44 | } |
manzagop | 0793c6c | 2017-04-23 12:10:37 | [diff] [blame] | 45 | |
bcwhite | e7aca06 | 2017-03-31 16:21:53 | [diff] [blame] | 46 | } // namespace |
| 47 | |
Chris Watkins | bb7211c | 2017-11-29 07:16:38 | [diff] [blame] | 48 | ThreadActivityAnalyzer::Snapshot::Snapshot() = default; |
| 49 | ThreadActivityAnalyzer::Snapshot::~Snapshot() = default; |
bcwhite | 587c325 | 2016-12-09 03:37:56 | [diff] [blame] | 50 | |
bcwhite | d970596 | 2016-08-10 03:10:03 | [diff] [blame] | 51 | ThreadActivityAnalyzer::ThreadActivityAnalyzer( |
| 52 | const ThreadActivityTracker& tracker) |
bcwhite | 587c325 | 2016-12-09 03:37:56 | [diff] [blame] | 53 | : activity_snapshot_valid_(tracker.CreateSnapshot(&activity_snapshot_)) {} |
bcwhite | d970596 | 2016-08-10 03:10:03 | [diff] [blame] | 54 | |
| 55 | ThreadActivityAnalyzer::ThreadActivityAnalyzer(void* base, size_t size) |
| 56 | : ThreadActivityAnalyzer(ThreadActivityTracker(base, size)) {} |
| 57 | |
| 58 | ThreadActivityAnalyzer::ThreadActivityAnalyzer( |
| 59 | PersistentMemoryAllocator* allocator, |
| 60 | PersistentMemoryAllocator::Reference reference) |
piman | 03cd21b | 2016-11-22 21:03:29 | [diff] [blame] | 61 | : ThreadActivityAnalyzer(allocator->GetAsArray<char>( |
bcwhite | d970596 | 2016-08-10 03:10:03 | [diff] [blame] | 62 | reference, |
piman | 03cd21b | 2016-11-22 21:03:29 | [diff] [blame] | 63 | GlobalActivityTracker::kTypeIdActivityTracker, |
bcwhite | de229b4 | 2017-01-26 18:28:18 | [diff] [blame] | 64 | PersistentMemoryAllocator::kSizeAny), |
bcwhite | d970596 | 2016-08-10 03:10:03 | [diff] [blame] | 65 | allocator->GetAllocSize(reference)) {} |
| 66 | |
Chris Watkins | bb7211c | 2017-11-29 07:16:38 | [diff] [blame] | 67 | ThreadActivityAnalyzer::~ThreadActivityAnalyzer() = default; |
bcwhite | d970596 | 2016-08-10 03:10:03 | [diff] [blame] | 68 | |
bcwhite | 587c325 | 2016-12-09 03:37:56 | [diff] [blame] | 69 | void 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( |
bcwhite | e7aca06 | 2017-03-31 16:21:53 | [diff] [blame] | 81 | activity_snapshot_.process_id, activity.user_data_ref, |
| 82 | activity.user_data_id)); |
bcwhite | 587c325 | 2016-12-09 03:37:56 | [diff] [blame] | 83 | } |
| 84 | } |
| 85 | |
bcwhite | d970596 | 2016-08-10 03:10:03 | [diff] [blame] | 86 | GlobalActivityAnalyzer::GlobalActivityAnalyzer( |
| 87 | std::unique_ptr<PersistentMemoryAllocator> allocator) |
manzagop | 27f4805 | 2017-08-17 20:32:13 | [diff] [blame] | 88 | : allocator_(std::move(allocator)), |
| 89 | analysis_stamp_(0LL), |
| 90 | allocator_iterator_(allocator_.get()) { |
manzagop | 0793c6c | 2017-04-23 12:10:37 | [diff] [blame] | 91 | DCHECK(allocator_); |
| 92 | } |
bcwhite | d970596 | 2016-08-10 03:10:03 | [diff] [blame] | 93 | |
Chris Watkins | bb7211c | 2017-11-29 07:16:38 | [diff] [blame] | 94 | GlobalActivityAnalyzer::~GlobalActivityAnalyzer() = default; |
bcwhite | d970596 | 2016-08-10 03:10:03 | [diff] [blame] | 95 | |
Brian White | 32db29f | 2017-11-23 16:53:24 | [diff] [blame] | 96 | // static |
| 97 | std::unique_ptr<GlobalActivityAnalyzer> |
| 98 | GlobalActivityAnalyzer::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 Benjamin | dd43629 | 2018-10-11 16:28:00 | [diff] [blame] | 115 | return std::make_unique<GlobalActivityAnalyzer>(std::move(allocator)); |
Brian White | 32db29f | 2017-11-23 16:53:24 | [diff] [blame] | 116 | } |
| 117 | |
bcwhite | d970596 | 2016-08-10 03:10:03 | [diff] [blame] | 118 | #if !defined(OS_NACL) |
| 119 | // static |
| 120 | std::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 Harrison | 0a81d0f | 2018-10-05 19:00:02 | [diff] [blame] | 125 | if (!mmfile->Initialize(file_path, MemoryMappedFile::READ_WRITE)) { |
manzagop | 0793c6c | 2017-04-23 12:10:37 | [diff] [blame] | 126 | LogAnalyzerCreationError(kInvalidMemoryMappedFile); |
bcwhite | d970596 | 2016-08-10 03:10:03 | [diff] [blame] | 127 | return nullptr; |
manzagop | 0793c6c | 2017-04-23 12:10:37 | [diff] [blame] | 128 | } |
bcwhite | d970596 | 2016-08-10 03:10:03 | [diff] [blame] | 129 | |
manzagop | 0793c6c | 2017-04-23 12:10:37 | [diff] [blame] | 130 | if (!FilePersistentMemoryAllocator::IsFileAcceptable(*mmfile, true)) { |
| 131 | LogAnalyzerCreationError(kPmaBadFile); |
bcwhite | d970596 | 2016-08-10 03:10:03 | [diff] [blame] | 132 | return nullptr; |
manzagop | 0793c6c | 2017-04-23 12:10:37 | [diff] [blame] | 133 | } |
bcwhite | d970596 | 2016-08-10 03:10:03 | [diff] [blame] | 134 | |
Brian White | 32db29f | 2017-11-23 16:53:24 | [diff] [blame] | 135 | return CreateWithAllocator(std::make_unique<FilePersistentMemoryAllocator>( |
| 136 | std::move(mmfile), 0, 0, StringPiece(), /*readonly=*/true)); |
bcwhite | d970596 | 2016-08-10 03:10:03 | [diff] [blame] | 137 | } |
| 138 | #endif // !defined(OS_NACL) |
| 139 | |
Brian White | 32db29f | 2017-11-23 16:53:24 | [diff] [blame] | 140 | // static |
| 141 | std::unique_ptr<GlobalActivityAnalyzer> |
| 142 | GlobalActivityAnalyzer::CreateWithSharedMemory( |
Alex Ilin | 61d7bcf | 2019-02-26 11:24:42 | [diff] [blame] | 143 | base::ReadOnlySharedMemoryMapping mapping) { |
| 144 | if (!mapping.IsValid() || |
| 145 | !ReadOnlySharedPersistentMemoryAllocator::IsSharedMemoryAcceptable( |
| 146 | mapping)) { |
Brian White | 32db29f | 2017-11-23 16:53:24 | [diff] [blame] | 147 | return nullptr; |
| 148 | } |
Alex Ilin | 61d7bcf | 2019-02-26 11:24:42 | [diff] [blame] | 149 | return CreateWithAllocator( |
| 150 | std::make_unique<ReadOnlySharedPersistentMemoryAllocator>( |
| 151 | std::move(mapping), 0, StringPiece())); |
Brian White | 32db29f | 2017-11-23 16:53:24 | [diff] [blame] | 152 | } |
| 153 | |
bcwhite | e7aca06 | 2017-03-31 16:21:53 | [diff] [blame] | 154 | int64_t GlobalActivityAnalyzer::GetFirstProcess() { |
bcwhite | d970596 | 2016-08-10 03:10:03 | [diff] [blame] | 155 | PrepareAllAnalyzers(); |
bcwhite | e7aca06 | 2017-03-31 16:21:53 | [diff] [blame] | 156 | return GetNextProcess(); |
| 157 | } |
| 158 | |
| 159 | int64_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 | |
| 167 | ThreadActivityAnalyzer* GlobalActivityAnalyzer::GetFirstAnalyzer(int64_t pid) { |
bcwhite | d970596 | 2016-08-10 03:10:03 | [diff] [blame] | 168 | analyzers_iterator_ = analyzers_.begin(); |
bcwhite | e7aca06 | 2017-03-31 16:21:53 | [diff] [blame] | 169 | analyzers_iterator_pid_ = pid; |
bcwhite | d970596 | 2016-08-10 03:10:03 | [diff] [blame] | 170 | if (analyzers_iterator_ == analyzers_.end()) |
| 171 | return nullptr; |
bcwhite | e7aca06 | 2017-03-31 16:21:53 | [diff] [blame] | 172 | 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(); |
bcwhite | d970596 | 2016-08-10 03:10:03 | [diff] [blame] | 178 | } |
| 179 | |
| 180 | ThreadActivityAnalyzer* GlobalActivityAnalyzer::GetNextAnalyzer() { |
| 181 | DCHECK(analyzers_iterator_ != analyzers_.end()); |
bcwhite | e7aca06 | 2017-03-31 16:21:53 | [diff] [blame] | 182 | 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_); |
bcwhite | d970596 | 2016-08-10 03:10:03 | [diff] [blame] | 190 | return analyzers_iterator_->second.get(); |
| 191 | } |
| 192 | |
| 193 | ThreadActivityAnalyzer* 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 | |
bcwhite | 587c325 | 2016-12-09 03:37:56 | [diff] [blame] | 201 | ActivityUserData::Snapshot GlobalActivityAnalyzer::GetUserDataSnapshot( |
bcwhite | e7aca06 | 2017-03-31 16:21:53 | [diff] [blame] | 202 | int64_t pid, |
bcwhite | 587c325 | 2016-12-09 03:37:56 | [diff] [blame] | 203 | 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); |
bcwhite | e7aca06 | 2017-03-31 16:21:53 | [diff] [blame] | 214 | 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) { |
bcwhite | 587c325 | 2016-12-09 03:37:56 | [diff] [blame] | 219 | // 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 | |
bcwhite | e7aca06 | 2017-03-31 16:21:53 | [diff] [blame] | 228 | const ActivityUserData::Snapshot& |
| 229 | GlobalActivityAnalyzer::GetProcessDataSnapshot(int64_t pid) { |
| 230 | auto iter = process_data_.find(pid); |
| 231 | if (iter == process_data_.end()) |
Lei Zhang | e3e126d78 | 2020-01-07 21:36:00 | [diff] [blame] | 232 | return GetEmptyUserDataSnapshot(); |
bcwhite | e7aca06 | 2017-03-31 16:21:53 | [diff] [blame] | 233 | if (iter->second.create_stamp > analysis_stamp_) |
Lei Zhang | e3e126d78 | 2020-01-07 21:36:00 | [diff] [blame] | 234 | return GetEmptyUserDataSnapshot(); |
bcwhite | e7aca06 | 2017-03-31 16:21:53 | [diff] [blame] | 235 | DCHECK_EQ(pid, iter->second.process_id); |
| 236 | return iter->second.data; |
| 237 | } |
| 238 | |
bcwhite | 7a30eb4 | 2016-12-02 21:23:40 | [diff] [blame] | 239 | std::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 | |
bcwhite | de229b4 | 2017-01-26 18:28:18 | [diff] [blame] | 256 | std::vector<GlobalActivityTracker::ModuleInfo> |
manzagop | 27f4805 | 2017-08-17 20:32:13 | [diff] [blame] | 257 | GlobalActivityAnalyzer::GetModules(int64_t pid) { |
bcwhite | de229b4 | 2017-01-26 18:28:18 | [diff] [blame] | 258 | 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) { |
manzagop | 27f4805 | 2017-08-17 20:32:13 | [diff] [blame] | 266 | 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 | } |
bcwhite | de229b4 | 2017-01-26 18:28:18 | [diff] [blame] | 273 | 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 | |
bcwhite | 21f6c57 | 2016-11-10 15:46:45 | [diff] [blame] | 283 | GlobalActivityAnalyzer::ProgramLocation |
| 284 | GlobalActivityAnalyzer::GetProgramLocationFromAddress(uint64_t address) { |
| 285 | // TODO(bcwhite): Implement this. |
| 286 | return { 0, 0 }; |
| 287 | } |
| 288 | |
manzagop | 0793c6c | 2017-04-23 12:10:37 | [diff] [blame] | 289 | bool GlobalActivityAnalyzer::IsDataComplete() const { |
| 290 | DCHECK(allocator_); |
| 291 | return !allocator_->IsFull(); |
| 292 | } |
| 293 | |
Chris Watkins | bb7211c | 2017-11-29 07:16:38 | [diff] [blame] | 294 | GlobalActivityAnalyzer::UserDataSnapshot::UserDataSnapshot() = default; |
bcwhite | e7aca06 | 2017-03-31 16:21:53 | [diff] [blame] | 295 | GlobalActivityAnalyzer::UserDataSnapshot::UserDataSnapshot( |
| 296 | const UserDataSnapshot& rhs) = default; |
| 297 | GlobalActivityAnalyzer::UserDataSnapshot::UserDataSnapshot( |
| 298 | UserDataSnapshot&& rhs) = default; |
Chris Watkins | bb7211c | 2017-11-29 07:16:38 | [diff] [blame] | 299 | GlobalActivityAnalyzer::UserDataSnapshot::~UserDataSnapshot() = default; |
bcwhite | e7aca06 | 2017-03-31 16:21:53 | [diff] [blame] | 300 | |
bcwhite | d970596 | 2016-08-10 03:10:03 | [diff] [blame] | 301 | void GlobalActivityAnalyzer::PrepareAllAnalyzers() { |
bcwhite | e7aca06 | 2017-03-31 16:21:53 | [diff] [blame] | 302 | // Record the time when analysis started. |
| 303 | analysis_stamp_ = base::Time::Now().ToInternalValue(); |
| 304 | |
bcwhite | d970596 | 2016-08-10 03:10:03 | [diff] [blame] | 305 | // 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: |
bcwhite | e7aca06 | 2017-03-31 16:21:53 | [diff] [blame] | 313 | 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); |
bcwhite | d970596 | 2016-08-10 03:10:03 | [diff] [blame] | 319 | break; |
| 320 | } |
| 321 | } |
| 322 | |
bcwhite | e7aca06 | 2017-03-31 16:21:53 | [diff] [blame] | 323 | // Clear out any old information. |
bcwhite | d970596 | 2016-08-10 03:10:03 | [diff] [blame] | 324 | analyzers_.clear(); |
bcwhite | e7aca06 | 2017-03-31 16:21:53 | [diff] [blame] | 325 | 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, |
piman | 03cd21b | 2016-11-22 21:03:29 | [diff] [blame] | 336 | PersistentMemoryAllocator::kSizeAny); |
bcwhite | e7aca06 | 2017-03-31 16:21:53 | [diff] [blame] | 337 | const size_t size = allocator_->GetAllocSize(memory_ref); |
bcwhite | d970596 | 2016-08-10 03:10:03 | [diff] [blame] | 338 | if (!base) |
| 339 | continue; |
| 340 | |
bcwhite | e7aca06 | 2017-03-31 16:21:53 | [diff] [blame] | 341 | 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); |
bcwhite | d970596 | 2016-08-10 03:10:03 | [diff] [blame] | 351 | |
bcwhite | e7aca06 | 2017-03-31 16:21:53 | [diff] [blame] | 352 | // 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örrie | f61e74c | 2019-06-07 08:20:02 | [diff] [blame] | 362 | DCHECK(!base::Contains(analyzers_, analyzer->GetThreadKey())); |
bcwhite | e7aca06 | 2017-03-31 16:21:53 | [diff] [blame] | 363 | 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örrie | f61e74c | 2019-06-07 08:20:02 | [diff] [blame] | 372 | DCHECK(!base::Contains(process_data_, process_id)); |
bcwhite | e7aca06 | 2017-03-31 16:21:53 | [diff] [blame] | 373 | |
| 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 | } |
bcwhite | d970596 | 2016-08-10 03:10:03 | [diff] [blame] | 398 | } |
bcwhite | e7aca06 | 2017-03-31 16:21:53 | [diff] [blame] | 399 | |
| 400 | // Reverse the list of PIDs so that they get popped in the order found. |
Anton Bikineev | a61fb57 | 2020-10-18 08:54:44 | [diff] [blame] | 401 | ranges::reverse(process_ids_); |
bcwhite | d970596 | 2016-08-10 03:10:03 | [diff] [blame] | 402 | } |
| 403 | |
| 404 | } // namespace debug |
| 405 | } // namespace base |