OLD | NEW |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |