diff options
author | jar@chromium.org <jar@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-20 04:17:07 +0000 |
---|---|---|
committer | jar@chromium.org <jar@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-20 04:17:07 +0000 |
commit | 26cdeb96d7091848b14f53c9343e2f9942c02a72 (patch) | |
tree | de877c03301ce02016c7b397244ed10efe86ddb7 /base/tracked_objects.h | |
parent | 3e6743f1653f2ce96bde0d6e918175963efe01ee (diff) | |
download | chromium_src-26cdeb96d7091848b14f53c9343e2f9942c02a72.zip chromium_src-26cdeb96d7091848b14f53c9343e2f9942c02a72.tar.gz chromium_src-26cdeb96d7091848b14f53c9343e2f9942c02a72.tar.bz2 |
Switch to a simple linked-list for worker thread pool
The goal was to avoid alloc/free during the thread
teardown callback, and this CL provides a very simple
and clear implementation.
r=rtenneti
BUG=104696
Review URL: http://codereview.chromium.org/8597017
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@110856 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/tracked_objects.h')
-rw-r--r-- | base/tracked_objects.h | 100 |
1 files changed, 48 insertions, 52 deletions
diff --git a/base/tracked_objects.h b/base/tracked_objects.h index dd1c7c4..8acddba 100644 --- a/base/tracked_objects.h +++ b/base/tracked_objects.h @@ -137,8 +137,10 @@ // // 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 such -// as a 64bit counter could be incorrectly recorded by this process. The +// 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, @@ -148,23 +150,40 @@ // // After an array of Snapshots instances are collected into a DataCollector, // they need to be prepared for displaying our output. We currently implement a -// direct rendering to HTML, but we will soon have a JSON serialization as well. - -// For direct HTML display, the data must be sorted, and possibly aggregated -// (example: how many threads are in a specific consecutive set of Snapshots? -// What was the total birth count for that set? etc.). Aggregation instances -// collect running sums of any set of snapshot instances, and are used to print -// sub-totals in an about:profiler page. +// serialization into a Value hierarchy, which is automatically translated to +// JSON when supplied to rendering Java Scirpt. +// +// TODO(jar): We can implement a Snapshot system that *tries* to grab the +// snapshots on the source threads *when* they have MessageLoops available +// (worker threads don't have message loops generally, and hence gathering from +// them will continue to be asynchronous). We had an implementation of this in +// the past, but the difficulty is dealing with message loops being terminated. +// We can *try* to spam the available threads via some message loop proxy to +// achieve this feat, and it *might* be valuable when we are colecting data for +// upload via UMA (where correctness of data may be more significant than for a +// single screen of about:profiler). +// +// TODO(jar): We need to save a single sample in each DeathData instance of the +// times recorded. This sample should be selected in a uniformly random way. // -// TODO(jar): I need to store DataCollections, and provide facilities for taking -// the difference between two gathered DataCollections. For now, I'm just -// adding a hack that Reset()s to zero all counts and stats. This is also +// TODO(jar): We should support (optionally) the recording of parent-child +// relationships for tasks. This should be done by detecting what tasks are +// Born during the running of a parent task. The resulting data can be used by +// a smarter profiler to aggregate the cost of a series of child tasks into +// the ancestor task. It can also be used to illuminate what child or parent is +// related to each task. +// +// TODO(jar): We need to store DataCollections, and provide facilities for +// taking the difference between two gathered DataCollections. For now, we're +// just adding a hack that Reset()s to zero all counts and stats. This is also // done in a slighly thread-unsafe fashion, as the resetting is done // asynchronously relative to ongoing updates (but all data is 32 bit in size). // For basic profiling, this will work "most of the time," and should be // sufficient... but storing away DataCollections is the "right way" to do this. // We'll accomplish this via JavaScript storage of snapshots, and then we'll -// remove the Reset() methods. +// remove the Reset() methods. We may also need a short-term-max value in +// DeathData that is reset (as synchronously as possible) during each snapshot. +// This will facilitate displaying a max value for each snapshot period. class MessageLoop; @@ -254,9 +273,6 @@ class BASE_EXPORT DeathData { // realtime statistics, and only used in snapshots and aggregatinos. void AddDeathData(const DeathData& other); - // Simple print of internal state for use in line of HTML. - void WriteHTML(std::string* output) const; - // Construct a DictionaryValue instance containing all our stats. The caller // assumes ownership of the returned instance. base::DictionaryValue* ToValue() const; @@ -275,10 +291,6 @@ class BASE_EXPORT DeathData { DurationInt duration() const { return duration_; } DurationInt max() const { return max_; } - // Emits HTML formated description of members, assuming |count| instances - // when calculating averages. - void WriteHTML(int count, std::string* output) const; - // Agggegate data into our state. void AddData(const Data& other); void AddDuration(DurationInt duration); @@ -486,7 +498,7 @@ class BASE_EXPORT ThreadData { 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 an HTML page for about:profiler. + // in order to build JSON for about:profiler. void SnapshotBirthMap(BirthMap *output) const; void SnapshotDeathMap(DeathMap *output) const; // -------- end of should be private methods. @@ -525,30 +537,8 @@ class BASE_EXPORT ThreadData { // in production code. friend class TrackedObjectsTest; - // Implment a stack that avoids allocations during a push() by having enough - // space ahead of time. - class ThreadDataPool { - public: - ThreadDataPool(); - ~ThreadDataPool(); - - // Make sure the stack is large enough to support the indicated number of - // elements. - void reserve(size_t largest_worker_pool_number); - - bool empty() const; - const ThreadData* top() const; - void push(const ThreadData* thread_data); - void pop(); - - private: - std::vector<const ThreadData*> stack_; - size_t empty_slot_; - DISALLOW_COPY_AND_ASSIGN(ThreadDataPool); - }; - // Worker thread construction creates a name since there is none. - explicit ThreadData(size_t thread_number); + explicit ThreadData(int thread_number); // Message loop based construction should provide a name. explicit ThreadData(const std::string& suggested_name); @@ -577,7 +567,7 @@ class BASE_EXPORT ThreadData { // 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; + void OnThreadTerminationCleanup(); // Cleans up data structures, and returns statics to near pristine (mostly // uninitialized) state. If there is any chance that other threads are still @@ -593,16 +583,17 @@ class BASE_EXPORT ThreadData { // We use thread local store to identify which ThreadData to interact with. static base::ThreadLocalStorage::Slot tls_index_; + // List of ThreadData instances for use with worker threads. When a worker + // thread is done (terminated), we push it onto this llist. When a new worker + // thread is created, we first try to re-use a ThreadData instance from the + // list, and if none are available, construct a new one. + // This is only accessed while list_lock_ is held. + static ThreadData* first_retired_worker_; + // Link to the most recently created instance (starts a null terminated list). // The list is traversed by about:profiler when it needs to snapshot data. // This is only accessed while list_lock_ is held. 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. - // This is only accessed while list_lock_ is held. - static ThreadDataPool* unregistered_thread_data_pool_; // The next available thread number. This should only be accessed when the // list_lock_ is held. static int thread_number_counter_; @@ -631,6 +622,11 @@ class BASE_EXPORT ThreadData { // data). ThreadData* next_; + // Pointer to another ThreadData instance for a Worker-Thread that has been + // retired (its thread was terminated). This value is non-NULL only for a + // retired ThreadData associated with a Worker-Thread. + ThreadData* next_retired_worker_; + // The name of the thread that is being recorded. If this thread has no // message_loop, then this is a worker thread, with a sequence number postfix. std::string thread_name_; @@ -639,7 +635,7 @@ class BASE_EXPORT ThreadData { // stored in the unregistered_thread_data_pool_ when not in use. // Value is zero when it is not a worker thread. Value is a positive integer // corresponding to the created thread name if it is a worker thread. - size_t worker_thread_number_; + int worker_thread_number_; // 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. |