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

Unified 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, 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 side-by-side diff with in-line comments
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 »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: base/debug/activity_analyzer.cc
diff --git a/base/debug/activity_analyzer.cc b/base/debug/activity_analyzer.cc
index 7c421e9630922a9135baae81bae052d3e21fb7d7..0ab7c3d0a0342c149b46ac568d6d409f48508bac 100644
--- a/base/debug/activity_analyzer.cc
+++ b/base/debug/activity_analyzer.cc
@@ -4,9 +4,12 @@
#include "base/debug/activity_analyzer.h"
+#include <algorithm>
+
#include "base/files/file.h"
#include "base/files/file_path.h"
#include "base/files/memory_mapped_file.h"
+#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/stl_util.h"
@@ -15,6 +18,11 @@
namespace base {
namespace debug {
+namespace {
+// An empty snapshot that can be returned when there otherwise is none.
+LazyInstance<ActivityUserData::Snapshot>::Leaky g_empty_user_data_snapshot;
+} // namespace
+
ThreadActivityAnalyzer::Snapshot::Snapshot() {}
ThreadActivityAnalyzer::Snapshot::~Snapshot() {}
@@ -48,7 +56,8 @@ void ThreadActivityAnalyzer::AddGlobalInformation(
// The global GetUserDataSnapshot will return an empty snapshot if the ref
// or id is not valid.
activity_snapshot_.user_data_stack.push_back(global->GetUserDataSnapshot(
- activity.user_data_ref, activity.user_data_id));
+ activity_snapshot_.process_id, activity.user_data_ref,
+ activity.user_data_id));
}
}
@@ -78,19 +87,42 @@ std::unique_ptr<GlobalActivityAnalyzer> GlobalActivityAnalyzer::CreateWithFile(
}
#endif // !defined(OS_NACL)
-ThreadActivityAnalyzer* GlobalActivityAnalyzer::GetFirstAnalyzer() {
+int64_t GlobalActivityAnalyzer::GetFirstProcess() {
PrepareAllAnalyzers();
+ return GetNextProcess();
+}
+
+int64_t GlobalActivityAnalyzer::GetNextProcess() {
+ if (process_ids_.empty())
+ return 0;
+ int64_t pid = process_ids_.back();
+ process_ids_.pop_back();
+ return pid;
+}
+
+ThreadActivityAnalyzer* GlobalActivityAnalyzer::GetFirstAnalyzer(int64_t pid) {
analyzers_iterator_ = analyzers_.begin();
+ analyzers_iterator_pid_ = pid;
if (analyzers_iterator_ == analyzers_.end())
return nullptr;
- return analyzers_iterator_->second.get();
+ int64_t create_stamp;
+ if (analyzers_iterator_->second->GetProcessId(&create_stamp) == pid &&
+ create_stamp <= analysis_stamp_) {
+ return analyzers_iterator_->second.get();
+ }
+ return GetNextAnalyzer();
}
ThreadActivityAnalyzer* GlobalActivityAnalyzer::GetNextAnalyzer() {
DCHECK(analyzers_iterator_ != analyzers_.end());
- ++analyzers_iterator_;
- if (analyzers_iterator_ == analyzers_.end())
- return nullptr;
+ int64_t create_stamp;
+ do {
+ ++analyzers_iterator_;
+ if (analyzers_iterator_ == analyzers_.end())
+ return nullptr;
+ } while (analyzers_iterator_->second->GetProcessId(&create_stamp) !=
+ analyzers_iterator_pid_ ||
+ create_stamp > analysis_stamp_);
return analyzers_iterator_->second.get();
}
@@ -103,6 +135,7 @@ ThreadActivityAnalyzer* GlobalActivityAnalyzer::GetAnalyzerForThread(
}
ActivityUserData::Snapshot GlobalActivityAnalyzer::GetUserDataSnapshot(
+ int64_t pid,
uint32_t ref,
uint32_t id) {
ActivityUserData::Snapshot snapshot;
@@ -114,7 +147,11 @@ ActivityUserData::Snapshot GlobalActivityAnalyzer::GetUserDataSnapshot(
size_t size = allocator_->GetAllocSize(ref);
const ActivityUserData user_data(memory, size);
user_data.CreateSnapshot(&snapshot);
- if (user_data.id() != id) {
+ int64_t process_id;
+ int64_t create_stamp;
+ if (!ActivityUserData::GetOwningProcessId(memory, &process_id,
+ &create_stamp) ||
+ process_id != pid || user_data.id() != id) {
// This allocation has been overwritten since it was created. Return an
// empty snapshot because whatever was captured is incorrect.
snapshot.clear();
@@ -124,8 +161,20 @@ ActivityUserData::Snapshot GlobalActivityAnalyzer::GetUserDataSnapshot(
return snapshot;
}
-ActivityUserData::Snapshot GlobalActivityAnalyzer::GetGlobalUserDataSnapshot() {
- ActivityUserData::Snapshot snapshot;
+const ActivityUserData::Snapshot&
+GlobalActivityAnalyzer::GetProcessDataSnapshot(int64_t pid) {
+ auto iter = process_data_.find(pid);
+ if (iter == process_data_.end())
+ return g_empty_user_data_snapshot.Get();
+ if (iter->second.create_stamp > analysis_stamp_)
+ return g_empty_user_data_snapshot.Get();
+ DCHECK_EQ(pid, iter->second.process_id);
+ return iter->second.data;
+}
+
+const ActivityUserData::Snapshot&
+GlobalActivityAnalyzer::GetGlobalDataSnapshot() {
+ global_data_snapshot_.clear();
PersistentMemoryAllocator::Reference ref =
PersistentMemoryAllocator::Iterator(allocator_.get())
@@ -136,10 +185,10 @@ ActivityUserData::Snapshot GlobalActivityAnalyzer::GetGlobalUserDataSnapshot() {
if (memory) {
size_t size = allocator_->GetAllocSize(ref);
const ActivityUserData global_data(memory, size);
- global_data.CreateSnapshot(&snapshot);
+ global_data.CreateSnapshot(&global_data_snapshot_);
}
- return snapshot;
+ return global_data_snapshot_;
}
std::vector<std::string> GlobalActivityAnalyzer::GetLogMessages() {
@@ -185,7 +234,17 @@ GlobalActivityAnalyzer::GetProgramLocationFromAddress(uint64_t address) {
return { 0, 0 };
}
+GlobalActivityAnalyzer::UserDataSnapshot::UserDataSnapshot() {}
+GlobalActivityAnalyzer::UserDataSnapshot::UserDataSnapshot(
+ const UserDataSnapshot& rhs) = default;
+GlobalActivityAnalyzer::UserDataSnapshot::UserDataSnapshot(
+ UserDataSnapshot&& rhs) = default;
+GlobalActivityAnalyzer::UserDataSnapshot::~UserDataSnapshot() {}
+
void GlobalActivityAnalyzer::PrepareAllAnalyzers() {
+ // Record the time when analysis started.
+ analysis_stamp_ = base::Time::Now().ToInternalValue();
+
// Fetch all the records. This will retrieve only ones created since the
// last run since the PMA iterator will continue from where it left off.
uint32_t type;
@@ -194,39 +253,95 @@ void GlobalActivityAnalyzer::PrepareAllAnalyzers() {
switch (type) {
case GlobalActivityTracker::kTypeIdActivityTracker:
case GlobalActivityTracker::kTypeIdActivityTrackerFree:
- // Free or not, add it to the list of references for later analysis.
- tracker_references_.insert(ref);
+ case GlobalActivityTracker::kTypeIdProcessDataRecord:
+ case GlobalActivityTracker::kTypeIdProcessDataRecordFree:
+ case PersistentMemoryAllocator::kTypeIdTransitioning:
+ // Active, free, or transitioning: add it to the list of references
+ // for later analysis.
+ memory_references_.insert(ref);
break;
}
}
- // Go through all the known references and create analyzers for them with
- // snapshots of the current state.
+ // Clear out any old information.
analyzers_.clear();
- for (PersistentMemoryAllocator::Reference tracker_ref : tracker_references_) {
- // Get the actual data segment for the tracker. This can fail if the
- // record has been marked "free" since the type will not match.
- void* base = allocator_->GetAsArray<char>(
- tracker_ref, GlobalActivityTracker::kTypeIdActivityTracker,
+ process_data_.clear();
+ process_ids_.clear();
+ std::set<int64_t> seen_pids;
+
+ // Go through all the known references and create objects for them with
+ // snapshots of the current state.
+ for (PersistentMemoryAllocator::Reference memory_ref : memory_references_) {
+ // Get the actual data segment for the tracker. Any type will do since it
+ // is checked below.
+ void* const base = allocator_->GetAsArray<char>(
+ memory_ref, PersistentMemoryAllocator::kTypeIdAny,
PersistentMemoryAllocator::kSizeAny);
+ const size_t size = allocator_->GetAllocSize(memory_ref);
if (!base)
continue;
- // Create the analyzer on the data. This will capture a snapshot of the
- // tracker state. This can fail if the tracker is somehow corrupted or is
- // in the process of shutting down.
- std::unique_ptr<ThreadActivityAnalyzer> analyzer(new ThreadActivityAnalyzer(
- base, allocator_->GetAllocSize(tracker_ref)));
- if (!analyzer->IsValid())
- continue;
- analyzer->AddGlobalInformation(this);
-
- // Add this analyzer to the map of known ones, indexed by a unique thread
- // identifier.
- DCHECK(!base::ContainsKey(analyzers_, analyzer->GetThreadKey()));
- analyzer->allocator_reference_ = ref;
- analyzers_[analyzer->GetThreadKey()] = std::move(analyzer);
+ switch (allocator_->GetType(memory_ref)) {
+ case GlobalActivityTracker::kTypeIdActivityTracker: {
+ // Create the analyzer on the data. This will capture a snapshot of the
+ // tracker state. This can fail if the tracker is somehow corrupted or
+ // is in the process of shutting down.
+ std::unique_ptr<ThreadActivityAnalyzer> analyzer(
+ new ThreadActivityAnalyzer(base, size));
+ if (!analyzer->IsValid())
+ continue;
+ analyzer->AddGlobalInformation(this);
+
+ // Track PIDs.
+ int64_t pid = analyzer->GetProcessId();
+ if (seen_pids.find(pid) == seen_pids.end()) {
+ process_ids_.push_back(pid);
+ seen_pids.insert(pid);
+ }
+
+ // Add this analyzer to the map of known ones, indexed by a unique
+ // thread
+ // identifier.
+ DCHECK(!base::ContainsKey(analyzers_, analyzer->GetThreadKey()));
+ analyzer->allocator_reference_ = ref;
+ analyzers_[analyzer->GetThreadKey()] = std::move(analyzer);
+ } break;
+
+ case GlobalActivityTracker::kTypeIdProcessDataRecord: {
+ // Get the PID associated with this data record.
+ int64_t process_id;
+ int64_t create_stamp;
+ ActivityUserData::GetOwningProcessId(base, &process_id, &create_stamp);
+ DCHECK(!base::ContainsKey(process_data_, process_id));
+
+ // Create a snapshot of the data. This can fail if the data is somehow
+ // corrupted or the process shutdown and the memory being released.
+ UserDataSnapshot& snapshot = process_data_[process_id];
+ snapshot.process_id = process_id;
+ snapshot.create_stamp = create_stamp;
+ const ActivityUserData process_data(base, size);
+ if (!process_data.CreateSnapshot(&snapshot.data))
+ break;
+
+ // Check that nothing changed. If it did, forget what was recorded.
+ ActivityUserData::GetOwningProcessId(base, &process_id, &create_stamp);
+ if (process_id != snapshot.process_id ||
+ create_stamp != snapshot.create_stamp) {
+ process_data_.erase(process_id);
+ break;
+ }
+
+ // Track PIDs.
+ if (seen_pids.find(process_id) == seen_pids.end()) {
+ process_ids_.push_back(process_id);
+ seen_pids.insert(process_id);
+ }
+ } break;
+ }
}
+
+ // Reverse the list of PIDs so that they get popped in the order found.
+ std::reverse(process_ids_.begin(), process_ids_.end());
}
} // namespace debug
« 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