blob: 8acddba6ae4dbce43125057b83c19fa3b42631d1 [file] [log] [blame]
[email protected]a502bbe72011-01-07 18:06:451// Copyright (c) 2011 The Chromium Authors. All rights reserved.
license.botbf09a502008-08-24 00:55:552// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commitd7cae122008-07-26 21:49:384
5#ifndef BASE_TRACKED_OBJECTS_H_
6#define BASE_TRACKED_OBJECTS_H_
[email protected]32b76ef2010-07-26 23:08:247#pragma once
initial.commitd7cae122008-07-26 21:49:388
initial.commitd7cae122008-07-26 21:49:389#include <map>
[email protected]84baeca2011-10-24 18:55:1610#include <stack>
initial.commitd7cae122008-07-26 21:49:3811#include <string>
12#include <vector>
13
[email protected]0bea7252011-08-05 15:34:0014#include "base/base_export.h"
[email protected]77169a62011-11-14 20:36:4615#include "base/lazy_instance.h"
[email protected]c62dd9d2011-09-21 18:05:4116#include "base/location.h"
[email protected]dbe5d2072011-11-08 17:09:2117#include "base/profiler/tracked_time.h"
[email protected]c62dd9d2011-09-21 18:05:4118#include "base/time.h"
[email protected]20305ec2011-01-21 04:55:5219#include "base/synchronization/lock.h"
[email protected]1357c322010-12-30 22:18:5620#include "base/threading/thread_local_storage.h"
[email protected]b2a9bbd2011-10-31 22:36:2121#include "base/tracking_info.h"
[email protected]84baeca2011-10-24 18:55:1622#include "base/values.h"
initial.commitd7cae122008-07-26 21:49:3823
[email protected]75b79202009-12-30 07:31:4524// TrackedObjects provides a database of stats about objects (generally Tasks)
25// that are tracked. Tracking means their birth, death, duration, birth thread,
26// death thread, and birth place are recorded. This data is carefully spread
27// across a series of objects so that the counts and times can be rapidly
28// updated without (usually) having to lock the data, and hence there is usually
29// very little contention caused by the tracking. The data can be viewed via
[email protected]dda97682011-11-14 05:24:0730// the about:profiler URL, with a variety of sorting and filtering choices.
[email protected]75b79202009-12-30 07:31:4531//
[email protected]ea319e42010-11-08 21:47:2432// These classes serve as the basis of a profiler of sorts for the Tasks system.
33// As a result, design decisions were made to maximize speed, by minimizing
34// recurring allocation/deallocation, lock contention and data copying. In the
35// "stable" state, which is reached relatively quickly, there is no separate
36// marginal allocation cost associated with construction or destruction of
37// tracked objects, no locks are generally employed, and probably the largest
38// computational cost is associated with obtaining start and stop times for
[email protected]84b57952011-10-15 23:52:4539// instances as they are created and destroyed.
[email protected]75b79202009-12-30 07:31:4540//
41// The following describes the lifecycle of tracking an instance.
42//
43// First off, when the instance is created, the FROM_HERE macro is expanded
44// to specify the birth place (file, line, function) where the instance was
45// created. That data is used to create a transient Location instance
46// encapsulating the above triple of information. The strings (like __FILE__)
47// are passed around by reference, with the assumption that they are static, and
48// will never go away. This ensures that the strings can be dealt with as atoms
49// with great efficiency (i.e., copying of strings is never needed, and
50// comparisons for equality can be based on pointer comparisons).
51//
52// Next, a Births instance is created for use ONLY on the thread where this
53// instance was created. That Births instance records (in a base class
54// BirthOnThread) references to the static data provided in a Location instance,
55// as well as a pointer specifying the thread on which the birth takes place.
56// Hence there is at most one Births instance for each Location on each thread.
57// The derived Births class contains slots for recording statistics about all
58// instances born at the same location. Statistics currently include only the
59// count of instances constructed.
[email protected]84b57952011-10-15 23:52:4560//
[email protected]75b79202009-12-30 07:31:4561// Since the base class BirthOnThread contains only constant data, it can be
62// freely accessed by any thread at any time (i.e., only the statistic needs to
[email protected]84b57952011-10-15 23:52:4563// be handled carefully, and stats are updated exclusively on the birth thread).
[email protected]75b79202009-12-30 07:31:4564//
[email protected]c62dd9d2011-09-21 18:05:4165// For Tasks, having now either constructed or found the Births instance
66// described above, a pointer to the Births instance is then recorded into the
67// PendingTask structure in MessageLoop. This fact alone is very useful in
[email protected]75b79202009-12-30 07:31:4568// debugging, when there is a question of where an instance came from. In
[email protected]c62dd9d2011-09-21 18:05:4169// addition, the birth time is also recorded and used to later evaluate the
70// lifetime duration of the whole Task. As a result of the above embedding, we
71// can find out a Task's location of birth, and thread of birth, without using
72// any locks, as all that data is constant across the life of the process.
73//
[email protected]84b57952011-10-15 23:52:4574// The above work *could* also be done for any other object as well by calling
[email protected]b2a9bbd2011-10-31 22:36:2175// TallyABirthIfActive() and TallyRunOnNamedThreadIfTracking() as appropriate.
[email protected]75b79202009-12-30 07:31:4576//
77// The amount of memory used in the above data structures depends on how many
78// threads there are, and how many Locations of construction there are.
79// Fortunately, we don't use memory that is the product of those two counts, but
80// rather we only need one Births instance for each thread that constructs an
[email protected]c62dd9d2011-09-21 18:05:4181// instance at a Location. In many cases, instances are only created on one
82// thread, so the memory utilization is actually fairly restrained.
[email protected]75b79202009-12-30 07:31:4583//
84// Lastly, when an instance is deleted, the final tallies of statistics are
[email protected]c7dbf302011-11-08 07:57:0585// carefully accumulated. That tallying writes into slots (members) in a
[email protected]75b79202009-12-30 07:31:4586// collection of DeathData instances. For each birth place Location that is
87// destroyed on a thread, there is a DeathData instance to record the additional
[email protected]84b57952011-10-15 23:52:4588// death count, as well as accumulate the run-time and queue-time durations for
89// the instance as it is destroyed (dies). By maintaining a single place to
90// aggregate this running sum *only* for the given thread, we avoid the need to
91// lock such DeathData instances. (i.e., these accumulated stats in a DeathData
92// instance are exclusively updated by the singular owning thread).
[email protected]75b79202009-12-30 07:31:4593//
94// With the above lifecycle description complete, the major remaining detail is
95// explaining how each thread maintains a list of DeathData instances, and of
96// Births instances, and is able to avoid additional (redundant/unnecessary)
97// allocations.
98//
99// Each thread maintains a list of data items specific to that thread in a
100// ThreadData instance (for that specific thread only). The two critical items
101// are lists of DeathData and Births instances. These lists are maintained in
102// STL maps, which are indexed by Location. As noted earlier, we can compare
103// locations very efficiently as we consider the underlying data (file,
104// function, line) to be atoms, and hence pointer comparison is used rather than
105// (slow) string comparisons.
106//
107// To provide a mechanism for iterating over all "known threads," which means
108// threads that have recorded a birth or a death, we create a singly linked list
109// of ThreadData instances. Each such instance maintains a pointer to the next
[email protected]84baeca2011-10-24 18:55:16110// one. A static member of ThreadData provides a pointer to the first item on
111// this global list, and access via that all_thread_data_list_head_ item
112// requires the use of the list_lock_.
[email protected]75b79202009-12-30 07:31:45113// When new ThreadData instances is added to the global list, it is pre-pended,
114// which ensures that any prior acquisition of the list is valid (i.e., the
115// holder can iterate over it without fear of it changing, or the necessity of
116// using an additional lock. Iterations are actually pretty rare (used
117// primarilly for cleanup, or snapshotting data for display), so this lock has
118// very little global performance impact.
119//
120// The above description tries to define the high performance (run time)
121// portions of these classes. After gathering statistics, calls instigated
[email protected]dda97682011-11-14 05:24:07122// by visiting about:profiler will assemble and aggregate data for display. The
[email protected]75b79202009-12-30 07:31:45123// following data structures are used for producing such displays. They are
124// not performance critical, and their only major constraint is that they should
125// be able to run concurrently with ongoing augmentation of the birth and death
126// data.
127//
[email protected]c7dbf302011-11-08 07:57:05128// For a given birth location, information about births is spread across data
[email protected]75b79202009-12-30 07:31:45129// structures that are asynchronously changing on various threads. For display
130// purposes, we need to construct Snapshot instances for each combination of
131// birth thread, death thread, and location, along with the count of such
132// lifetimes. We gather such data into a Snapshot instances, so that such
133// instances can be sorted and aggregated (and remain frozen during our
134// processing). Snapshot instances use pointers to constant portions of the
135// birth and death datastructures, but have local (frozen) copies of the actual
136// statistics (birth count, durations, etc. etc.).
137//
[email protected]84b57952011-10-15 23:52:45138// A DataCollector is a container object that holds a set of Snapshots. The
139// statistics in a snapshot are gathered asynhcronously relative to their
[email protected]26cdeb962011-11-20 04:17:07140// ongoing updates. It is possible, though highly unlikely, that stats could be
141// incorrectly recorded by this process (all data is held in 32 bit ints, but we
142// are not atomically collecting all data, so we could have count that does not,
143// for example, match with the number of durations we accumulated). The
[email protected]c7dbf302011-11-08 07:57:05144// advantage to having fast (non-atomic) updates of the data outweighs the
145// minimal risk of a singular corrupt statistic snapshot (only the snapshot
146// could be corrupt, not the underlying and ongoing statistic). In constrast,
147// pointer data that is accessed during snapshotting is completely invariant,
148// and hence is perfectly acquired (i.e., no potential corruption, and no risk
149// of a bad memory reference).
[email protected]75b79202009-12-30 07:31:45150//
[email protected]c7dbf302011-11-08 07:57:05151// After an array of Snapshots instances are collected into a DataCollector,
152// they need to be prepared for displaying our output. We currently implement a
[email protected]26cdeb962011-11-20 04:17:07153// serialization into a Value hierarchy, which is automatically translated to
154// JSON when supplied to rendering Java Scirpt.
[email protected]75b79202009-12-30 07:31:45155//
[email protected]26cdeb962011-11-20 04:17:07156// TODO(jar): We can implement a Snapshot system that *tries* to grab the
157// snapshots on the source threads *when* they have MessageLoops available
158// (worker threads don't have message loops generally, and hence gathering from
159// them will continue to be asynchronous). We had an implementation of this in
160// the past, but the difficulty is dealing with message loops being terminated.
161// We can *try* to spam the available threads via some message loop proxy to
162// achieve this feat, and it *might* be valuable when we are colecting data for
163// upload via UMA (where correctness of data may be more significant than for a
164// single screen of about:profiler).
165//
166// TODO(jar): We need to save a single sample in each DeathData instance of the
167// times recorded. This sample should be selected in a uniformly random way.
168//
169// TODO(jar): We should support (optionally) the recording of parent-child
170// relationships for tasks. This should be done by detecting what tasks are
171// Born during the running of a parent task. The resulting data can be used by
172// a smarter profiler to aggregate the cost of a series of child tasks into
173// the ancestor task. It can also be used to illuminate what child or parent is
174// related to each task.
175//
176// TODO(jar): We need to store DataCollections, and provide facilities for
177// taking the difference between two gathered DataCollections. For now, we're
178// just adding a hack that Reset()s to zero all counts and stats. This is also
[email protected]c7dbf302011-11-08 07:57:05179// done in a slighly thread-unsafe fashion, as the resetting is done
[email protected]eab79c382011-11-06 19:14:48180// asynchronously relative to ongoing updates (but all data is 32 bit in size).
181// For basic profiling, this will work "most of the time," and should be
[email protected]75b79202009-12-30 07:31:45182// sufficient... but storing away DataCollections is the "right way" to do this.
[email protected]eab79c382011-11-06 19:14:48183// We'll accomplish this via JavaScript storage of snapshots, and then we'll
[email protected]26cdeb962011-11-20 04:17:07184// remove the Reset() methods. We may also need a short-term-max value in
185// DeathData that is reset (as synchronously as possible) during each snapshot.
186// This will facilitate displaying a max value for each snapshot period.
initial.commitd7cae122008-07-26 21:49:38187
[email protected]c62dd9d2011-09-21 18:05:41188class MessageLoop;
[email protected]75b79202009-12-30 07:31:45189
initial.commitd7cae122008-07-26 21:49:38190namespace tracked_objects {
191
192//------------------------------------------------------------------------------
193// For a specific thread, and a specific birth place, the collection of all
194// death info (with tallies for each death thread, to prevent access conflicts).
195class ThreadData;
[email protected]0bea7252011-08-05 15:34:00196class BASE_EXPORT BirthOnThread {
initial.commitd7cae122008-07-26 21:49:38197 public:
[email protected]84baeca2011-10-24 18:55:16198 BirthOnThread(const Location& location, const ThreadData& current);
initial.commitd7cae122008-07-26 21:49:38199
200 const Location location() const { return location_; }
201 const ThreadData* birth_thread() const { return birth_thread_; }
202
203 private:
[email protected]84b57952011-10-15 23:52:45204 // File/lineno of birth. This defines the essence of the task, as the context
initial.commitd7cae122008-07-26 21:49:38205 // of the birth (construction) often tell what the item is for. This field
206 // is const, and hence safe to access from any thread.
207 const Location location_;
208
209 // The thread that records births into this object. Only this thread is
[email protected]84baeca2011-10-24 18:55:16210 // allowed to update birth_count_ (which changes over time).
211 const ThreadData* const birth_thread_;
initial.commitd7cae122008-07-26 21:49:38212
[email protected]022614ef92008-12-30 20:50:01213 DISALLOW_COPY_AND_ASSIGN(BirthOnThread);
initial.commitd7cae122008-07-26 21:49:38214};
215
216//------------------------------------------------------------------------------
217// A class for accumulating counts of births (without bothering with a map<>).
218
[email protected]0bea7252011-08-05 15:34:00219class BASE_EXPORT Births: public BirthOnThread {
initial.commitd7cae122008-07-26 21:49:38220 public:
[email protected]84baeca2011-10-24 18:55:16221 Births(const Location& location, const ThreadData& current);
initial.commitd7cae122008-07-26 21:49:38222
223 int birth_count() const { return birth_count_; }
224
225 // When we have a birth we update the count for this BirhPLace.
226 void RecordBirth() { ++birth_count_; }
227
228 // When a birthplace is changed (updated), we need to decrement the counter
229 // for the old instance.
230 void ForgetBirth() { --birth_count_; } // We corrected a birth place.
231
[email protected]75b79202009-12-30 07:31:45232 // Hack to quickly reset all counts to zero.
233 void Clear() { birth_count_ = 0; }
234
initial.commitd7cae122008-07-26 21:49:38235 private:
236 // The number of births on this thread for our location_.
237 int birth_count_;
238
[email protected]022614ef92008-12-30 20:50:01239 DISALLOW_COPY_AND_ASSIGN(Births);
initial.commitd7cae122008-07-26 21:49:38240};
241
242//------------------------------------------------------------------------------
[email protected]b2a9bbd2011-10-31 22:36:21243// Basic info summarizing multiple destructions of a tracked object with a
244// single birthplace (fixed Location). Used both on specific threads, and also
initial.commitd7cae122008-07-26 21:49:38245// in snapshots when integrating assembled data.
246
[email protected]0bea7252011-08-05 15:34:00247class BASE_EXPORT DeathData {
initial.commitd7cae122008-07-26 21:49:38248 public:
249 // Default initializer.
[email protected]84b57952011-10-15 23:52:45250 DeathData() : count_(0) {}
initial.commitd7cae122008-07-26 21:49:38251
252 // When deaths have not yet taken place, and we gather data from all the
253 // threads, we create DeathData stats that tally the number of births without
254 // a corrosponding death.
[email protected]c25db182011-11-11 22:40:27255 explicit DeathData(int count)
256 : count_(count) {}
initial.commitd7cae122008-07-26 21:49:38257
[email protected]84b57952011-10-15 23:52:45258 // Update stats for a task destruction (death) that had a Run() time of
259 // |duration|, and has had a queueing delay of |queue_duration|.
[email protected]c25db182011-11-11 22:40:27260 void RecordDeath(DurationInt queue_duration,
261 DurationInt run_duration);
initial.commitd7cae122008-07-26 21:49:38262
263 // Metrics accessors.
264 int count() const { return count_; }
[email protected]c25db182011-11-11 22:40:27265 DurationInt run_duration() const { return run_time_.duration(); }
266 DurationInt AverageMsRunDuration() const;
267 DurationInt run_duration_max() const { return run_time_.max(); }
268 DurationInt queue_duration() const { return queue_time_.duration(); }
269 DurationInt AverageMsQueueDuration() const;
270 DurationInt queue_duration_max() const { return queue_time_.max(); }
initial.commitd7cae122008-07-26 21:49:38271
[email protected]84b57952011-10-15 23:52:45272 // Accumulate metrics from other into this. This method is never used on
273 // realtime statistics, and only used in snapshots and aggregatinos.
initial.commitd7cae122008-07-26 21:49:38274 void AddDeathData(const DeathData& other);
275
[email protected]b2a9bbd2011-10-31 22:36:21276 // Construct a DictionaryValue instance containing all our stats. The caller
[email protected]84baeca2011-10-24 18:55:16277 // assumes ownership of the returned instance.
278 base::DictionaryValue* ToValue() const;
initial.commitd7cae122008-07-26 21:49:38279
[email protected]84b57952011-10-15 23:52:45280 // Reset all tallies to zero. This is used as a hack on realtime data.
initial.commitd7cae122008-07-26 21:49:38281 void Clear();
282
283 private:
[email protected]63f5b0e2011-11-04 00:23:27284 // DeathData::Data is a helper class, useful when different metrics need to be
285 // aggregated, such as queueing times, or run times.
286 class Data {
287 public:
[email protected]c25db182011-11-11 22:40:27288 Data() : duration_(0), max_(0) {}
[email protected]63f5b0e2011-11-04 00:23:27289 ~Data() {}
290
[email protected]c25db182011-11-11 22:40:27291 DurationInt duration() const { return duration_; }
292 DurationInt max() const { return max_; }
[email protected]63f5b0e2011-11-04 00:23:27293
[email protected]63f5b0e2011-11-04 00:23:27294 // Agggegate data into our state.
295 void AddData(const Data& other);
[email protected]c25db182011-11-11 22:40:27296 void AddDuration(DurationInt duration);
[email protected]63f5b0e2011-11-04 00:23:27297
298 // Central helper function for calculating averages (correctly, in only one
299 // place).
[email protected]c25db182011-11-11 22:40:27300 DurationInt AverageMsDuration(int count) const;
[email protected]63f5b0e2011-11-04 00:23:27301
302 // Resets all members to zero.
303 void Clear();
304
305 private:
[email protected]c25db182011-11-11 22:40:27306 DurationInt duration_; // Sum of all durations seen.
307 DurationInt max_; // Largest singular duration seen.
[email protected]63f5b0e2011-11-04 00:23:27308 };
309
310
311 int count_; // Number of deaths seen.
312 Data run_time_; // Data about run time durations.
313 Data queue_time_; // Data about queueing times durations.
initial.commitd7cae122008-07-26 21:49:38314};
315
316//------------------------------------------------------------------------------
317// A temporary collection of data that can be sorted and summarized. It is
318// gathered (carefully) from many threads. Instances are held in arrays and
319// processed, filtered, and rendered.
320// The source of this data was collected on many threads, and is asynchronously
321// changing. The data in this instance is not asynchronously changing.
322
[email protected]0bea7252011-08-05 15:34:00323class BASE_EXPORT Snapshot {
initial.commitd7cae122008-07-26 21:49:38324 public:
325 // When snapshotting a full life cycle set (birth-to-death), use this:
326 Snapshot(const BirthOnThread& birth_on_thread, const ThreadData& death_thread,
327 const DeathData& death_data);
328
329 // When snapshotting a birth, with no death yet, use this:
330 Snapshot(const BirthOnThread& birth_on_thread, int count);
331
initial.commitd7cae122008-07-26 21:49:38332 const ThreadData* birth_thread() const { return birth_->birth_thread(); }
333 const Location location() const { return birth_->location(); }
334 const BirthOnThread& birth() const { return *birth_; }
335 const ThreadData* death_thread() const {return death_thread_; }
336 const DeathData& death_data() const { return death_data_; }
337 const std::string DeathThreadName() const;
338
339 int count() const { return death_data_.count(); }
[email protected]c25db182011-11-11 22:40:27340 DurationInt run_duration() const { return death_data_.run_duration(); }
341 DurationInt AverageMsRunDuration() const {
[email protected]84b57952011-10-15 23:52:45342 return death_data_.AverageMsRunDuration();
343 }
[email protected]c25db182011-11-11 22:40:27344 DurationInt run_duration_max() const {
[email protected]63f5b0e2011-11-04 00:23:27345 return death_data_.run_duration_max();
346 }
[email protected]c25db182011-11-11 22:40:27347 DurationInt queue_duration() const { return death_data_.queue_duration(); }
348 DurationInt AverageMsQueueDuration() const {
[email protected]84b57952011-10-15 23:52:45349 return death_data_.AverageMsQueueDuration();
350 }
[email protected]c25db182011-11-11 22:40:27351 DurationInt queue_duration_max() const {
[email protected]63f5b0e2011-11-04 00:23:27352 return death_data_.queue_duration_max();
353 }
initial.commitd7cae122008-07-26 21:49:38354
[email protected]84baeca2011-10-24 18:55:16355 // Construct a DictionaryValue instance containing all our data recursively.
356 // The caller assumes ownership of the memory in the returned instance.
357 base::DictionaryValue* ToValue() const;
initial.commitd7cae122008-07-26 21:49:38358
initial.commitd7cae122008-07-26 21:49:38359 private:
360 const BirthOnThread* birth_; // Includes Location and birth_thread.
361 const ThreadData* death_thread_;
362 DeathData death_data_;
363};
[email protected]84b57952011-10-15 23:52:45364
initial.commitd7cae122008-07-26 21:49:38365//------------------------------------------------------------------------------
366// DataCollector is a container class for Snapshot and BirthOnThread count
[email protected]84b57952011-10-15 23:52:45367// items.
initial.commitd7cae122008-07-26 21:49:38368
[email protected]0bea7252011-08-05 15:34:00369class BASE_EXPORT DataCollector {
initial.commitd7cae122008-07-26 21:49:38370 public:
[email protected]764be58b2008-08-08 20:03:42371 typedef std::vector<Snapshot> Collection;
initial.commitd7cae122008-07-26 21:49:38372
373 // Construct with a list of how many threads should contribute. This helps us
374 // determine (in the async case) when we are done with all contributions.
375 DataCollector();
[email protected]d4799a32010-09-28 22:54:58376 ~DataCollector();
initial.commitd7cae122008-07-26 21:49:38377
[email protected]b2a9bbd2011-10-31 22:36:21378 // Adds all stats from the indicated thread into our arrays. This function
379 // uses locks at the lowest level (when accessing the underlying maps which
380 // could change when not locked), and can be called from any threads.
initial.commitd7cae122008-07-26 21:49:38381 void Append(const ThreadData& thread_data);
382
[email protected]75b79202009-12-30 07:31:45383 // After the accumulation phase, the following accessor is used to process the
[email protected]b2a9bbd2011-10-31 22:36:21384 // data (i.e., sort it, filter it, etc.).
initial.commitd7cae122008-07-26 21:49:38385 Collection* collection();
386
[email protected]b2a9bbd2011-10-31 22:36:21387 // Adds entries for all the remaining living objects (objects that have
388 // tallied a birth, but have not yet tallied a matching death, and hence must
389 // be either running, queued up, or being held in limbo for future posting).
390 // This should be called after all known ThreadData instances have been
391 // processed using Append().
initial.commitd7cae122008-07-26 21:49:38392 void AddListOfLivingObjects();
393
[email protected]b2a9bbd2011-10-31 22:36:21394 // Generates a ListValue representation of the vector of snapshots. The caller
[email protected]84baeca2011-10-24 18:55:16395 // assumes ownership of the memory in the returned instance.
396 base::ListValue* ToValue() const;
397
initial.commitd7cae122008-07-26 21:49:38398 private:
[email protected]a502bbe72011-01-07 18:06:45399 typedef std::map<const BirthOnThread*, int> BirthCount;
400
initial.commitd7cae122008-07-26 21:49:38401 // The array that we collect data into.
402 Collection collection_;
403
404 // The total number of births recorded at each location for which we have not
[email protected]b2a9bbd2011-10-31 22:36:21405 // seen a death count. This map changes as we do Append() calls, and is later
406 // used by AddListOfLivingObjects() to gather up unaccounted for births.
initial.commitd7cae122008-07-26 21:49:38407 BirthCount global_birth_count_;
408
[email protected]022614ef92008-12-30 20:50:01409 DISALLOW_COPY_AND_ASSIGN(DataCollector);
initial.commitd7cae122008-07-26 21:49:38410};
411
412//------------------------------------------------------------------------------
initial.commitd7cae122008-07-26 21:49:38413// For each thread, we have a ThreadData that stores all tracking info generated
414// on this thread. This prevents the need for locking as data accumulates.
[email protected]b2a9bbd2011-10-31 22:36:21415// We use ThreadLocalStorage to quickly identfy the current ThreadData context.
416// We also have a linked list of ThreadData instances, and that list is used to
417// harvest data from all existing instances.
initial.commitd7cae122008-07-26 21:49:38418
[email protected]0bea7252011-08-05 15:34:00419class BASE_EXPORT ThreadData {
initial.commitd7cae122008-07-26 21:49:38420 public:
[email protected]b2a9bbd2011-10-31 22:36:21421 // Current allowable states of the tracking system. The states can vary
422 // between ACTIVE and DEACTIVATED, but can never go back to UNINITIALIZED.
423 enum Status {
424 UNINITIALIZED,
425 ACTIVE,
426 DEACTIVATED,
427 };
428
initial.commitd7cae122008-07-26 21:49:38429 typedef std::map<Location, Births*> BirthMap;
430 typedef std::map<const Births*, DeathData> DeathMap;
431
[email protected]84b57952011-10-15 23:52:45432 // Initialize the current thread context with a new instance of ThreadData.
[email protected]b2a9bbd2011-10-31 22:36:21433 // This is used by all threads that have names, and should be explicitly
434 // set *before* any births on the threads have taken place. It is generally
435 // only used by the message loop, which has a well defined thread name.
[email protected]84b57952011-10-15 23:52:45436 static void InitializeThreadContext(const std::string& suggested_name);
initial.commitd7cae122008-07-26 21:49:38437
438 // Using Thread Local Store, find the current instance for collecting data.
439 // If an instance does not exist, construct one (and remember it for use on
440 // this thread.
[email protected]84baeca2011-10-24 18:55:16441 // This may return NULL if the system is disabled for any reason.
[email protected]84b57952011-10-15 23:52:45442 static ThreadData* Get();
initial.commitd7cae122008-07-26 21:49:38443
[email protected]b2a9bbd2011-10-31 22:36:21444 // Constructs a DictionaryValue instance containing all recursive results in
445 // our process. The caller assumes ownership of the memory in the returned
446 // instance.
447 static base::DictionaryValue* ToValue();
448
449 // Finds (or creates) a place to count births from the given location in this
[email protected]84baeca2011-10-24 18:55:16450 // thread, and increment that tally.
[email protected]180c85e2011-07-26 18:25:16451 // TallyABirthIfActive will returns NULL if the birth cannot be tallied.
452 static Births* TallyABirthIfActive(const Location& location);
[email protected]84b57952011-10-15 23:52:45453
[email protected]b2a9bbd2011-10-31 22:36:21454 // Records the end of a timed run of an object. The |completed_task| contains
455 // a pointer to a Births, the time_posted, and a delayed_start_time if any.
456 // The |start_of_run| indicates when we started to perform the run of the
457 // task. The delayed_start_time is non-null for tasks that were posted as
458 // delayed tasks, and it indicates when the task should have run (i.e., when
459 // it should have posted out of the timer queue, and into the work queue.
460 // The |end_of_run| was just obtained by a call to Now() (just after the task
461 // finished). It is provided as an argument to help with testing.
462 static void TallyRunOnNamedThreadIfTracking(
463 const base::TrackingInfo& completed_task,
464 const TrackedTime& start_of_run,
465 const TrackedTime& end_of_run);
466
[email protected]6b26b96012011-10-28 21:41:50467 // Record the end of a timed run of an object. The |birth| is the record for
[email protected]b2a9bbd2011-10-31 22:36:21468 // the instance, the |time_posted| records that instant, which is presumed to
469 // be when the task was posted into a queue to run on a worker thread.
470 // The |start_of_run| is when the worker thread started to perform the run of
471 // the task.
[email protected]84baeca2011-10-24 18:55:16472 // The |end_of_run| was just obtained by a call to Now() (just after the task
473 // finished).
[email protected]b2a9bbd2011-10-31 22:36:21474 static void TallyRunOnWorkerThreadIfTracking(
475 const Births* birth,
476 const TrackedTime& time_posted,
477 const TrackedTime& start_of_run,
478 const TrackedTime& end_of_run);
initial.commitd7cae122008-07-26 21:49:38479
[email protected]dbe5d2072011-11-08 17:09:21480 // Record the end of execution in region, generally corresponding to a scope
481 // being exited.
482 static void TallyRunInAScopedRegionIfTracking(
483 const Births* birth,
484 const TrackedTime& start_of_run,
485 const TrackedTime& end_of_run);
486
[email protected]84b57952011-10-15 23:52:45487 const std::string thread_name() const { return thread_name_; }
initial.commitd7cae122008-07-26 21:49:38488
[email protected]84baeca2011-10-24 18:55:16489 // ---------------------
[email protected]dbe5d2072011-11-08 17:09:21490 // TODO(jar):
[email protected]84baeca2011-10-24 18:55:16491 // The following functions should all be private, and are only public because
492 // the collection is done externally. We need to relocate that code from the
493 // collection class into this class, and then all these methods can be made
494 // private.
495 // (Thread safe) Get start of list of all ThreadData instances.
496 static ThreadData* first();
497 // Iterate through the null terminated list of ThreadData instances.
498 ThreadData* next() const { return next_; }
initial.commitd7cae122008-07-26 21:49:38499 // Using our lock, make a copy of the specified maps. These calls may arrive
[email protected]75b79202009-12-30 07:31:45500 // from non-local threads, and are used to quickly scan data from all threads
[email protected]26cdeb962011-11-20 04:17:07501 // in order to build JSON for about:profiler.
initial.commitd7cae122008-07-26 21:49:38502 void SnapshotBirthMap(BirthMap *output) const;
503 void SnapshotDeathMap(DeathMap *output) const;
[email protected]84baeca2011-10-24 18:55:16504 // -------- end of should be private methods.
initial.commitd7cae122008-07-26 21:49:38505
[email protected]75b79202009-12-30 07:31:45506 // Hack: asynchronously clear all birth counts and death tallies data values
507 // in all ThreadData instances. The numerical (zeroing) part is done without
508 // use of a locks or atomics exchanges, and may (for int64 values) produce
509 // bogus counts VERY rarely.
510 static void ResetAllThreadData();
511
[email protected]b2a9bbd2011-10-31 22:36:21512 // Initializes all statics if needed (this initialization call should be made
513 // while we are single threaded). Returns false if unable to initialize.
514 static bool Initialize();
515
516 // Sets internal status_ to either become ACTIVE, or DEACTIVATED,
initial.commitd7cae122008-07-26 21:49:38517 // based on argument being true or false respectively.
[email protected]b2a9bbd2011-10-31 22:36:21518 // If tracking is not compiled in, this function will return false.
519 static bool InitializeAndSetTrackingStatus(bool status);
520 static bool tracking_status();
initial.commitd7cae122008-07-26 21:49:38521
[email protected]dda97682011-11-14 05:24:07522 // Special versions of Now() for getting times at start and end of a tracked
523 // run. They are super fast when tracking is disabled, and have some internal
524 // side effects when we are tracking, so that we can deduce the amount of time
525 // accumulated outside of execution of tracked runs.
526 static TrackedTime NowForStartOfRun();
527 static TrackedTime NowForEndOfRun();
528
[email protected]84b57952011-10-15 23:52:45529 // Provide a time function that does nothing (runs fast) when we don't have
530 // the profiler enabled. It will generally be optimized away when it is
531 // ifdef'ed to be small enough (allowing the profiler to be "compiled out" of
532 // the code).
[email protected]b2a9bbd2011-10-31 22:36:21533 static TrackedTime Now();
initial.commitd7cae122008-07-26 21:49:38534
initial.commitd7cae122008-07-26 21:49:38535 private:
[email protected]eab79c382011-11-06 19:14:48536 // Allow only tests to call ShutdownSingleThreadedCleanup. We NEVER call it
537 // in production code.
538 friend class TrackedObjectsTest;
539
[email protected]84baeca2011-10-24 18:55:16540 // Worker thread construction creates a name since there is none.
[email protected]26cdeb962011-11-20 04:17:07541 explicit ThreadData(int thread_number);
[email protected]445029fb2011-11-18 17:03:33542
[email protected]84baeca2011-10-24 18:55:16543 // Message loop based construction should provide a name.
544 explicit ThreadData(const std::string& suggested_name);
545
546 ~ThreadData();
547
548 // Push this instance to the head of all_thread_data_list_head_, linking it to
549 // the previous head. This is performed after each construction, and leaves
550 // the instance permanently on that list.
551 void PushToHeadOfList();
552
553 // In this thread's data, record a new birth.
554 Births* TallyABirth(const Location& location);
555
556 // Find a place to record a death on this thread.
557 void TallyADeath(const Births& birth,
[email protected]c25db182011-11-11 22:40:27558 DurationInt queue_duration,
559 DurationInt duration);
[email protected]84baeca2011-10-24 18:55:16560
561 // Using our lock to protect the iteration, Clear all birth and death data.
562 void Reset();
563
564 // This method is called by the TLS system when a thread terminates.
565 // The argument may be NULL if this thread has never tracked a birth or death.
566 static void OnThreadTermination(void* thread_data);
567
568 // This method should be called when a worker thread terminates, so that we
569 // can save all the thread data into a cache of reusable ThreadData instances.
[email protected]26cdeb962011-11-20 04:17:07570 void OnThreadTerminationCleanup();
[email protected]84baeca2011-10-24 18:55:16571
[email protected]eab79c382011-11-06 19:14:48572 // Cleans up data structures, and returns statics to near pristine (mostly
573 // uninitialized) state. If there is any chance that other threads are still
574 // using the data structures, then the |leak| argument should be passed in as
575 // true, and the data structures (birth maps, death maps, ThreadData
576 // insntances, etc.) will be leaked and not deleted. If you have joined all
577 // threads since the time that InitializeAndSetTrackingStatus() was called,
578 // then you can pass in a |leak| value of false, and this function will
579 // delete recursively all data structures, starting with the list of
580 // ThreadData instances.
581 static void ShutdownSingleThreadedCleanup(bool leak);
582
initial.commitd7cae122008-07-26 21:49:38583 // We use thread local store to identify which ThreadData to interact with.
[email protected]1357c322010-12-30 22:18:56584 static base::ThreadLocalStorage::Slot tls_index_;
initial.commitd7cae122008-07-26 21:49:38585
[email protected]26cdeb962011-11-20 04:17:07586 // List of ThreadData instances for use with worker threads. When a worker
587 // thread is done (terminated), we push it onto this llist. When a new worker
588 // thread is created, we first try to re-use a ThreadData instance from the
589 // list, and if none are available, construct a new one.
590 // This is only accessed while list_lock_ is held.
591 static ThreadData* first_retired_worker_;
592
initial.commitd7cae122008-07-26 21:49:38593 // Link to the most recently created instance (starts a null terminated list).
[email protected]dda97682011-11-14 05:24:07594 // The list is traversed by about:profiler when it needs to snapshot data.
[email protected]b2a9bbd2011-10-31 22:36:21595 // This is only accessed while list_lock_ is held.
[email protected]84baeca2011-10-24 18:55:16596 static ThreadData* all_thread_data_list_head_;
[email protected]b2a9bbd2011-10-31 22:36:21597 // The next available thread number. This should only be accessed when the
598 // list_lock_ is held.
599 static int thread_number_counter_;
600 // Incarnation sequence number, indicating how many times (during unittests)
601 // we've either transitioned out of UNINITIALIZED, or into that state. This
602 // value is only accessed while the list_lock_ is held.
603 static int incarnation_counter_;
[email protected]84baeca2011-10-24 18:55:16604 // Protection for access to all_thread_data_list_head_, and to
[email protected]b2a9bbd2011-10-31 22:36:21605 // unregistered_thread_data_pool_. This lock is leaked at shutdown.
[email protected]77169a62011-11-14 20:36:46606 // The lock is very infrequently used, so we can afford to just make a lazy
607 // instance and be safe.
608 static base::LazyInstance<base::Lock,
609 base::LeakyLazyInstanceTraits<base::Lock> > list_lock_;
[email protected]b2a9bbd2011-10-31 22:36:21610
611 // Record of what the incarnation_counter_ was when this instance was created.
612 // If the incarnation_counter_ has changed, then we avoid pushing into the
613 // pool (this is only critical in tests which go through multiple
614 // incarations).
615 int incarnation_count_for_pool_;
initial.commitd7cae122008-07-26 21:49:38616
[email protected]84b57952011-10-15 23:52:45617 // We set status_ to SHUTDOWN when we shut down the tracking service.
initial.commitd7cae122008-07-26 21:49:38618 static Status status_;
619
620 // Link to next instance (null terminated list). Used to globally track all
621 // registered instances (corresponds to all registered threads where we keep
622 // data).
623 ThreadData* next_;
624
[email protected]26cdeb962011-11-20 04:17:07625 // Pointer to another ThreadData instance for a Worker-Thread that has been
626 // retired (its thread was terminated). This value is non-NULL only for a
627 // retired ThreadData associated with a Worker-Thread.
628 ThreadData* next_retired_worker_;
629
[email protected]84b57952011-10-15 23:52:45630 // The name of the thread that is being recorded. If this thread has no
631 // message_loop, then this is a worker thread, with a sequence number postfix.
632 std::string thread_name_;
initial.commitd7cae122008-07-26 21:49:38633
[email protected]84baeca2011-10-24 18:55:16634 // Indicate if this is a worker thread, and the ThreadData contexts should be
635 // stored in the unregistered_thread_data_pool_ when not in use.
[email protected]445029fb2011-11-18 17:03:33636 // Value is zero when it is not a worker thread. Value is a positive integer
637 // corresponding to the created thread name if it is a worker thread.
[email protected]26cdeb962011-11-20 04:17:07638 int worker_thread_number_;
[email protected]84baeca2011-10-24 18:55:16639
initial.commitd7cae122008-07-26 21:49:38640 // A map used on each thread to keep track of Births on this thread.
641 // This map should only be accessed on the thread it was constructed on.
642 // When a snapshot is needed, this structure can be locked in place for the
643 // duration of the snapshotting activity.
644 BirthMap birth_map_;
645
646 // Similar to birth_map_, this records informations about death of tracked
647 // instances (i.e., when a tracked instance was destroyed on this thread).
[email protected]75b79202009-12-30 07:31:45648 // It is locked before changing, and hence other threads may access it by
649 // locking before reading it.
initial.commitd7cae122008-07-26 21:49:38650 DeathMap death_map_;
651
[email protected]75b79202009-12-30 07:31:45652 // Lock to protect *some* access to BirthMap and DeathMap. The maps are
653 // regularly read and written on this thread, but may only be read from other
654 // threads. To support this, we acquire this lock if we are writing from this
655 // thread, or reading from another thread. For reading from this thread we
656 // don't need a lock, as there is no potential for a conflict since the
657 // writing is only done from this thread.
[email protected]20305ec2011-01-21 04:55:52658 mutable base::Lock lock_;
initial.commitd7cae122008-07-26 21:49:38659
[email protected]022614ef92008-12-30 20:50:01660 DISALLOW_COPY_AND_ASSIGN(ThreadData);
initial.commitd7cae122008-07-26 21:49:38661};
662
[email protected]022614ef92008-12-30 20:50:01663//------------------------------------------------------------------------------
664// Provide simple way to to start global tracking, and to tear down tracking
[email protected]84baeca2011-10-24 18:55:16665// when done. The design has evolved to *not* do any teardown (and just leak
666// all allocated data structures). As a result, we don't have any code in this
667// destructor, and perhaps this whole class should go away.
[email protected]862aa2f02009-12-31 07:26:16668
[email protected]0bea7252011-08-05 15:34:00669class BASE_EXPORT AutoTracking {
[email protected]022614ef92008-12-30 20:50:01670 public:
[email protected]862aa2f02009-12-31 07:26:16671 AutoTracking() {
[email protected]b2a9bbd2011-10-31 22:36:21672 ThreadData::Initialize();
[email protected]862aa2f02009-12-31 07:26:16673 }
[email protected]022614ef92008-12-30 20:50:01674
675 ~AutoTracking() {
[email protected]b2a9bbd2011-10-31 22:36:21676 // TODO(jar): Consider emitting a CSV dump of the data at this point. This
677 // should be called after the message loops have all terminated (or at least
678 // the main message loop is gone), so there is little chance for additional
679 // tasks to be Run.
[email protected]022614ef92008-12-30 20:50:01680 }
681
682 private:
[email protected]862aa2f02009-12-31 07:26:16683
[email protected]022614ef92008-12-30 20:50:01684 DISALLOW_COPY_AND_ASSIGN(AutoTracking);
685};
686
initial.commitd7cae122008-07-26 21:49:38687} // namespace tracked_objects
688
689#endif // BASE_TRACKED_OBJECTS_H_