summaryrefslogtreecommitdiffstats
path: root/base/tracked_objects.h
diff options
context:
space:
mode:
authorjar@chromium.org <jar@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-12-04 07:19:10 +0000
committerjar@chromium.org <jar@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-12-04 07:19:10 +0000
commitb6b2b89a89a78a563232ae7a4fdc42b7d1663a07 (patch)
treef3b0110b8dc4246cb668f015f21a348f8d188caf /base/tracked_objects.h
parentc6562f4b883b37a288205a206bdadf9a37978bf3 (diff)
downloadchromium_src-b6b2b89a89a78a563232ae7a4fdc42b7d1663a07.zip
chromium_src-b6b2b89a89a78a563232ae7a4fdc42b7d1663a07.tar.gz
chromium_src-b6b2b89a89a78a563232ae7a4fdc42b7d1663a07.tar.bz2
Support incremental-max and sample in Profiler data
I also did some cleaning and refactoring in tracked_objects. We had a lot of functionality that has migrated to JS, that we didn't need (a lot of acccessors that are supplanted by the ToValue() methods. I'm anticipating that we'll move to an asynhcronous collecting of data from the profiler, so that we can bounce around to various threads and more cleanly collect samples (without risking races during data snapshots). Several of the refactors are heading in that direction. r=rtenneti tbr=jam (for microscopic content change) BUG=106291,106293 Review URL: http://codereview.chromium.org/8775061 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@112928 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/tracked_objects.h')
-rw-r--r--base/tracked_objects.h263
1 files changed, 121 insertions, 142 deletions
diff --git a/base/tracked_objects.h b/base/tracked_objects.h
index 29b2900..1eca68b 100644
--- a/base/tracked_objects.h
+++ b/base/tracked_objects.h
@@ -12,6 +12,7 @@
#include <vector>
#include "base/base_export.h"
+#include "base/gtest_prod_util.h"
#include "base/lazy_instance.h"
#include "base/location.h"
#include "base/profiler/tracked_time.h"
@@ -197,8 +198,8 @@ class BASE_EXPORT BirthOnThread {
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 @@ class BASE_EXPORT Births: public BirthOnThread {
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 Births: public BirthOnThread {
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);
-
- // 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(); }
-
- // 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);
+ void RecordDeath(const DurationInt queue_duration,
+ const DurationInt run_duration,
+ int random_number);
+
+ // 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;
// 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 @@ class BASE_EXPORT Snapshot {
// 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 @@ class BASE_EXPORT Snapshot {
};
//------------------------------------------------------------------------------
-// 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 @@ class BASE_EXPORT ThreadData {
// 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_max| is true, then the
+ // 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 @@ class BASE_EXPORT ThreadData {
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 @@ class BASE_EXPORT ThreadData {
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 @@ class BASE_EXPORT ThreadData {
// 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 @@ class BASE_EXPORT ThreadData {
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 @@ class BASE_EXPORT ThreadData {
// 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 can't start off with
+ // much randomness (because we can't call RandInt() on all our threads), so
+ // we stir in more and more as we go.
+ 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