Index: base/tracked_objects.h |
diff --git a/base/tracked_objects.h b/base/tracked_objects.h |
index e09b70b303f4fb4b96777d2e4bc768ad7ef5afee..25b8753794de84b54dd01da46414ac3e87247d17 100644 |
--- a/base/tracked_objects.h |
+++ b/base/tracked_objects.h |
@@ -23,7 +23,6 @@ |
#include "base/synchronization/lock.h" |
#include "base/threading/thread_local_storage.h" |
#include "base/tracking_info.h" |
-#include "base/values.h" |
// TrackedObjects provides a database of stats about objects (generally Tasks) |
// that are tracked. Tracking means their birth, death, duration, birth thread, |
@@ -129,33 +128,36 @@ |
// be able to run concurrently with ongoing augmentation of the birth and death |
// data. |
// |
-// For a given birth location, information about births is spread across data |
-// structures that are asynchronously changing on various threads. For display |
-// purposes, we need to construct Snapshot instances for each combination of |
-// birth thread, death thread, and location, along with the count of such |
-// lifetimes. We gather such data into a Snapshot instances, so that such |
-// instances can be sorted and aggregated (and remain frozen during our |
-// processing). Snapshot instances use pointers to constant portions of the |
-// birth and death datastructures, but have local (frozen) copies of the actual |
-// statistics (birth count, durations, etc. etc.). |
+// This header also exports collection of classes that provide "snapshotted" |
+// representations of the core tracked_objects:: classes. These snapshotted |
+// representations are designed for safe transmission of the tracked_objects:: |
+// data across process boundaries. Each consists of: |
+// (1) a default constructor, to support the IPC serialization macros, |
+// (2) a constructor that extracts data from the type being snapshotted, and |
+// (3) the snapshotted data. |
// |
-// A DataCollector is a container object that holds a set of Snapshots. The |
-// statistics in a snapshot are gathered asynhcronously relative to their |
-// ongoing updates. It is possible, though highly unlikely, that stats could be |
-// incorrectly recorded by this process (all data is held in 32 bit ints, but we |
-// are not atomically collecting all data, so we could have count that does not, |
-// for example, match with the number of durations we accumulated). The |
-// advantage to having fast (non-atomic) updates of the data outweighs the |
-// minimal risk of a singular corrupt statistic snapshot (only the snapshot |
-// could be corrupt, not the underlying and ongoing statistic). In constrast, |
-// pointer data that is accessed during snapshotting is completely invariant, |
-// and hence is perfectly acquired (i.e., no potential corruption, and no risk |
-// of a bad memory reference). |
+// For a given birth location, information about births is spread across data |
+// structures that are asynchronously changing on various threads. For |
+// serialization and display purposes, we need to construct TaskSnapshot |
+// instances for each combination of birth thread, death thread, and location, |
+// along with the count of such lifetimes. We gather such data into a |
+// TaskSnapshot instances, so that such instances can be sorted and |
+// aggregated (and remain frozen during our processing). |
// |
-// After an array of Snapshots instances are collected into a DataCollector, |
-// they need to be prepared for displaying our output. We currently implement a |
-// serialization into a Value hierarchy, which is automatically translated to |
-// JSON when supplied to rendering Java Scirpt. |
+// The ProcessDataSnapshot struct is a serialized representation of the list |
+// of ThreadData objects for a process. It holds a set of TaskSnapshots |
+// and tracks parent/child relationships for the executed tasks. The statistics |
+// in a snapshot are gathered asynhcronously relative to their ongoing updates. |
+// It is possible, though highly unlikely, that stats could be incorrectly |
+// recorded by this process (all data is held in 32 bit ints, but we are not |
+// atomically collecting all data, so we could have count that does not, for |
+// example, match with the number of durations we accumulated). The advantage |
+// to having fast (non-atomic) updates of the data outweighs the minimal risk of |
+// a singular corrupt statistic snapshot (only the snapshot could be corrupt, |
+// not the underlying and ongoing statistic). In constrast, pointer data that |
+// is accessed during snapshotting is completely invariant, and hence is |
+// perfectly acquired (i.e., no potential corruption, and no risk of a bad |
+// memory reference). |
// |
// TODO(jar): We can implement a Snapshot system that *tries* to grab the |
// snapshots on the source threads *when* they have MessageLoops available |
@@ -196,14 +198,8 @@ class BASE_EXPORT BirthOnThread { |
public: |
BirthOnThread(const Location& location, const ThreadData& current); |
- const Location location() const; |
- const ThreadData* birth_thread() const; |
- |
- // Insert our state (location, and thread name) into the dictionary. |
- // Use the supplied |prefix| in front of "thread_name" and "location" |
- // respectively when defining keys. |
- void ToValue(const std::string& prefix, |
- base::DictionaryValue* dictionary) const; |
+ const Location location() const { return location_; } |
+ const ThreadData* birth_thread() const { return birth_thread_; } |
private: |
// File/lineno of birth. This defines the essence of the task, as the context |
@@ -219,6 +215,18 @@ class BASE_EXPORT BirthOnThread { |
}; |
//------------------------------------------------------------------------------ |
+// A "snapshotted" representation of the BirthOnThread class. |
+ |
+struct BASE_EXPORT BirthOnThreadSnapshot { |
+ BirthOnThreadSnapshot(); |
+ explicit BirthOnThreadSnapshot(const BirthOnThread& birth); |
+ ~BirthOnThreadSnapshot(); |
+ |
+ LocationSnapshot location; |
+ std::string thread_name; |
+}; |
+ |
+//------------------------------------------------------------------------------ |
// A class for accumulating counts of births (without bothering with a map<>). |
class BASE_EXPORT Births: public BirthOnThread { |
@@ -227,7 +235,7 @@ class BASE_EXPORT Births: public BirthOnThread { |
int birth_count() const; |
- // When we have a birth we update the count for this BirhPLace. |
+ // When we have a birth we update the count for this birthplace. |
void RecordBirth(); |
// When a birthplace is changed (updated), we need to decrement the counter |
@@ -265,7 +273,7 @@ class BASE_EXPORT DeathData { |
const int32 run_duration, |
int random_number); |
- // Metrics accessors, used only in tests. |
+ // Metrics accessors, used only for serialization and in tests. |
int count() const; |
int32 run_duration_sum() const; |
int32 run_duration_max() const; |
@@ -274,10 +282,6 @@ class BASE_EXPORT DeathData { |
int32 queue_duration_max() const; |
int32 queue_duration_sample() const; |
- // Construct a DictionaryValue instance containing all our stats. The caller |
- // assumes ownership of the returned instance. |
- base::DictionaryValue* ToValue() const; |
- |
// Reset the max values to zero. |
void ResetMax(); |
@@ -296,40 +300,46 @@ class BASE_EXPORT DeathData { |
// but rarely updated. |
int32 run_duration_max_; |
int32 queue_duration_max_; |
- // Samples, used by by crowd sourcing gatherers. These are almost never read, |
+ // Samples, used by crowd sourcing gatherers. These are almost never read, |
// and rarely updated. |
int32 run_duration_sample_; |
int32 queue_duration_sample_; |
}; |
//------------------------------------------------------------------------------ |
+// A "snapshotted" representation of the DeathData class. |
+ |
+struct BASE_EXPORT DeathDataSnapshot { |
+ DeathDataSnapshot(); |
+ explicit DeathDataSnapshot(const DeathData& death_data); |
+ ~DeathDataSnapshot(); |
+ |
+ int count; |
+ int32 run_duration_sum; |
+ int32 run_duration_max; |
+ int32 run_duration_sample; |
+ int32 queue_duration_sum; |
+ int32 queue_duration_max; |
+ int32 queue_duration_sample; |
+}; |
+ |
+//------------------------------------------------------------------------------ |
// A temporary collection of data that can be sorted and summarized. It is |
// gathered (carefully) from many threads. Instances are held in arrays and |
// processed, filtered, and rendered. |
// The source of this data was collected on many threads, and is asynchronously |
// changing. The data in this instance is not asynchronously changing. |
-class BASE_EXPORT Snapshot { |
- public: |
- // When snapshotting a full life cycle set (birth-to-death), use this: |
- Snapshot(const BirthOnThread& birth_on_thread, |
- const ThreadData& death_thread, |
- const DeathData& death_data); |
+struct BASE_EXPORT TaskSnapshot { |
+ TaskSnapshot(); |
+ TaskSnapshot(const BirthOnThread& birth, |
+ const DeathData& death_data, |
+ const std::string& death_thread_name); |
+ ~TaskSnapshot(); |
- // When snapshotting a birth, with no death yet, use this: |
- Snapshot(const BirthOnThread& birth_on_thread, int count); |
- |
- // Accessor, that provides default value when there is no death thread. |
- const std::string DeathThreadName() const; |
- |
- // Construct a DictionaryValue instance containing all our data recursively. |
- // The caller assumes ownership of the memory in the returned instance. |
- base::DictionaryValue* ToValue() const; |
- |
- private: |
- const BirthOnThread* birth_; // Includes Location and birth_thread. |
- const ThreadData* death_thread_; |
- DeathData death_data_; |
+ BirthOnThreadSnapshot birth; |
+ DeathDataSnapshot death_data; |
+ std::string death_thread_name; |
}; |
//------------------------------------------------------------------------------ |
@@ -339,6 +349,7 @@ class BASE_EXPORT Snapshot { |
// We also have a linked list of ThreadData instances, and that list is used to |
// harvest data from all existing instances. |
+struct ProcessDataSnapshot; |
class BASE_EXPORT ThreadData { |
public: |
// Current allowable states of the tracking system. The states can vary |
@@ -369,11 +380,10 @@ class BASE_EXPORT ThreadData { |
// This may return NULL if the system is disabled for any reason. |
static ThreadData* Get(); |
- // Constructs a DictionaryValue instance containing all recursive results in |
- // our process. The caller assumes ownership of the memory in the returned |
- // instance. During the scavenging, if |reset_max| is true, then the |
- // DeathData instances max-values are reset to zero during this scan. |
- static base::DictionaryValue* ToValue(bool reset_max); |
+ // Fills |process_data| with all the recursive results in our process. |
+ // During the scavenging, if |reset_max| is true, then the DeathData instances |
+ // max-values are reset to zero during this scan. |
+ static void Snapshot(bool reset_max, ProcessDataSnapshot* process_data); |
// Finds (or creates) a place to count births from the given location in this |
// thread, and increment that tally. |
@@ -415,12 +425,6 @@ class BASE_EXPORT ThreadData { |
const std::string thread_name() const; |
- // Snapshot (under a lock) copies of the maps in each ThreadData instance. For |
- // each set of maps (BirthMap, DeathMap, and ParentChildSet) call the Append() |
- // method of the |target| DataCollector. If |reset_max| is true, then the max |
- // values in each DeathData instance should be reset during the scan. |
- static void SendAllMaps(bool reset_max, class DataCollector* target); |
- |
// Hack: asynchronously clear all birth counts and death tallies data values |
// in all ThreadData instances. The numerical (zeroing) part is done without |
// use of a locks or atomics exchanges, and may (for int64 values) produce |
@@ -490,6 +494,8 @@ class BASE_EXPORT ThreadData { |
FRIEND_TEST_ALL_PREFIXES(TrackedObjectsTest, TinyStartupShutdown); |
FRIEND_TEST_ALL_PREFIXES(TrackedObjectsTest, ParentChildTest); |
+ typedef std::map<const BirthOnThread*, int> BirthCountMap; |
+ |
// Worker thread construction creates a name since there is none. |
explicit ThreadData(int thread_number); |
@@ -516,6 +522,27 @@ class BASE_EXPORT ThreadData { |
// Find a place to record a death on this thread. |
void TallyADeath(const Births& birth, int32 queue_duration, int32 duration); |
+ // Snapshot (under a lock) the profiled data for the tasks in each ThreadData |
+ // instance. Also updates the |birth_counts| tally for each task to keep |
+ // track of the number of living instances of the task. If |reset_max| is |
+ // true, then the max values in each DeathData instance are reset during the |
+ // scan. |
+ static void SnapshotAllExecutedTasks(bool reset_max, |
+ ProcessDataSnapshot* process_data, |
+ BirthCountMap* birth_counts); |
+ |
+ // Snapshots (under a lock) the profiled data for the tasks for this thread |
+ // and writes all of the executed tasks' data -- i.e. the data for the tasks |
+ // with with entries in the death_map_ -- into |process_data|. Also updates |
+ // the |birth_counts| tally for each task to keep track of the number of |
+ // living instances of the task -- that is, each task maps to the number of |
+ // births for the task that have not yet been balanced by a death. If |
+ // |reset_max| is true, then the max values in each DeathData instance are |
+ // reset during the scan. |
+ void SnapshotExecutedTasks(bool reset_max, |
+ ProcessDataSnapshot* process_data, |
+ BirthCountMap* birth_counts); |
+ |
// Using our lock, make a copy of the specified maps. This call may be made |
// on non-local threads, which necessitate the use of the lock to prevent |
// the map(s) from being reallocaed while they are copied. If |reset_max| is |
@@ -660,56 +687,31 @@ class BASE_EXPORT ThreadData { |
}; |
//------------------------------------------------------------------------------ |
-// DataCollector is a container class for Snapshot and BirthOnThread count |
-// items. |
+// A snapshotted representation of a (parent, child) task pair, for tracking |
+// hierarchical profiles. |
-class BASE_EXPORT DataCollector { |
+struct BASE_EXPORT ParentChildPairSnapshot { |
public: |
- typedef std::vector<Snapshot> Collection; |
- |
- // Construct with a list of how many threads should contribute. This helps us |
- // determine (in the async case) when we are done with all contributions. |
- DataCollector(); |
- ~DataCollector(); |
- |
- // Adds all stats from the indicated thread into our arrays. Accepts copies |
- // of the birth_map and death_map, so that the data will not change during the |
- // iterations and processing. |
- void Append(const ThreadData &thread_data, |
- const ThreadData::BirthMap& birth_map, |
- const ThreadData::DeathMap& death_map, |
- const ThreadData::ParentChildSet& parent_child_set); |
- |
- // After the accumulation phase, the following accessor is used to process the |
- // data (i.e., sort it, filter it, etc.). |
- Collection* collection(); |
- |
- // Adds entries for all the remaining living objects (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). |
- // This should be called after all known ThreadData instances have been |
- // processed using Append(). |
- void AddListOfLivingObjects(); |
- |
- // Generates a ListValue representation of the vector of snapshots, and |
- // inserts the results into |dictionary|. |
- void ToValue(base::DictionaryValue* dictionary) const; |
- |
- private: |
- typedef std::map<const BirthOnThread*, int> BirthCount; |
+ ParentChildPairSnapshot(); |
+ explicit ParentChildPairSnapshot( |
+ const ThreadData::ParentChildPair& parent_child); |
+ ~ParentChildPairSnapshot(); |
- // The array that we collect data into. |
- Collection collection_; |
+ BirthOnThreadSnapshot parent; |
+ BirthOnThreadSnapshot child; |
+}; |
- // The total number of births recorded at each location for which we have not |
- // seen a death count. This map changes as we do Append() calls, and is later |
- // used by AddListOfLivingObjects() to gather up unaccounted for births. |
- BirthCount global_birth_count_; |
+//------------------------------------------------------------------------------ |
+// A snapshotted representation of the list of ThreadData objects for a process. |
- // The complete list of parent-child relationships among tasks. |
- ThreadData::ParentChildSet parent_child_set_; |
+struct BASE_EXPORT ProcessDataSnapshot { |
+ public: |
+ ProcessDataSnapshot(); |
+ ~ProcessDataSnapshot(); |
- DISALLOW_COPY_AND_ASSIGN(DataCollector); |
+ std::vector<TaskSnapshot> tasks; |
+ std::vector<ParentChildPairSnapshot> descendants; |
+ int process_id; |
}; |
} // namespace tracked_objects |