Chromium Code Reviews| Index: base/tracked_objects.h |
| =================================================================== |
| --- base/tracked_objects.h (revision 110706) |
| +++ base/tracked_objects.h (working copy) |
| @@ -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): 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 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): We should support (optionally) the recording of of parent-child |
|
ramant (doing other things)
2011/11/18 23:33:44
nit: of of -> of
jar (doing other things)
2011/11/18 23:57:41
Done.
|
| +// 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 @@ |
| // 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 @@ |
| 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 @@ |
| 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 @@ |
| // 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 @@ |
| // 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 @@ |
| // 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 @@ |
| // 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 @@ |
| // 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. |