Index: base/tracked_objects.h |
=================================================================== |
--- base/tracked_objects.h (revision 112568) |
+++ base/tracked_objects.h (working copy) |
@@ -12,6 +12,7 @@ |
#include <vector> |
#include "base/base_export.h" |
+#include "base/gtest_prod_util.h" |
ramant (doing other things)
2011/12/03 17:36:26
hi Jim,
In the tip this file is deleted. New cod
ramant (doing other things)
2011/12/03 22:48:39
This comment was in the wrong file. I meant to add
jar (doing other things)
2011/12/04 00:46:22
No problem... I understood.
On 2011/12/03 22:48:3
|
#include "base/lazy_instance.h" |
#include "base/location.h" |
#include "base/profiler/tracked_time.h" |
@@ -197,8 +198,8 @@ |
public: |
BirthOnThread(const Location& location, const ThreadData& current); |
- const Location location() const { return location_; } |
- const ThreadData* birth_thread() const { return birth_thread_; } |
+ const Location location() const; |
+ const ThreadData* birth_thread() const; |
private: |
// File/lineno of birth. This defines the essence of the task, as the context |
@@ -220,17 +221,17 @@ |
public: |
Births(const Location& location, const ThreadData& current); |
- int birth_count() const { return birth_count_; } |
+ int birth_count() const; |
// When we have a birth we update the count for this BirhPLace. |
- void RecordBirth() { ++birth_count_; } |
+ void RecordBirth(); |
// When a birthplace is changed (updated), we need to decrement the counter |
// for the old instance. |
- void ForgetBirth() { --birth_count_; } // We corrected a birth place. |
+ void ForgetBirth(); |
// Hack to quickly reset all counts to zero. |
- void Clear() { birth_count_ = 0; } |
+ void Clear(); |
private: |
// The number of births on this thread for our location_. |
@@ -247,70 +248,49 @@ |
class BASE_EXPORT DeathData { |
public: |
// Default initializer. |
- DeathData() : count_(0) {} |
+ DeathData(); |
// When deaths have not yet taken place, and we gather data from all the |
// threads, we create DeathData stats that tally the number of births without |
- // a corrosponding death. |
- explicit DeathData(int count) |
- : count_(count) {} |
+ // a corresponding death. |
+ explicit DeathData(int count); |
// Update stats for a task destruction (death) that had a Run() time of |
// |duration|, and has had a queueing delay of |queue_duration|. |
- void RecordDeath(DurationInt queue_duration, |
- DurationInt run_duration); |
+ void RecordDeath(const DurationInt queue_duration, |
+ const DurationInt run_duration, |
+ int random_number); |
- // Metrics accessors. |
- int count() const { return count_; } |
- DurationInt run_duration() const { return run_time_.duration(); } |
- DurationInt AverageMsRunDuration() const; |
- DurationInt run_duration_max() const { return run_time_.max(); } |
- DurationInt queue_duration() const { return queue_time_.duration(); } |
- DurationInt AverageMsQueueDuration() const; |
- DurationInt queue_duration_max() const { return queue_time_.max(); } |
+ // Metrics accessors, used only in tests. |
+ int count() const; |
+ DurationInt run_duration_sum() const; |
+ DurationInt run_duration_max() const; |
+ DurationInt run_duration_sample() const; |
+ DurationInt queue_duration_sum() const; |
+ DurationInt queue_duration_max() const; |
+ DurationInt queue_duration_sample() const; |
- // Accumulate metrics from other into this. This method is never used on |
- // realtime statistics, and only used in snapshots and aggregatinos. |
- void AddDeathData(const DeathData& other); |
- |
// 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(); |
+ |
// Reset all tallies to zero. This is used as a hack on realtime data. |
void Clear(); |
private: |
- // DeathData::Data is a helper class, useful when different metrics need to be |
- // aggregated, such as queueing times, or run times. |
- class Data { |
- public: |
- Data() : duration_(0), max_(0) {} |
- ~Data() {} |
- |
- DurationInt duration() const { return duration_; } |
- DurationInt max() const { return max_; } |
- |
- // Agggegate data into our state. |
- void AddData(const Data& other); |
- void AddDuration(DurationInt duration); |
- |
- // Central helper function for calculating averages (correctly, in only one |
- // place). |
- DurationInt AverageMsDuration(int count) const; |
- |
- // Resets all members to zero. |
- void Clear(); |
- |
- private: |
- DurationInt duration_; // Sum of all durations seen. |
- DurationInt max_; // Largest singular duration seen. |
- }; |
- |
- |
- int count_; // Number of deaths seen. |
- Data run_time_; // Data about run time durations. |
- Data queue_time_; // Data about queueing times durations. |
+ // Number of runs seen. |
+ int count_; |
+ // Data about run time durations. |
+ DurationInt run_duration_sum_; |
+ DurationInt run_duration_max_; |
+ DurationInt run_duration_sample_; |
+ // Data about queueing times durations. |
+ DurationInt queue_duration_sum_; |
+ DurationInt queue_duration_max_; |
+ DurationInt queue_duration_sample_; |
}; |
//------------------------------------------------------------------------------ |
@@ -329,29 +309,9 @@ |
// When snapshotting a birth, with no death yet, use this: |
Snapshot(const BirthOnThread& birth_on_thread, int count); |
- const ThreadData* birth_thread() const { return birth_->birth_thread(); } |
- const Location location() const { return birth_->location(); } |
- const BirthOnThread& birth() const { return *birth_; } |
- const ThreadData* death_thread() const {return death_thread_; } |
- const DeathData& death_data() const { return death_data_; } |
+ // Accessor, that provides default value when there is no death thread. |
const std::string DeathThreadName() const; |
- int count() const { return death_data_.count(); } |
- DurationInt run_duration() const { return death_data_.run_duration(); } |
- DurationInt AverageMsRunDuration() const { |
- return death_data_.AverageMsRunDuration(); |
- } |
- DurationInt run_duration_max() const { |
- return death_data_.run_duration_max(); |
- } |
- DurationInt queue_duration() const { return death_data_.queue_duration(); } |
- DurationInt AverageMsQueueDuration() const { |
- return death_data_.AverageMsQueueDuration(); |
- } |
- DurationInt queue_duration_max() const { |
- return death_data_.queue_duration_max(); |
- } |
- |
// Construct a DictionaryValue instance containing all our data recursively. |
// The caller assumes ownership of the memory in the returned instance. |
base::DictionaryValue* ToValue() const; |
@@ -363,53 +323,6 @@ |
}; |
//------------------------------------------------------------------------------ |
-// DataCollector is a container class for Snapshot and BirthOnThread count |
-// items. |
- |
-class BASE_EXPORT DataCollector { |
- 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. This function |
- // uses locks at the lowest level (when accessing the underlying maps which |
- // could change when not locked), and can be called from any threads. |
- void Append(const ThreadData& thread_data); |
- |
- // 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. The caller |
- // assumes ownership of the memory in the returned instance. |
- base::ListValue* ToValue() const; |
- |
- private: |
- typedef std::map<const BirthOnThread*, int> BirthCount; |
- |
- // The array that we collect data into. |
- Collection collection_; |
- |
- // 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_; |
- |
- DISALLOW_COPY_AND_ASSIGN(DataCollector); |
-}; |
- |
-//------------------------------------------------------------------------------ |
// For each thread, we have a ThreadData that stores all tracking info generated |
// on this thread. This prevents the need for locking as data accumulates. |
// We use ThreadLocalStorage to quickly identfy the current ThreadData context. |
@@ -443,8 +356,9 @@ |
// Constructs a DictionaryValue instance containing all recursive results in |
// our process. The caller assumes ownership of the memory in the returned |
- // instance. |
- static base::DictionaryValue* ToValue(); |
+ // instance. During the scavenging, if |reset_value| is true, then the |
ramant (doing other things)
2011/12/03 22:48:39
reset_value -> reset_max
jar (doing other things)
2011/12/04 00:46:22
Done.
|
+ // DeathData instances max-values are reset to zero during this scan. |
+ static base::DictionaryValue* ToValue(bool reset_max); |
// Finds (or creates) a place to count births from the given location in this |
// thread, and increment that tally. |
@@ -484,24 +398,13 @@ |
const TrackedTime& start_of_run, |
const TrackedTime& end_of_run); |
- const std::string thread_name() const { return thread_name_; } |
+ const std::string thread_name() const; |
- // --------------------- |
- // TODO(jar): |
- // The following functions should all be private, and are only public because |
- // the collection is done externally. We need to relocate that code from the |
- // collection class into this class, and then all these methods can be made |
- // private. |
- // (Thread safe) Get start of list of all ThreadData instances. |
- static ThreadData* first(); |
- // Iterate through the null terminated list of ThreadData instances. |
- ThreadData* next() const { return next_; } |
- // Using our lock, make a copy of the specified maps. These calls may arrive |
- // from non-local threads, and are used to quickly scan data from all threads |
- // in order to build JSON for about:profiler. |
- void SnapshotBirthMap(BirthMap *output) const; |
- void SnapshotDeathMap(DeathMap *output) const; |
- // -------- end of should be private methods. |
+ // Snapshot (under a lock) copies of the maps in each ThreadData instance. For |
+ // each set of maps (BirthMap and DeathMap) 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 |
@@ -540,7 +443,12 @@ |
private: |
// Allow only tests to call ShutdownSingleThreadedCleanup. We NEVER call it |
// in production code. |
+ // TODO(jar): Make this a friend in DEBUG only, so that the optimizer has a |
+ // better change of optimizing (inlining? etc.) private methods (knowing that |
+ // there will be no need for an external entry point). |
friend class TrackedObjectsTest; |
+ FRIEND_TEST_ALL_PREFIXES(TrackedObjectsTest, MinimalStartupShutdown); |
+ FRIEND_TEST_ALL_PREFIXES(TrackedObjectsTest, TinyStartupShutdown); |
// Worker thread construction creates a name since there is none. |
explicit ThreadData(int thread_number); |
@@ -555,6 +463,13 @@ |
// the instance permanently on that list. |
void PushToHeadOfList(); |
+ // (Thread safe) Get start of list of all ThreadData instances using the lock. |
+ static ThreadData* first(); |
+ |
+ // Iterate through the null terminated list of ThreadData instances. |
+ ThreadData* next() const; |
+ |
+ |
// In this thread's data, record a new birth. |
Births* TallyABirth(const Location& location); |
@@ -563,6 +478,15 @@ |
DurationInt queue_duration, |
DurationInt duration); |
+ // 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 |
+ // true, then, just after we copy the DeathMap, we will set the max values to |
+ // zero in the active DeathMap (not the snapshot). |
+ void SnapshotMaps(bool reset_max, |
+ BirthMap* birth_map, |
+ DeathMap* death_map); |
+ |
// Using our lock to protect the iteration, Clear all birth and death data. |
void Reset(); |
@@ -669,10 +593,65 @@ |
// writing is only done from this thread. |
mutable base::Lock map_lock_; |
+ // A random number that we used to select decide which sample to keep as a |
+ // representative sample in each DeathData instance. We start it off "very |
+ // random" (which is expensive), and then stir in some data gently as we see |
+ // various events. |
+ int32 random_number_; |
+ |
DISALLOW_COPY_AND_ASSIGN(ThreadData); |
}; |
//------------------------------------------------------------------------------ |
+// DataCollector is a container class for Snapshot and BirthOnThread count |
+// items. |
+ |
+class BASE_EXPORT DataCollector { |
+ 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); |
+ |
+ // 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. The caller |
+ // assumes ownership of the memory in the returned instance. |
+ base::ListValue* ToValue() const; |
+ |
+ private: |
+ typedef std::map<const BirthOnThread*, int> BirthCount; |
+ |
+ // The array that we collect data into. |
+ Collection collection_; |
+ |
+ // 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_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(DataCollector); |
+}; |
+ |
+//------------------------------------------------------------------------------ |
// Provide simple way to to start global tracking, and to tear down tracking |
// when done. The design has evolved to *not* do any teardown (and just leak |
// all allocated data structures). As a result, we don't have any code in this |