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

Unified Diff: base/tracked_objects.cc

Issue 10077001: [UMA] Use proper C++ objects to serialize tracked_objects across process boundaries. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix yet another IWYU in the chromeos/ code... Created 8 years, 8 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/tracked_objects.h ('k') | base/tracked_objects_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: base/tracked_objects.cc
diff --git a/base/tracked_objects.cc b/base/tracked_objects.cc
index 1db578e38157c5f3a9896d14fb4067f2014f39da..38b9320eb5a653d6db254633f7483bd6d8d9c00a 100644
--- a/base/tracked_objects.cc
+++ b/base/tracked_objects.cc
@@ -8,11 +8,12 @@
#include <stdlib.h>
#include "base/format_macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/process_util.h"
#include "base/profiler/alternate_timer.h"
#include "base/stringprintf.h"
#include "base/third_party/valgrind/memcheck.h"
#include "base/threading/thread_restrictions.h"
-#include "build/build_config.h"
#include "base/port.h"
using base::TimeDelta;
@@ -24,6 +25,8 @@ namespace {
// Flag to compile out almost all of the task tracking code.
const bool kTrackAllTaskObjects = true;
+// TODO(jar): Evaluate the perf impact of enabling this. If the perf impact is
+// negligible, enable by default.
// Flag to compile out parent-child link recording.
const bool kTrackParentChildLinks = false;
@@ -44,6 +47,7 @@ const ThreadData::Status kInitialStartupState =
// can be flipped to efficiently disable this path (if there is a performance
// problem with its presence).
static const bool kAllowAlternateTimeSourceHandling = true;
+
} // namespace
//------------------------------------------------------------------------------
@@ -113,25 +117,6 @@ int32 DeathData::queue_duration_sample() const {
return queue_duration_sample_;
}
-
-base::DictionaryValue* DeathData::ToValue() const {
- base::DictionaryValue* dictionary = new base::DictionaryValue;
- dictionary->Set("count", base::Value::CreateIntegerValue(count_));
- dictionary->Set("run_ms",
- base::Value::CreateIntegerValue(run_duration_sum()));
- dictionary->Set("run_ms_max",
- base::Value::CreateIntegerValue(run_duration_max()));
- dictionary->Set("run_ms_sample",
- base::Value::CreateIntegerValue(run_duration_sample()));
- dictionary->Set("queue_ms",
- base::Value::CreateIntegerValue(queue_duration_sum()));
- dictionary->Set("queue_ms_max",
- base::Value::CreateIntegerValue(queue_duration_max()));
- dictionary->Set("queue_ms_sample",
- base::Value::CreateIntegerValue(queue_duration_sample()));
- return dictionary;
-}
-
void DeathData::ResetMax() {
run_duration_max_ = 0;
queue_duration_max_ = 0;
@@ -148,20 +133,48 @@ void DeathData::Clear() {
}
//------------------------------------------------------------------------------
+DeathDataSnapshot::DeathDataSnapshot()
+ : count(-1),
+ run_duration_sum(-1),
+ run_duration_max(-1),
+ run_duration_sample(-1),
+ queue_duration_sum(-1),
+ queue_duration_max(-1),
+ queue_duration_sample(-1) {
+}
+
+DeathDataSnapshot::DeathDataSnapshot(
+ const tracked_objects::DeathData& death_data)
+ : count(death_data.count()),
+ run_duration_sum(death_data.run_duration_sum()),
+ run_duration_max(death_data.run_duration_max()),
+ run_duration_sample(death_data.run_duration_sample()),
+ queue_duration_sum(death_data.queue_duration_sum()),
+ queue_duration_max(death_data.queue_duration_max()),
+ queue_duration_sample(death_data.queue_duration_sample()) {
+}
+
+DeathDataSnapshot::~DeathDataSnapshot() {
+}
+
+//------------------------------------------------------------------------------
BirthOnThread::BirthOnThread(const Location& location,
const ThreadData& current)
: location_(location),
birth_thread_(&current) {
}
-const Location BirthOnThread::location() const { return location_; }
-const ThreadData* BirthOnThread::birth_thread() const { return birth_thread_; }
+//------------------------------------------------------------------------------
+BirthOnThreadSnapshot::BirthOnThreadSnapshot() {
+}
+
+BirthOnThreadSnapshot::BirthOnThreadSnapshot(
+ const tracked_objects::BirthOnThread& birth)
+ : location(birth.location()),
+ thread_name(birth.birth_thread()->thread_name()) {
+}
-void BirthOnThread::ToValue(const std::string& prefix,
- base::DictionaryValue* dictionary) const {
- dictionary->Set(prefix + "_location", location_.ToValue());
- dictionary->Set(prefix + "_thread",
- base::Value::CreateStringValue(birth_thread_->thread_name()));
+BirthOnThreadSnapshot::~BirthOnThreadSnapshot() {
}
//------------------------------------------------------------------------------
@@ -334,14 +347,23 @@ void ThreadData::OnThreadTerminationCleanup() {
}
// static
-base::DictionaryValue* ThreadData::ToValue(bool reset_max) {
- DataCollector collected_data; // Gather data.
- // Request multiple calls to collected_data.Append() for all threads.
- SendAllMaps(reset_max, &collected_data);
- collected_data.AddListOfLivingObjects(); // Add births that are still alive.
- base::DictionaryValue* dictionary = new base::DictionaryValue();
- collected_data.ToValue(dictionary);
- return dictionary;
+void ThreadData::Snapshot(bool reset_max, ProcessDataSnapshot* process_data) {
+ // Add births that have run to completion to |collected_data|.
+ // |birth_counts| tracks the total number of births recorded at each location
+ // for which we have not seen a death count.
+ BirthCountMap birth_counts;
+ ThreadData::SnapshotAllExecutedTasks(reset_max, process_data, &birth_counts);
+
+ // Add births that are still active -- i.e. objects that have tallied a birth,
+ // but have not yet tallied a matching death, and hence must be either
+ // running, queued up, or being held in limbo for future posting.
+ for (BirthCountMap::const_iterator it = birth_counts.begin();
+ it != birth_counts.end(); ++it) {
+ if (it->second > 0) {
+ process_data->tasks.push_back(
+ TaskSnapshot(*it->first, DeathData(it->second), "Still_Alive"));
+ }
+ }
}
Births* ThreadData::TallyABirth(const Location& location) {
@@ -527,6 +549,60 @@ void ThreadData::TallyRunInAScopedRegionIfTracking(
const std::string ThreadData::thread_name() const { return thread_name_; }
+// static
+void ThreadData::SnapshotAllExecutedTasks(bool reset_max,
+ ProcessDataSnapshot* process_data,
+ BirthCountMap* birth_counts) {
+ if (!kTrackAllTaskObjects)
+ return; // Not compiled in.
+
+ // Get an unchanging copy of a ThreadData list.
+ ThreadData* my_list = ThreadData::first();
+
+ // Gather data serially.
+ // This hackish approach *can* get some slighly corrupt tallies, as we are
+ // grabbing values without the protection of a lock, but it has the advantage
+ // of working even with threads that don't have message loops. If a user
+ // sees any strangeness, they can always just run their stats gathering a
+ // second time.
+ for (ThreadData* thread_data = my_list;
+ thread_data;
+ thread_data = thread_data->next()) {
+ thread_data->SnapshotExecutedTasks(reset_max, process_data, birth_counts);
+ }
+}
+
+void ThreadData::SnapshotExecutedTasks(bool reset_max,
+ ProcessDataSnapshot* process_data,
+ BirthCountMap* birth_counts) {
+ // Get copy of data, so that the data will not change during the iterations
+ // and processing.
+ ThreadData::BirthMap birth_map;
+ ThreadData::DeathMap death_map;
+ ThreadData::ParentChildSet parent_child_set;
+ SnapshotMaps(reset_max, &birth_map, &death_map, &parent_child_set);
+
+ for (ThreadData::DeathMap::const_iterator it = death_map.begin();
+ it != death_map.end(); ++it) {
+ process_data->tasks.push_back(
+ TaskSnapshot(*it->first, it->second, thread_name()));
+ (*birth_counts)[it->first] -= it->first->birth_count();
+ }
+
+ for (ThreadData::BirthMap::const_iterator it = birth_map.begin();
+ it != birth_map.end(); ++it) {
+ (*birth_counts)[it->second] += it->second->birth_count();
+ }
+
+ if (!kTrackParentChildLinks)
+ return;
+
+ for (ThreadData::ParentChildSet::const_iterator it = parent_child_set.begin();
+ it != parent_child_set.end(); ++it) {
+ process_data->descendants.push_back(ParentChildPairSnapshot(*it));
+ }
+}
+
// This may be called from another thread.
void ThreadData::SnapshotMaps(bool reset_max,
BirthMap* birth_map,
@@ -552,32 +628,6 @@ void ThreadData::SnapshotMaps(bool reset_max,
}
// static
-void ThreadData::SendAllMaps(bool reset_max, class DataCollector* target) {
- if (!kTrackAllTaskObjects)
- return; // Not compiled in.
- // Get an unchanging copy of a ThreadData list.
- ThreadData* my_list = ThreadData::first();
-
- // Gather data serially.
- // This hackish approach *can* get some slighly corrupt tallies, as we are
- // grabbing values without the protection of a lock, but it has the advantage
- // of working even with threads that don't have message loops. If a user
- // sees any strangeness, they can always just run their stats gathering a
- // second time.
- for (ThreadData* thread_data = my_list;
- thread_data;
- thread_data = thread_data->next()) {
- // Get copy of data.
- ThreadData::BirthMap birth_map;
- ThreadData::DeathMap death_map;
- ThreadData::ParentChildSet parent_child_set;
- thread_data->SnapshotMaps(reset_max, &birth_map, &death_map,
- &parent_child_set);
- target->Append(*thread_data, birth_map, death_map, parent_child_set);
- }
-}
-
-// static
void ThreadData::ResetAllThreadData() {
ThreadData* my_list = first();
@@ -785,107 +835,43 @@ void ThreadData::ShutdownSingleThreadedCleanup(bool leak) {
}
//------------------------------------------------------------------------------
-// Individual 3-tuple of birth (place and thread) along with death thread, and
-// the accumulated stats for instances (DeathData).
-
-Snapshot::Snapshot(const BirthOnThread& birth_on_thread,
- const ThreadData& death_thread,
- const DeathData& death_data)
- : birth_(&birth_on_thread),
- death_thread_(&death_thread),
- death_data_(death_data) {
+TaskSnapshot::TaskSnapshot() {
}
-Snapshot::Snapshot(const BirthOnThread& birth_on_thread, int count)
- : birth_(&birth_on_thread),
- death_thread_(NULL),
- death_data_(DeathData(count)) {
+TaskSnapshot::TaskSnapshot(const BirthOnThread& birth,
+ const DeathData& death_data,
+ const std::string& death_thread_name)
+ : birth(birth),
+ death_data(death_data),
+ death_thread_name(death_thread_name) {
}
-const std::string Snapshot::DeathThreadName() const {
- if (death_thread_)
- return death_thread_->thread_name();
- return "Still_Alive";
-}
-
-base::DictionaryValue* Snapshot::ToValue() const {
- base::DictionaryValue* dictionary = new base::DictionaryValue;
- // TODO(jar): Switch the next two lines to:
- // birth_->ToValue("birth", dictionary);
- // ...but that will require fixing unit tests, and JS to take
- // "birth_location" rather than "location"
- dictionary->Set("birth_thread",
- base::Value::CreateStringValue(birth_->birth_thread()->thread_name()));
- dictionary->Set("location", birth_->location().ToValue());
-
- dictionary->Set("death_data", death_data_.ToValue());
- dictionary->Set("death_thread",
- base::Value::CreateStringValue(DeathThreadName()));
- return dictionary;
+TaskSnapshot::~TaskSnapshot() {
}
//------------------------------------------------------------------------------
-// DataCollector
+// ParentChildPairSnapshot
-DataCollector::DataCollector() {}
-
-DataCollector::~DataCollector() {
+ParentChildPairSnapshot::ParentChildPairSnapshot(){
}
-void DataCollector::Append(const ThreadData& thread_data,
- const ThreadData::BirthMap& birth_map,
- const ThreadData::DeathMap& death_map,
- const ThreadData::ParentChildSet& parent_child_set) {
- for (ThreadData::DeathMap::const_iterator it = death_map.begin();
- it != death_map.end(); ++it) {
- collection_.push_back(Snapshot(*it->first, thread_data, it->second));
- global_birth_count_[it->first] -= it->first->birth_count();
- }
-
- for (ThreadData::BirthMap::const_iterator it = birth_map.begin();
- it != birth_map.end(); ++it) {
- global_birth_count_[it->second] += it->second->birth_count();
- }
-
- if (!kTrackParentChildLinks)
- return;
-
- for (ThreadData::ParentChildSet::const_iterator it = parent_child_set.begin();
- it != parent_child_set.end(); ++it) {
- parent_child_set_.insert(*it);
- }
+ParentChildPairSnapshot::ParentChildPairSnapshot(
+ const ThreadData::ParentChildPair& parent_child)
+ : parent(*parent_child.first),
+ child(*parent_child.second) {
}
-DataCollector::Collection* DataCollector::collection() {
- return &collection_;
+ParentChildPairSnapshot::~ParentChildPairSnapshot() {
}
-void DataCollector::AddListOfLivingObjects() {
- for (BirthCount::iterator it = global_birth_count_.begin();
- it != global_birth_count_.end(); ++it) {
- if (it->second > 0)
- collection_.push_back(Snapshot(*it->first, it->second));
- }
+//------------------------------------------------------------------------------
+// ProcessDataSnapshot
+
+ProcessDataSnapshot::ProcessDataSnapshot()
+ : process_id(base::GetCurrentProcId()) {
}
-void DataCollector::ToValue(base::DictionaryValue* dictionary) const {
- base::ListValue* list = new base::ListValue;
- for (size_t i = 0; i < collection_.size(); ++i) {
- list->Append(collection_[i].ToValue());
- }
- dictionary->Set("list", list);
-
- base::ListValue* descendants = new base::ListValue;
- for (ThreadData::ParentChildSet::const_iterator it =
- parent_child_set_.begin();
- it != parent_child_set_.end();
- ++it) {
- base::DictionaryValue* parent_child = new base::DictionaryValue;
- it->first->ToValue("parent", parent_child);
- it->second->ToValue("child", parent_child);
- descendants->Append(parent_child);
- }
- dictionary->Set("descendants", descendants);
+ProcessDataSnapshot::~ProcessDataSnapshot() {
}
} // namespace tracked_objects
« no previous file with comments | « base/tracked_objects.h ('k') | base/tracked_objects_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698