Index: base/tracked_objects.h |
=================================================================== |
--- base/tracked_objects.h (revision 106875) |
+++ base/tracked_objects.h (working copy) |
@@ -7,6 +7,7 @@ |
#pragma once |
#include <map> |
+#include <stack> |
#include <string> |
#include <vector> |
@@ -15,6 +16,7 @@ |
#include "base/time.h" |
#include "base/synchronization/lock.h" |
#include "base/threading/thread_local_storage.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, |
@@ -102,8 +104,9 @@ |
// To provide a mechanism for iterating over all "known threads," which means |
// threads that have recorded a birth or a death, we create a singly linked list |
// of ThreadData instances. Each such instance maintains a pointer to the next |
-// one. A static member of ThreadData provides a pointer to the first_ item on |
-// this global list, and access to that first_ item requires the use of a lock_. |
+// one. A static member of ThreadData provides a pointer to the first item on |
+// this global list, and access via that all_thread_data_list_head_ item |
+// requires the use of the list_lock_. |
// When new ThreadData instances is added to the global list, it is pre-pended, |
// which ensures that any prior acquisition of the list is valid (i.e., the |
// holder can iterate over it without fear of it changing, or the necessity of |
@@ -169,7 +172,7 @@ |
class ThreadData; |
class BASE_EXPORT BirthOnThread { |
public: |
- explicit BirthOnThread(const Location& location); |
+ BirthOnThread(const Location& location, const ThreadData& current); |
const Location location() const { return location_; } |
const ThreadData* birth_thread() const { return birth_thread_; } |
@@ -181,8 +184,8 @@ |
const Location location_; |
// The thread that records births into this object. Only this thread is |
- // allowed to access birth_count_ (which changes over time). |
- const ThreadData* birth_thread_; // The thread this birth took place on. |
+ // allowed to update birth_count_ (which changes over time). |
+ const ThreadData* const birth_thread_; |
DISALLOW_COPY_AND_ASSIGN(BirthOnThread); |
}; |
@@ -192,7 +195,7 @@ |
class BASE_EXPORT Births: public BirthOnThread { |
public: |
- explicit Births(const Location& location); |
+ Births(const Location& location, const ThreadData& current); |
int birth_count() const { return birth_count_; } |
@@ -244,9 +247,13 @@ |
// realtime statistics, and only used in snapshots and aggregatinos. |
void AddDeathData(const DeathData& other); |
- // Simple print of internal state. |
- void Write(std::string* output) const; |
+ // Simple print of internal state for use in line of HTML. |
+ void WriteHTML(std::string* output) const; |
+ // Constructe a DictionaryValue instance containing all our stats. The caller |
eroman
2011/10/24 22:23:04
typo: construct
jar (doing other things)
2011/10/27 06:23:35
Done.
|
+ // assumes ownership of the returned instance. |
+ base::DictionaryValue* ToValue() const; |
+ |
// Reset all tallies to zero. This is used as a hack on realtime data. |
void Clear(); |
@@ -291,8 +298,13 @@ |
return death_data_.AverageMsQueueDuration(); |
} |
- void Write(std::string* output) const; |
+ // Emit contents for use in a line of HTML |
+ void WriteHTML(std::string* output) 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; |
+ |
void Add(const Snapshot& other); |
private: |
@@ -327,6 +339,10 @@ |
// remaining living objects. |
void AddListOfLivingObjects(); |
+ // Generate a ListValue representation of the vector of snapshots. The caller |
eroman
2011/10/24 22:23:04
nit: style guide says to use passive tense for fun
jar (doing other things)
2011/10/27 06:23:35
Done.
|
+ // assumes ownership of the memory in the returned instance. |
+ base::ListValue* ToValue() const; |
+ |
private: |
typedef std::map<const BirthOnThread*, int> BirthCount; |
@@ -353,7 +369,7 @@ |
void AddBirths(const Births& births); |
void AddBirth(const BirthOnThread& birth); |
void AddBirthPlace(const Location& location); |
- void Write(std::string* output) const; |
+ void WriteHTML(std::string* output) const; |
void Clear(); |
private: |
@@ -447,7 +463,7 @@ |
bool WriteSortGrouping(const Snapshot& sample, std::string* output) const; |
// Output a sample, with SortGroup details not displayed. |
- void WriteSnapshot(const Snapshot& sample, std::string* output) const; |
+ void WriteSnapshotHTML(const Snapshot& sample, std::string* output) const; |
private: |
// The selector directs this instance to compare based on the specified |
@@ -492,57 +508,58 @@ |
// Using Thread Local Store, find the current instance for collecting data. |
// If an instance does not exist, construct one (and remember it for use on |
// this thread. |
- // If shutdown has already started, and we don't yet have an instance, then |
- // return null. |
+ // This may return NULL if the system is disabled for any reason. |
static ThreadData* Get(); |
// For a given (unescaped) about:tracking query, develop resulting HTML, and |
// append to output. |
static void WriteHTML(const std::string& query, std::string* output); |
+ // Constructe a ListValue instance containing all recursive results in our |
eroman
2011/10/24 22:23:04
typo construct.
jar (doing other things)
2011/10/27 06:23:35
Done.
|
+ // process. The caller assumes ownership of the memory in the returned |
+ // instance. The |process_type| should become an enum, which corresponds |
+ // to all possible process types. I'm using an int as a placeholder. |
+ static base::Value* ToValue(int process_type); |
eroman
2011/10/24 22:23:04
not sure about this process_type parameter.
jar (doing other things)
2011/10/27 06:23:35
Rephrased as a TODO task.
|
+ |
// For a given accumulated array of results, use the comparator to sort and |
// subtotal, writing the results to the output. |
static void WriteHTMLTotalAndSubtotals( |
const DataCollector::Collection& match_array, |
const Comparator& comparator, std::string* output); |
- // In this thread's data, record a new birth. |
- Births* TallyABirth(const Location& location); |
- |
- // Find a place to record a death on this thread. |
- void TallyADeath(const Births& the_birth, |
- const base::TimeDelta& queue_duration, |
- const base::TimeDelta& duration); |
- |
- // Helper methods to only tally if the current thread has tracking active. |
- // |
+ // Find (or create) a place to count births from the given location in this |
+ // thread, and increment that tally. |
// TallyABirthIfActive will returns NULL if the birth cannot be tallied. |
static Births* TallyABirthIfActive(const Location& location); |
- // Record the end of a timed run of an object. The |the_birth| is the record |
- // for the instance, the |time_posted| and |start_of_run| are times of posting |
+ // Record the end of a timed run of an object. The |birth| is the record for |
+ // the instance, the |time_posted| and |start_of_run| are times of posting |
// into a message loop queue, and of starting to perform the run of the task. |
- // Implied is that the run just (Now()) ended. The current_message_loop is |
- // optional, and only used in DEBUG mode (when supplied) to verify that the |
- // ThreadData has a thread name that does indeed match the given loop's |
- // associated thread name (in RELEASE mode, its use is compiled away). |
- static void TallyADeathIfActive(const Births* the_birth, |
+ // The |end_of_run| was just obtained by a call to Now() (just after the task |
+ // finished). |
+ static void TallyADeathIfActive(const Births* birth, |
const base::TimeTicks& time_posted, |
const base::TimeTicks& delayed_start_time, |
- const base::TimeTicks& start_of_run); |
+ const base::TimeTicks& start_of_run, |
+ const base::TimeTicks& end_of_run); |
- // (Thread safe) Get start of list of instances. |
+ const std::string thread_name() const { return thread_name_; } |
+ |
+ // --------------------- |
+ // 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 instances. |
+ // Iterate through the null terminated list of ThreadData instances. |
ThreadData* next() const { return next_; } |
- |
- const std::string thread_name() const { return thread_name_; } |
- |
// 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 an HTML page for about:tracking. |
void SnapshotBirthMap(BirthMap *output) const; |
void SnapshotDeathMap(DeathMap *output) const; |
+ // -------- end of should be private methods. |
// Hack: asynchronously clear all birth counts and death tallies data values |
// in all ThreadData instances. The numerical (zeroing) part is done without |
@@ -550,9 +567,6 @@ |
// bogus counts VERY rarely. |
static void ResetAllThreadData(); |
- // Using our lock to protect the iteration, Clear all birth and death data. |
- void Reset(); |
- |
// Set internal status_ to either become ACTIVE, or later, to be SHUTDOWN, |
// based on argument being true or false respectively. |
// IF tracking is not compiled in, this function will return false. |
@@ -573,18 +587,6 @@ |
static void ShutdownSingleThreadedCleanup(); |
private: |
- // Worker thread construction creates a name. |
- ThreadData(); |
- // Message loop based construction should provide a name. |
- explicit ThreadData(const std::string& suggested_name); |
- |
- ~ThreadData(); |
- |
- // Enter a new instance into Thread Local Store. |
- // Return the instance, or null if we can't register it (because we're |
- // shutting down). |
- static ThreadData* RegisterCurrentContext(ThreadData* unregistered); |
- |
// Current allowable states of the tracking system. The states always |
// proceed towards SHUTDOWN, and never go backwards. |
enum Status { |
@@ -593,12 +595,52 @@ |
SHUTDOWN, |
}; |
+ typedef std::stack<const ThreadData*> ThreadDataPool; |
+ |
+ // Worker thread construction creates a name since there is none. |
+ ThreadData(); |
+ // Message loop based construction should provide a name. |
+ explicit ThreadData(const std::string& suggested_name); |
+ |
+ ~ThreadData(); |
+ |
+ // Push this instance to the head of all_thread_data_list_head_, linking it to |
+ // the previous head. This is performed after each construction, and leaves |
+ // the instance permanently on that list. |
+ void PushToHeadOfList(); |
+ |
+ // In this thread's data, record a new birth. |
+ Births* TallyABirth(const Location& location); |
+ |
+ // Find a place to record a death on this thread. |
+ void TallyADeath(const Births& birth, |
+ const base::TimeDelta& queue_duration, |
+ const base::TimeDelta& duration); |
+ |
+ // Using our lock to protect the iteration, Clear all birth and death data. |
+ void Reset(); |
+ |
+ // This method is called by the TLS system when a thread terminates. |
+ // The argument may be NULL if this thread has never tracked a birth or death. |
+ static void OnThreadTermination(void* thread_data); |
+ |
+ // This method should be called when a worker thread terminates, so that we |
+ // can save all the thread data into a cache of reusable ThreadData instances. |
+ void OnThreadTerminationCleanup() const; |
+ |
// We use thread local store to identify which ThreadData to interact with. |
static base::ThreadLocalStorage::Slot tls_index_; |
// Link to the most recently created instance (starts a null terminated list). |
- static ThreadData* first_; |
- // Protection for access to first_. |
+ // The list is traversed by about:tracking when it needs to snapshot data. |
+ static ThreadData* all_thread_data_list_head_; |
+ // Set of ThreadData instances for use with worker threads. When a worker |
+ // thread is done (terminating), we push it into this pool. When a new worker |
+ // thread is created, we first try to re-use a ThreadData instance from the |
+ // pool, and if none are available, construct a new one. |
+ static ThreadDataPool* unregistered_thread_data_pool_; |
+ // Protection for access to all_thread_data_list_head_, and to |
+ // unregistered_thread_data_pool_. |
static base::Lock list_lock_; |
// We set status_ to SHUTDOWN when we shut down the tracking service. |
@@ -613,6 +655,10 @@ |
// message_loop, then this is a worker thread, with a sequence number postfix. |
std::string thread_name_; |
+ // Indicate if this is a worker thread, and the ThreadData contexts should be |
+ // stored in the unregistered_thread_data_pool_ when not in use. |
+ bool is_a_worker_thread_; |
+ |
// A map used on each thread to keep track of Births on this thread. |
// This map should only be accessed on the thread it was constructed on. |
// When a snapshot is needed, this structure can be locked in place for the |
@@ -635,22 +681,17 @@ |
// The next available thread number. This should only be accessed when the |
// list_lock_ is held. |
- static int thread_number_counter; |
+ static int thread_number_counter_; |
DISALLOW_COPY_AND_ASSIGN(ThreadData); |
}; |
//------------------------------------------------------------------------------ |
// Provide simple way to to start global tracking, and to tear down tracking |
-// when done. Note that construction and destruction of this object must be |
-// done when running in threaded mode (before spawning a lot of threads |
-// for construction, and after shutting down all the threads for destruction). |
+// 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 |
+// destructor, and perhaps this whole class should go away. |
-// To prevent grabbing thread local store resources time and again if someone |
-// chooses to try to re-run the browser many times, we maintain global state and |
-// only allow the tracking system to be started up at most once, and shutdown |
-// at most once. See bug 31344 for an example. |
- |
class BASE_EXPORT AutoTracking { |
public: |
AutoTracking() { |
@@ -661,28 +702,18 @@ |
} |
~AutoTracking() { |
-#ifndef NDEBUG |
- if (state_ != kRunning) |
- return; |
- // We don't do cleanup of any sort in Release build because it is a |
- // complete waste of time. Since Chromium doesn't join all its thread and |
- // guarantee we're in a single threaded mode, we don't even do cleanup in |
- // debug mode, as it will generate race-checker warnings. |
-#endif |
} |
private: |
enum State { |
kNeverBeenRun, |
kRunning, |
- kTornDownAndStopped, |
}; |
static State state_; |
DISALLOW_COPY_AND_ASSIGN(AutoTracking); |
}; |
- |
} // namespace tracked_objects |
#endif // BASE_TRACKED_OBJECTS_H_ |