blob: e89bcf944085cf0cd31b6bc5b72f0d1cf9c4e228 [file] [log] [blame]
erg@google.comd5fffd42011-01-08 03:06:45 +09001// Copyright (c) 2011 The Chromium Authors. All rights reserved.
license.botf003cfe2008-08-24 09:55:55 +09002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commit3f4a7322008-07-27 06:49:38 +09004
5#ifndef BASE_TRACKED_OBJECTS_H_
6#define BASE_TRACKED_OBJECTS_H_
thakis@chromium.org01d14522010-07-27 08:08:24 +09007#pragma once
initial.commit3f4a7322008-07-27 06:49:38 +09008
initial.commit3f4a7322008-07-27 06:49:38 +09009#include <map>
jar@chromium.org666ef9c2011-10-25 03:55:16 +090010#include <stack>
initial.commit3f4a7322008-07-27 06:49:38 +090011#include <string>
12#include <vector>
13
darin@chromium.orge585bed2011-08-06 00:34:00 +090014#include "base/base_export.h"
ajwong@chromium.org8e2e3002011-09-22 03:05:41 +090015#include "base/location.h"
16#include "base/time.h"
brettw@chromium.orgabe477a2011-01-21 13:55:52 +090017#include "base/synchronization/lock.h"
brettw@chromium.org63965582010-12-31 07:18:56 +090018#include "base/threading/thread_local_storage.h"
jar@chromium.org4be2cb02011-11-01 07:36:21 +090019#include "base/tracking_info.h"
jar@chromium.org666ef9c2011-10-25 03:55:16 +090020#include "base/values.h"
initial.commit3f4a7322008-07-27 06:49:38 +090021
joi@chromium.org523ca432011-11-08 19:46:48 +090022#if defined(OS_WIN)
23#include <mmsystem.h> // Declare timeGetTime();
24#endif
25
jar@chromium.orgfebe0e42009-12-30 16:31:45 +090026// TrackedObjects provides a database of stats about objects (generally Tasks)
27// that are tracked. Tracking means their birth, death, duration, birth thread,
28// death thread, and birth place are recorded. This data is carefully spread
29// across a series of objects so that the counts and times can be rapidly
30// updated without (usually) having to lock the data, and hence there is usually
31// very little contention caused by the tracking. The data can be viewed via
jar@chromium.orgf9701052011-10-08 03:26:02 +090032// the about:tracking URL, with a variety of sorting and filtering choices.
jar@chromium.orgfebe0e42009-12-30 16:31:45 +090033//
jar@chromium.org0d6778a2010-11-09 06:47:24 +090034// These classes serve as the basis of a profiler of sorts for the Tasks system.
35// As a result, design decisions were made to maximize speed, by minimizing
36// recurring allocation/deallocation, lock contention and data copying. In the
37// "stable" state, which is reached relatively quickly, there is no separate
38// marginal allocation cost associated with construction or destruction of
39// tracked objects, no locks are generally employed, and probably the largest
40// computational cost is associated with obtaining start and stop times for
jar@chromium.org79a58c32011-10-16 08:52:45 +090041// instances as they are created and destroyed.
jar@chromium.orgfebe0e42009-12-30 16:31:45 +090042//
43// The following describes the lifecycle of tracking an instance.
44//
45// First off, when the instance is created, the FROM_HERE macro is expanded
46// to specify the birth place (file, line, function) where the instance was
47// created. That data is used to create a transient Location instance
48// encapsulating the above triple of information. The strings (like __FILE__)
49// are passed around by reference, with the assumption that they are static, and
50// will never go away. This ensures that the strings can be dealt with as atoms
51// with great efficiency (i.e., copying of strings is never needed, and
52// comparisons for equality can be based on pointer comparisons).
53//
54// Next, a Births instance is created for use ONLY on the thread where this
55// instance was created. That Births instance records (in a base class
56// BirthOnThread) references to the static data provided in a Location instance,
57// as well as a pointer specifying the thread on which the birth takes place.
58// Hence there is at most one Births instance for each Location on each thread.
59// The derived Births class contains slots for recording statistics about all
60// instances born at the same location. Statistics currently include only the
61// count of instances constructed.
jar@chromium.org79a58c32011-10-16 08:52:45 +090062//
jar@chromium.orgfebe0e42009-12-30 16:31:45 +090063// Since the base class BirthOnThread contains only constant data, it can be
64// freely accessed by any thread at any time (i.e., only the statistic needs to
jar@chromium.org79a58c32011-10-16 08:52:45 +090065// be handled carefully, and stats are updated exclusively on the birth thread).
jar@chromium.orgfebe0e42009-12-30 16:31:45 +090066//
ajwong@chromium.org8e2e3002011-09-22 03:05:41 +090067// For Tasks, having now either constructed or found the Births instance
68// described above, a pointer to the Births instance is then recorded into the
69// PendingTask structure in MessageLoop. This fact alone is very useful in
jar@chromium.orgfebe0e42009-12-30 16:31:45 +090070// debugging, when there is a question of where an instance came from. In
ajwong@chromium.org8e2e3002011-09-22 03:05:41 +090071// addition, the birth time is also recorded and used to later evaluate the
72// lifetime duration of the whole Task. As a result of the above embedding, we
73// can find out a Task's location of birth, and thread of birth, without using
74// any locks, as all that data is constant across the life of the process.
75//
jar@chromium.org79a58c32011-10-16 08:52:45 +090076// The above work *could* also be done for any other object as well by calling
jar@chromium.org4be2cb02011-11-01 07:36:21 +090077// TallyABirthIfActive() and TallyRunOnNamedThreadIfTracking() as appropriate.
jar@chromium.orgfebe0e42009-12-30 16:31:45 +090078//
79// The amount of memory used in the above data structures depends on how many
80// threads there are, and how many Locations of construction there are.
81// Fortunately, we don't use memory that is the product of those two counts, but
82// rather we only need one Births instance for each thread that constructs an
ajwong@chromium.org8e2e3002011-09-22 03:05:41 +090083// instance at a Location. In many cases, instances are only created on one
84// thread, so the memory utilization is actually fairly restrained.
jar@chromium.orgfebe0e42009-12-30 16:31:45 +090085//
86// Lastly, when an instance is deleted, the final tallies of statistics are
isherman@chromium.orgfe9a84c2011-11-08 16:57:05 +090087// carefully accumulated. That tallying writes into slots (members) in a
jar@chromium.orgfebe0e42009-12-30 16:31:45 +090088// collection of DeathData instances. For each birth place Location that is
89// destroyed on a thread, there is a DeathData instance to record the additional
jar@chromium.org79a58c32011-10-16 08:52:45 +090090// death count, as well as accumulate the run-time and queue-time durations for
91// the instance as it is destroyed (dies). By maintaining a single place to
92// aggregate this running sum *only* for the given thread, we avoid the need to
93// lock such DeathData instances. (i.e., these accumulated stats in a DeathData
94// instance are exclusively updated by the singular owning thread).
jar@chromium.orgfebe0e42009-12-30 16:31:45 +090095//
96// With the above lifecycle description complete, the major remaining detail is
97// explaining how each thread maintains a list of DeathData instances, and of
98// Births instances, and is able to avoid additional (redundant/unnecessary)
99// allocations.
100//
101// Each thread maintains a list of data items specific to that thread in a
102// ThreadData instance (for that specific thread only). The two critical items
103// are lists of DeathData and Births instances. These lists are maintained in
104// STL maps, which are indexed by Location. As noted earlier, we can compare
105// locations very efficiently as we consider the underlying data (file,
106// function, line) to be atoms, and hence pointer comparison is used rather than
107// (slow) string comparisons.
108//
109// To provide a mechanism for iterating over all "known threads," which means
110// threads that have recorded a birth or a death, we create a singly linked list
111// of ThreadData instances. Each such instance maintains a pointer to the next
jar@chromium.org666ef9c2011-10-25 03:55:16 +0900112// one. A static member of ThreadData provides a pointer to the first item on
113// this global list, and access via that all_thread_data_list_head_ item
114// requires the use of the list_lock_.
jar@chromium.orgfebe0e42009-12-30 16:31:45 +0900115// When new ThreadData instances is added to the global list, it is pre-pended,
116// which ensures that any prior acquisition of the list is valid (i.e., the
117// holder can iterate over it without fear of it changing, or the necessity of
118// using an additional lock. Iterations are actually pretty rare (used
119// primarilly for cleanup, or snapshotting data for display), so this lock has
120// very little global performance impact.
121//
122// The above description tries to define the high performance (run time)
123// portions of these classes. After gathering statistics, calls instigated
isherman@chromium.orgfe9a84c2011-11-08 16:57:05 +0900124// by visiting about:tracking will assemble and aggregate data for display. The
jar@chromium.orgfebe0e42009-12-30 16:31:45 +0900125// following data structures are used for producing such displays. They are
126// not performance critical, and their only major constraint is that they should
127// be able to run concurrently with ongoing augmentation of the birth and death
128// data.
129//
isherman@chromium.orgfe9a84c2011-11-08 16:57:05 +0900130// For a given birth location, information about births is spread across data
jar@chromium.orgfebe0e42009-12-30 16:31:45 +0900131// structures that are asynchronously changing on various threads. For display
132// purposes, we need to construct Snapshot instances for each combination of
133// birth thread, death thread, and location, along with the count of such
134// lifetimes. We gather such data into a Snapshot instances, so that such
135// instances can be sorted and aggregated (and remain frozen during our
136// processing). Snapshot instances use pointers to constant portions of the
137// birth and death datastructures, but have local (frozen) copies of the actual
138// statistics (birth count, durations, etc. etc.).
139//
jar@chromium.org79a58c32011-10-16 08:52:45 +0900140// A DataCollector is a container object that holds a set of Snapshots. The
141// statistics in a snapshot are gathered asynhcronously relative to their
142// ongoing updates. It is possible, though highly unlikely, that stats such
isherman@chromium.orgfe9a84c2011-11-08 16:57:05 +0900143// as a 64bit counter could be incorrectly recorded by this process. The
144// 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).
jar@chromium.orgfebe0e42009-12-30 16:31:45 +0900150//
isherman@chromium.orgfe9a84c2011-11-08 16:57:05 +0900151// 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
153// direct rendering to HTML, but we will soon have a JSON serialization as well.
jar@chromium.org79a58c32011-10-16 08:52:45 +0900154
155// For direct HTML display, the data must be sorted, and possibly aggregated
156// (example: how many threads are in a specific consecutive set of Snapshots?
157// What was the total birth count for that set? etc.). Aggregation instances
158// collect running sums of any set of snapshot instances, and are used to print
159// sub-totals in an about:tracking page.
jar@chromium.orgfebe0e42009-12-30 16:31:45 +0900160//
161// TODO(jar): I need to store DataCollections, and provide facilities for taking
162// the difference between two gathered DataCollections. For now, I'm just
jar@chromium.org7ad4a622011-11-07 04:14:48 +0900163// adding a hack that Reset()s to zero all counts and stats. This is also
isherman@chromium.orgfe9a84c2011-11-08 16:57:05 +0900164// done in a slighly thread-unsafe fashion, as the resetting is done
jar@chromium.org7ad4a622011-11-07 04:14:48 +0900165// asynchronously relative to ongoing updates (but all data is 32 bit in size).
166// For basic profiling, this will work "most of the time," and should be
jar@chromium.orgfebe0e42009-12-30 16:31:45 +0900167// sufficient... but storing away DataCollections is the "right way" to do this.
jar@chromium.org7ad4a622011-11-07 04:14:48 +0900168// We'll accomplish this via JavaScript storage of snapshots, and then we'll
169// remove the Reset() methods.
initial.commit3f4a7322008-07-27 06:49:38 +0900170
ajwong@chromium.org8e2e3002011-09-22 03:05:41 +0900171class MessageLoop;
jar@chromium.orgfebe0e42009-12-30 16:31:45 +0900172
initial.commit3f4a7322008-07-27 06:49:38 +0900173namespace tracked_objects {
174
175//------------------------------------------------------------------------------
joi@chromium.org523ca432011-11-08 19:46:48 +0900176
177#define USE_FAST_TIME_CLASS_FOR_DURATION_CALCULATIONS
178
179#if defined(USE_FAST_TIME_CLASS_FOR_DURATION_CALCULATIONS)
180
181// TimeTicks maintains a wasteful 64 bits of data (we need less than 32), and on
182// windows, a 64 bit timer is expensive to even obtain. We use a simple
183// millisecond counter for most of our time values, as well as millisecond units
184// of duration between those values. This means we can only handle durations
185// up to 49 days (range), or 24 days (non-negative time durations).
186// We only define enough methods to service the needs of the tracking classes,
187// and our interfaces are modeled after what TimeTicks and TimeDelta use (so we
188// can swap them into place if we want to use the "real" classes).
189
190class BASE_EXPORT Duration { // Similar to base::TimeDelta.
191 public:
192 Duration() : ms_(0) {}
193
194 Duration& operator+=(const Duration& other) {
195 ms_ += other.ms_;
196 return *this;
197 }
198
199 Duration operator+(const Duration& other) const {
200 return Duration(ms_ + other.ms_);
201 }
202
203 bool operator==(const Duration& other) const { return ms_ == other.ms_; }
204 bool operator!=(const Duration& other) const { return ms_ != other.ms_; }
205 bool operator>(const Duration& other) const { return ms_ > other.ms_; }
206
207 static Duration FromMilliseconds(int ms) { return Duration(ms); }
208
209 int32 InMilliseconds() const { return ms_; }
210
211 private:
212 friend class TrackedTime;
213 explicit Duration(int32 duration) : ms_(duration) {}
214
215 // Internal time is stored directly in milliseconds.
216 int32 ms_;
217};
218
219class BASE_EXPORT TrackedTime { // Similar to base::TimeTicks.
220 public:
221 TrackedTime() : ms_(0) {}
222 explicit TrackedTime(const base::TimeTicks& time)
223 : ms_((time - base::TimeTicks()).InMilliseconds()) {
224 }
225
226 static TrackedTime Now() {
227#if defined(OS_WIN)
228 // Use lock-free accessor to 32 bit time.
229 // Note that TimeTicks::Now() is built on this, so we have "compatible"
230 // times when we down-convert a TimeTicks sample.
231 // TODO(jar): Surface this interface via something in base/time.h.
232 return TrackedTime(static_cast<int32>(::timeGetTime()));
233#else
234 // Posix has nice cheap 64 bit times, so we just down-convert it.
235 return TrackedTime(base::TimeTicks::Now());
236#endif // OS_WIN
237 }
238
239 Duration operator-(const TrackedTime& other) const {
240 return Duration(ms_ - other.ms_);
241 }
242
243 TrackedTime operator+(const Duration& other) const {
244 return TrackedTime(ms_ + other.ms_);
245 }
246
247 bool is_null() const { return ms_ == 0; }
248
249 private:
250 friend class Duration;
251 explicit TrackedTime(int32 ms) : ms_(ms) {}
252
253 // Internal duration is stored directly in milliseconds.
254 uint32 ms_;
255};
256
257#else
258
259// Just use full 64 bit time calculations, and the slower TimeTicks::Now().
260typedef base::TimeTicks TrackedTime;
261typedef base::TimeDelta Duration;
262
263#endif // USE_FAST_TIME_CLASS_FOR_DURATION_CALCULATIONS
264
265//------------------------------------------------------------------------------
initial.commit3f4a7322008-07-27 06:49:38 +0900266// For a specific thread, and a specific birth place, the collection of all
267// death info (with tallies for each death thread, to prevent access conflicts).
268class ThreadData;
darin@chromium.orge585bed2011-08-06 00:34:00 +0900269class BASE_EXPORT BirthOnThread {
initial.commit3f4a7322008-07-27 06:49:38 +0900270 public:
jar@chromium.org666ef9c2011-10-25 03:55:16 +0900271 BirthOnThread(const Location& location, const ThreadData& current);
initial.commit3f4a7322008-07-27 06:49:38 +0900272
273 const Location location() const { return location_; }
274 const ThreadData* birth_thread() const { return birth_thread_; }
275
276 private:
jar@chromium.org79a58c32011-10-16 08:52:45 +0900277 // File/lineno of birth. This defines the essence of the task, as the context
initial.commit3f4a7322008-07-27 06:49:38 +0900278 // of the birth (construction) often tell what the item is for. This field
279 // is const, and hence safe to access from any thread.
280 const Location location_;
281
282 // The thread that records births into this object. Only this thread is
jar@chromium.org666ef9c2011-10-25 03:55:16 +0900283 // allowed to update birth_count_ (which changes over time).
284 const ThreadData* const birth_thread_;
initial.commit3f4a7322008-07-27 06:49:38 +0900285
jar@google.com4cd2c172008-12-31 05:50:01 +0900286 DISALLOW_COPY_AND_ASSIGN(BirthOnThread);
initial.commit3f4a7322008-07-27 06:49:38 +0900287};
288
289//------------------------------------------------------------------------------
290// A class for accumulating counts of births (without bothering with a map<>).
291
darin@chromium.orge585bed2011-08-06 00:34:00 +0900292class BASE_EXPORT Births: public BirthOnThread {
initial.commit3f4a7322008-07-27 06:49:38 +0900293 public:
jar@chromium.org666ef9c2011-10-25 03:55:16 +0900294 Births(const Location& location, const ThreadData& current);
initial.commit3f4a7322008-07-27 06:49:38 +0900295
296 int birth_count() const { return birth_count_; }
297
298 // When we have a birth we update the count for this BirhPLace.
299 void RecordBirth() { ++birth_count_; }
300
301 // When a birthplace is changed (updated), we need to decrement the counter
302 // for the old instance.
303 void ForgetBirth() { --birth_count_; } // We corrected a birth place.
304
jar@chromium.orgfebe0e42009-12-30 16:31:45 +0900305 // Hack to quickly reset all counts to zero.
306 void Clear() { birth_count_ = 0; }
307
initial.commit3f4a7322008-07-27 06:49:38 +0900308 private:
309 // The number of births on this thread for our location_.
310 int birth_count_;
311
jar@google.com4cd2c172008-12-31 05:50:01 +0900312 DISALLOW_COPY_AND_ASSIGN(Births);
initial.commit3f4a7322008-07-27 06:49:38 +0900313};
314
315//------------------------------------------------------------------------------
jar@chromium.org4be2cb02011-11-01 07:36:21 +0900316// Basic info summarizing multiple destructions of a tracked object with a
317// single birthplace (fixed Location). Used both on specific threads, and also
initial.commit3f4a7322008-07-27 06:49:38 +0900318// in snapshots when integrating assembled data.
319
darin@chromium.orge585bed2011-08-06 00:34:00 +0900320class BASE_EXPORT DeathData {
initial.commit3f4a7322008-07-27 06:49:38 +0900321 public:
322 // Default initializer.
jar@chromium.org79a58c32011-10-16 08:52:45 +0900323 DeathData() : count_(0) {}
initial.commit3f4a7322008-07-27 06:49:38 +0900324
325 // When deaths have not yet taken place, and we gather data from all the
326 // threads, we create DeathData stats that tally the number of births without
327 // a corrosponding death.
jar@chromium.org79a58c32011-10-16 08:52:45 +0900328 explicit DeathData(int count) : count_(count) {}
initial.commit3f4a7322008-07-27 06:49:38 +0900329
jar@chromium.org79a58c32011-10-16 08:52:45 +0900330 // Update stats for a task destruction (death) that had a Run() time of
331 // |duration|, and has had a queueing delay of |queue_duration|.
jar@chromium.org4be2cb02011-11-01 07:36:21 +0900332 void RecordDeath(const Duration& queue_duration,
333 const Duration& run_duration);
initial.commit3f4a7322008-07-27 06:49:38 +0900334
335 // Metrics accessors.
336 int count() const { return count_; }
jar@chromium.org0d46f3b2011-11-04 09:23:27 +0900337 Duration run_duration() const { return run_time_.duration(); }
jar@chromium.org79a58c32011-10-16 08:52:45 +0900338 int AverageMsRunDuration() const;
jar@chromium.org0d46f3b2011-11-04 09:23:27 +0900339 Duration run_duration_max() const { return run_time_.max(); }
340 Duration queue_duration() const { return queue_time_.duration(); }
jar@chromium.org79a58c32011-10-16 08:52:45 +0900341 int AverageMsQueueDuration() const;
jar@chromium.org0d46f3b2011-11-04 09:23:27 +0900342 Duration queue_duration_max() const { return queue_time_.max(); }
initial.commit3f4a7322008-07-27 06:49:38 +0900343
jar@chromium.org79a58c32011-10-16 08:52:45 +0900344 // Accumulate metrics from other into this. This method is never used on
345 // realtime statistics, and only used in snapshots and aggregatinos.
initial.commit3f4a7322008-07-27 06:49:38 +0900346 void AddDeathData(const DeathData& other);
347
jar@chromium.org666ef9c2011-10-25 03:55:16 +0900348 // Simple print of internal state for use in line of HTML.
349 void WriteHTML(std::string* output) const;
350
jar@chromium.org4be2cb02011-11-01 07:36:21 +0900351 // Construct a DictionaryValue instance containing all our stats. The caller
jar@chromium.org666ef9c2011-10-25 03:55:16 +0900352 // assumes ownership of the returned instance.
353 base::DictionaryValue* ToValue() const;
initial.commit3f4a7322008-07-27 06:49:38 +0900354
jar@chromium.org79a58c32011-10-16 08:52:45 +0900355 // Reset all tallies to zero. This is used as a hack on realtime data.
initial.commit3f4a7322008-07-27 06:49:38 +0900356 void Clear();
357
358 private:
jar@chromium.org0d46f3b2011-11-04 09:23:27 +0900359 // DeathData::Data is a helper class, useful when different metrics need to be
360 // aggregated, such as queueing times, or run times.
361 class Data {
362 public:
363 Data() {}
364 ~Data() {}
365
366 Duration duration() const { return duration_; }
367 Duration max() const { return max_; }
368
369 // Emits HTML formated description of members, assuming |count| instances
370 // when calculating averages.
371 void WriteHTML(int count, std::string* output) const;
372
373 // Agggegate data into our state.
374 void AddData(const Data& other);
375 void AddDuration(const Duration& duration);
376
377 // Central helper function for calculating averages (correctly, in only one
378 // place).
379 int AverageMsDuration(int count) const;
380
381 // Resets all members to zero.
382 void Clear();
383
384 private:
385 Duration duration_; // Sum of all durations seen.
386 Duration max_; // Largest singular duration seen.
387 };
388
389
390 int count_; // Number of deaths seen.
391 Data run_time_; // Data about run time durations.
392 Data queue_time_; // Data about queueing times durations.
initial.commit3f4a7322008-07-27 06:49:38 +0900393};
394
395//------------------------------------------------------------------------------
396// A temporary collection of data that can be sorted and summarized. It is
397// gathered (carefully) from many threads. Instances are held in arrays and
398// processed, filtered, and rendered.
399// The source of this data was collected on many threads, and is asynchronously
400// changing. The data in this instance is not asynchronously changing.
401
darin@chromium.orge585bed2011-08-06 00:34:00 +0900402class BASE_EXPORT Snapshot {
initial.commit3f4a7322008-07-27 06:49:38 +0900403 public:
404 // When snapshotting a full life cycle set (birth-to-death), use this:
405 Snapshot(const BirthOnThread& birth_on_thread, const ThreadData& death_thread,
406 const DeathData& death_data);
407
408 // When snapshotting a birth, with no death yet, use this:
409 Snapshot(const BirthOnThread& birth_on_thread, int count);
410
initial.commit3f4a7322008-07-27 06:49:38 +0900411 const ThreadData* birth_thread() const { return birth_->birth_thread(); }
412 const Location location() const { return birth_->location(); }
413 const BirthOnThread& birth() const { return *birth_; }
414 const ThreadData* death_thread() const {return death_thread_; }
415 const DeathData& death_data() const { return death_data_; }
416 const std::string DeathThreadName() const;
417
418 int count() const { return death_data_.count(); }
jar@chromium.org4be2cb02011-11-01 07:36:21 +0900419 Duration run_duration() const { return death_data_.run_duration(); }
jar@chromium.org79a58c32011-10-16 08:52:45 +0900420 int AverageMsRunDuration() const {
421 return death_data_.AverageMsRunDuration();
422 }
jar@chromium.org0d46f3b2011-11-04 09:23:27 +0900423 Duration run_duration_max() const {
424 return death_data_.run_duration_max();
425 }
426 Duration queue_duration() const { return death_data_.queue_duration(); }
jar@chromium.org79a58c32011-10-16 08:52:45 +0900427 int AverageMsQueueDuration() const {
428 return death_data_.AverageMsQueueDuration();
429 }
jar@chromium.org0d46f3b2011-11-04 09:23:27 +0900430 Duration queue_duration_max() const {
431 return death_data_.queue_duration_max();
432 }
initial.commit3f4a7322008-07-27 06:49:38 +0900433
jar@chromium.org666ef9c2011-10-25 03:55:16 +0900434 // Emit contents for use in a line of HTML
435 void WriteHTML(std::string* output) const;
436
437 // Construct a DictionaryValue instance containing all our data recursively.
438 // The caller assumes ownership of the memory in the returned instance.
439 base::DictionaryValue* ToValue() const;
initial.commit3f4a7322008-07-27 06:49:38 +0900440
initial.commit3f4a7322008-07-27 06:49:38 +0900441 private:
442 const BirthOnThread* birth_; // Includes Location and birth_thread.
443 const ThreadData* death_thread_;
444 DeathData death_data_;
445};
jar@chromium.org79a58c32011-10-16 08:52:45 +0900446
initial.commit3f4a7322008-07-27 06:49:38 +0900447//------------------------------------------------------------------------------
448// DataCollector is a container class for Snapshot and BirthOnThread count
jar@chromium.org79a58c32011-10-16 08:52:45 +0900449// items.
initial.commit3f4a7322008-07-27 06:49:38 +0900450
darin@chromium.orge585bed2011-08-06 00:34:00 +0900451class BASE_EXPORT DataCollector {
initial.commit3f4a7322008-07-27 06:49:38 +0900452 public:
paulg@google.com2919c092008-08-09 05:03:42 +0900453 typedef std::vector<Snapshot> Collection;
initial.commit3f4a7322008-07-27 06:49:38 +0900454
455 // Construct with a list of how many threads should contribute. This helps us
456 // determine (in the async case) when we are done with all contributions.
457 DataCollector();
erg@google.com71915232010-09-29 07:54:58 +0900458 ~DataCollector();
initial.commit3f4a7322008-07-27 06:49:38 +0900459
jar@chromium.org4be2cb02011-11-01 07:36:21 +0900460 // Adds all stats from the indicated thread into our arrays. This function
461 // uses locks at the lowest level (when accessing the underlying maps which
462 // could change when not locked), and can be called from any threads.
initial.commit3f4a7322008-07-27 06:49:38 +0900463 void Append(const ThreadData& thread_data);
464
jar@chromium.orgfebe0e42009-12-30 16:31:45 +0900465 // After the accumulation phase, the following accessor is used to process the
jar@chromium.org4be2cb02011-11-01 07:36:21 +0900466 // data (i.e., sort it, filter it, etc.).
initial.commit3f4a7322008-07-27 06:49:38 +0900467 Collection* collection();
468
jar@chromium.org4be2cb02011-11-01 07:36:21 +0900469 // Adds entries for all the remaining living objects (objects that have
470 // tallied a birth, but have not yet tallied a matching death, and hence must
471 // be either running, queued up, or being held in limbo for future posting).
472 // This should be called after all known ThreadData instances have been
473 // processed using Append().
initial.commit3f4a7322008-07-27 06:49:38 +0900474 void AddListOfLivingObjects();
475
jar@chromium.org4be2cb02011-11-01 07:36:21 +0900476 // Generates a ListValue representation of the vector of snapshots. The caller
jar@chromium.org666ef9c2011-10-25 03:55:16 +0900477 // assumes ownership of the memory in the returned instance.
478 base::ListValue* ToValue() const;
479
initial.commit3f4a7322008-07-27 06:49:38 +0900480 private:
erg@google.comd5fffd42011-01-08 03:06:45 +0900481 typedef std::map<const BirthOnThread*, int> BirthCount;
482
initial.commit3f4a7322008-07-27 06:49:38 +0900483 // The array that we collect data into.
484 Collection collection_;
485
486 // The total number of births recorded at each location for which we have not
jar@chromium.org4be2cb02011-11-01 07:36:21 +0900487 // seen a death count. This map changes as we do Append() calls, and is later
488 // used by AddListOfLivingObjects() to gather up unaccounted for births.
initial.commit3f4a7322008-07-27 06:49:38 +0900489 BirthCount global_birth_count_;
490
jar@google.com4cd2c172008-12-31 05:50:01 +0900491 DISALLOW_COPY_AND_ASSIGN(DataCollector);
initial.commit3f4a7322008-07-27 06:49:38 +0900492};
493
494//------------------------------------------------------------------------------
495// Aggregation contains summaries (totals and subtotals) of groups of Snapshot
496// instances to provide printing of these collections on a single line.
jar@chromium.org4be2cb02011-11-01 07:36:21 +0900497// We generally provide an aggregate total for the entire list, as well as
498// aggregate subtotals for groups of stats (example: group of all lives that
499// died on the specific thread).
initial.commit3f4a7322008-07-27 06:49:38 +0900500
darin@chromium.orge585bed2011-08-06 00:34:00 +0900501class BASE_EXPORT Aggregation: public DeathData {
initial.commit3f4a7322008-07-27 06:49:38 +0900502 public:
erg@google.com71915232010-09-29 07:54:58 +0900503 Aggregation();
504 ~Aggregation();
initial.commit3f4a7322008-07-27 06:49:38 +0900505
506 void AddDeathSnapshot(const Snapshot& snapshot);
507 void AddBirths(const Births& births);
508 void AddBirth(const BirthOnThread& birth);
509 void AddBirthPlace(const Location& location);
jar@chromium.org666ef9c2011-10-25 03:55:16 +0900510 void WriteHTML(std::string* output) const;
initial.commit3f4a7322008-07-27 06:49:38 +0900511 void Clear();
512
513 private:
514 int birth_count_;
515 std::map<std::string, int> birth_files_;
516 std::map<Location, int> locations_;
517 std::map<const ThreadData*, int> birth_threads_;
518 DeathData death_data_;
519 std::map<const ThreadData*, int> death_threads_;
520
jar@google.com4cd2c172008-12-31 05:50:01 +0900521 DISALLOW_COPY_AND_ASSIGN(Aggregation);
initial.commit3f4a7322008-07-27 06:49:38 +0900522};
523
524//------------------------------------------------------------------------------
jar@chromium.orgfebe0e42009-12-30 16:31:45 +0900525// Comparator is a class that supports the comparison of Snapshot instances.
526// An instance is actually a list of chained Comparitors, that can provide for
jar@chromium.orgf9701052011-10-08 03:26:02 +0900527// arbitrary ordering. The path portion of an about:tracking URL is translated
jar@chromium.orgfebe0e42009-12-30 16:31:45 +0900528// into such a chain, which is then used to order Snapshot instances in a
529// vector. It orders them into groups (for aggregation), and can also order
530// instances within the groups (for detailed rendering of the instances in an
531// aggregation).
initial.commit3f4a7322008-07-27 06:49:38 +0900532
darin@chromium.orge585bed2011-08-06 00:34:00 +0900533class BASE_EXPORT Comparator {
initial.commit3f4a7322008-07-27 06:49:38 +0900534 public:
jar@chromium.orgfebe0e42009-12-30 16:31:45 +0900535 // Selector enum is the token identifier for each parsed keyword, most of
536 // which specify a sort order.
537 // Since it is not meaningful to sort more than once on a specific key, we
538 // use bitfields to accumulate what we have sorted on so far.
initial.commit3f4a7322008-07-27 06:49:38 +0900539 enum Selector {
jar@chromium.orgfebe0e42009-12-30 16:31:45 +0900540 // Sort orders.
initial.commit3f4a7322008-07-27 06:49:38 +0900541 NIL = 0,
542 BIRTH_THREAD = 1,
543 DEATH_THREAD = 2,
544 BIRTH_FILE = 4,
545 BIRTH_FUNCTION = 8,
546 BIRTH_LINE = 16,
547 COUNT = 32,
jar@chromium.org79a58c32011-10-16 08:52:45 +0900548 AVERAGE_RUN_DURATION = 64,
549 TOTAL_RUN_DURATION = 128,
550 AVERAGE_QUEUE_DURATION = 256,
551 TOTAL_QUEUE_DURATION = 512,
jar@chromium.org0d46f3b2011-11-04 09:23:27 +0900552 MAX_RUN_DURATION = 1024,
553 MAX_QUEUE_DURATION = 2048,
jar@chromium.orgfebe0e42009-12-30 16:31:45 +0900554
555 // Imediate action keywords.
556 RESET_ALL_DATA = -1,
jar@chromium.org4be2cb02011-11-01 07:36:21 +0900557 UNKNOWN_KEYWORD = -2,
initial.commit3f4a7322008-07-27 06:49:38 +0900558 };
559
560 explicit Comparator();
561
jar@chromium.orgfebe0e42009-12-30 16:31:45 +0900562 // Reset the comparator to a NIL selector. Clear() and recursively delete any
initial.commit3f4a7322008-07-27 06:49:38 +0900563 // tiebreaker_ entries. NOTE: We can't use a standard destructor, because
564 // the sort algorithm makes copies of this object, and then deletes them,
565 // which would cause problems (either we'd make expensive deep copies, or we'd
566 // do more thna one delete on a tiebreaker_.
567 void Clear();
568
569 // The less() operator for sorting the array via std::sort().
570 bool operator()(const Snapshot& left, const Snapshot& right) const;
571
572 void Sort(DataCollector::Collection* collection) const;
573
574 // Check to see if the items are sort equivalents (should be aggregated).
575 bool Equivalent(const Snapshot& left, const Snapshot& right) const;
576
577 // Check to see if all required fields are present in the given sample.
578 bool Acceptable(const Snapshot& sample) const;
579
580 // A comparator can be refined by specifying what to do if the selected basis
581 // for comparison is insufficient to establish an ordering. This call adds
582 // the indicated attribute as the new "least significant" basis of comparison.
phajdan.jr@chromium.org5130ec22009-07-07 05:11:00 +0900583 void SetTiebreaker(Selector selector, const std::string& required);
initial.commit3f4a7322008-07-27 06:49:38 +0900584
585 // Indicate if this instance is set up to sort by the given Selector, thereby
586 // putting that information in the SortGrouping, so it is not needed in each
587 // printed line.
588 bool IsGroupedBy(Selector selector) const;
589
jar@chromium.org79a58c32011-10-16 08:52:45 +0900590 // Using the tiebreakers as set above, we mostly get an ordering, with some
initial.commit3f4a7322008-07-27 06:49:38 +0900591 // equivalent groups. If those groups are displayed (rather than just being
592 // aggregated, then the following is used to order them (within the group).
593 void SetSubgroupTiebreaker(Selector selector);
594
595 // Translate a keyword and restriction in URL path to a selector for sorting.
phajdan.jr@chromium.org5130ec22009-07-07 05:11:00 +0900596 void ParseKeyphrase(const std::string& key_phrase);
initial.commit3f4a7322008-07-27 06:49:38 +0900597
tsepez@chromium.orgd0f33c22011-06-29 02:35:18 +0900598 // Parse a query to decide on sort ordering.
phajdan.jr@chromium.org5130ec22009-07-07 05:11:00 +0900599 bool ParseQuery(const std::string& query);
initial.commit3f4a7322008-07-27 06:49:38 +0900600
601 // Output a header line that can be used to indicated what items will be
602 // collected in the group. It lists all (potentially) tested attributes and
603 // their values (in the sample item).
604 bool WriteSortGrouping(const Snapshot& sample, std::string* output) const;
605
606 // Output a sample, with SortGroup details not displayed.
jar@chromium.org666ef9c2011-10-25 03:55:16 +0900607 void WriteSnapshotHTML(const Snapshot& sample, std::string* output) const;
initial.commit3f4a7322008-07-27 06:49:38 +0900608
609 private:
610 // The selector directs this instance to compare based on the specified
611 // members of the tested elements.
612 enum Selector selector_;
613
jar@chromium.org4be2cb02011-11-01 07:36:21 +0900614 // Translate a path keyword into a selector. This is a slow implementation,
615 // but this is rarely done, and only for HTML presentations.
616 static Selector FindSelector(const std::string& keyword);
617
initial.commit3f4a7322008-07-27 06:49:38 +0900618 // For filtering into acceptable and unacceptable snapshot instance, the
619 // following is required to be a substring of the selector_ field.
620 std::string required_;
621
622 // If this instance can't decide on an ordering, we can consult a tie-breaker
623 // which may have a different basis of comparison.
624 Comparator* tiebreaker_;
625
626 // We or together all the selectors we sort on (not counting sub-group
627 // selectors), so that we can tell if we've decided to group on any given
628 // criteria.
629 int combined_selectors_;
630
631 // Some tiebreakrs are for subgroup ordering, and not for basic ordering (in
632 // preparation for aggregation). The subgroup tiebreakers are not consulted
633 // when deciding if two items are in equivalent groups. This flag tells us
634 // to ignore the tiebreaker when doing Equivalent() testing.
635 bool use_tiebreaker_for_sort_only_;
636};
637
initial.commit3f4a7322008-07-27 06:49:38 +0900638//------------------------------------------------------------------------------
639// For each thread, we have a ThreadData that stores all tracking info generated
640// on this thread. This prevents the need for locking as data accumulates.
jar@chromium.org4be2cb02011-11-01 07:36:21 +0900641// We use ThreadLocalStorage to quickly identfy the current ThreadData context.
642// We also have a linked list of ThreadData instances, and that list is used to
643// harvest data from all existing instances.
initial.commit3f4a7322008-07-27 06:49:38 +0900644
darin@chromium.orge585bed2011-08-06 00:34:00 +0900645class BASE_EXPORT ThreadData {
initial.commit3f4a7322008-07-27 06:49:38 +0900646 public:
jar@chromium.org4be2cb02011-11-01 07:36:21 +0900647 // Current allowable states of the tracking system. The states can vary
648 // between ACTIVE and DEACTIVATED, but can never go back to UNINITIALIZED.
649 enum Status {
650 UNINITIALIZED,
651 ACTIVE,
652 DEACTIVATED,
653 };
654
initial.commit3f4a7322008-07-27 06:49:38 +0900655 typedef std::map<Location, Births*> BirthMap;
656 typedef std::map<const Births*, DeathData> DeathMap;
657
jar@chromium.org79a58c32011-10-16 08:52:45 +0900658 // Initialize the current thread context with a new instance of ThreadData.
jar@chromium.org4be2cb02011-11-01 07:36:21 +0900659 // This is used by all threads that have names, and should be explicitly
660 // set *before* any births on the threads have taken place. It is generally
661 // only used by the message loop, which has a well defined thread name.
jar@chromium.org79a58c32011-10-16 08:52:45 +0900662 static void InitializeThreadContext(const std::string& suggested_name);
initial.commit3f4a7322008-07-27 06:49:38 +0900663
664 // Using Thread Local Store, find the current instance for collecting data.
665 // If an instance does not exist, construct one (and remember it for use on
666 // this thread.
jar@chromium.org666ef9c2011-10-25 03:55:16 +0900667 // This may return NULL if the system is disabled for any reason.
jar@chromium.org79a58c32011-10-16 08:52:45 +0900668 static ThreadData* Get();
initial.commit3f4a7322008-07-27 06:49:38 +0900669
jar@chromium.orgf9701052011-10-08 03:26:02 +0900670 // For a given (unescaped) about:tracking query, develop resulting HTML, and
tsepez@chromium.orgd0f33c22011-06-29 02:35:18 +0900671 // append to output.
initial.commit3f4a7322008-07-27 06:49:38 +0900672 static void WriteHTML(const std::string& query, std::string* output);
673
674 // For a given accumulated array of results, use the comparator to sort and
675 // subtotal, writing the results to the output.
676 static void WriteHTMLTotalAndSubtotals(
677 const DataCollector::Collection& match_array,
678 const Comparator& comparator, std::string* output);
679
jar@chromium.org4be2cb02011-11-01 07:36:21 +0900680 // Constructs a DictionaryValue instance containing all recursive results in
681 // our process. The caller assumes ownership of the memory in the returned
682 // instance.
683 static base::DictionaryValue* ToValue();
684
685 // Finds (or creates) a place to count births from the given location in this
jar@chromium.org666ef9c2011-10-25 03:55:16 +0900686 // thread, and increment that tally.
ajwong@chromium.org12fa0922011-07-27 03:25:16 +0900687 // TallyABirthIfActive will returns NULL if the birth cannot be tallied.
688 static Births* TallyABirthIfActive(const Location& location);
jar@chromium.org79a58c32011-10-16 08:52:45 +0900689
jar@chromium.org4be2cb02011-11-01 07:36:21 +0900690 // Records the end of a timed run of an object. The |completed_task| contains
691 // a pointer to a Births, the time_posted, and a delayed_start_time if any.
692 // The |start_of_run| indicates when we started to perform the run of the
693 // task. The delayed_start_time is non-null for tasks that were posted as
694 // delayed tasks, and it indicates when the task should have run (i.e., when
695 // it should have posted out of the timer queue, and into the work queue.
696 // The |end_of_run| was just obtained by a call to Now() (just after the task
697 // finished). It is provided as an argument to help with testing.
698 static void TallyRunOnNamedThreadIfTracking(
699 const base::TrackingInfo& completed_task,
700 const TrackedTime& start_of_run,
701 const TrackedTime& end_of_run);
702
jar@chromium.orgb8bb8522011-10-29 06:41:50 +0900703 // Record the end of a timed run of an object. The |birth| is the record for
jar@chromium.org4be2cb02011-11-01 07:36:21 +0900704 // the instance, the |time_posted| records that instant, which is presumed to
705 // be when the task was posted into a queue to run on a worker thread.
706 // The |start_of_run| is when the worker thread started to perform the run of
707 // the task.
jar@chromium.org666ef9c2011-10-25 03:55:16 +0900708 // The |end_of_run| was just obtained by a call to Now() (just after the task
709 // finished).
jar@chromium.org4be2cb02011-11-01 07:36:21 +0900710 static void TallyRunOnWorkerThreadIfTracking(
711 const Births* birth,
712 const TrackedTime& time_posted,
713 const TrackedTime& start_of_run,
714 const TrackedTime& end_of_run);
initial.commit3f4a7322008-07-27 06:49:38 +0900715
jar@chromium.org79a58c32011-10-16 08:52:45 +0900716 const std::string thread_name() const { return thread_name_; }
initial.commit3f4a7322008-07-27 06:49:38 +0900717
jar@chromium.org666ef9c2011-10-25 03:55:16 +0900718 // ---------------------
719 // The following functions should all be private, and are only public because
720 // the collection is done externally. We need to relocate that code from the
721 // collection class into this class, and then all these methods can be made
722 // private.
723 // (Thread safe) Get start of list of all ThreadData instances.
724 static ThreadData* first();
725 // Iterate through the null terminated list of ThreadData instances.
726 ThreadData* next() const { return next_; }
initial.commit3f4a7322008-07-27 06:49:38 +0900727 // Using our lock, make a copy of the specified maps. These calls may arrive
jar@chromium.orgfebe0e42009-12-30 16:31:45 +0900728 // from non-local threads, and are used to quickly scan data from all threads
jar@chromium.orgf9701052011-10-08 03:26:02 +0900729 // in order to build an HTML page for about:tracking.
initial.commit3f4a7322008-07-27 06:49:38 +0900730 void SnapshotBirthMap(BirthMap *output) const;
731 void SnapshotDeathMap(DeathMap *output) const;
jar@chromium.org666ef9c2011-10-25 03:55:16 +0900732 // -------- end of should be private methods.
initial.commit3f4a7322008-07-27 06:49:38 +0900733
jar@chromium.orgfebe0e42009-12-30 16:31:45 +0900734 // Hack: asynchronously clear all birth counts and death tallies data values
735 // in all ThreadData instances. The numerical (zeroing) part is done without
736 // use of a locks or atomics exchanges, and may (for int64 values) produce
737 // bogus counts VERY rarely.
738 static void ResetAllThreadData();
739
jar@chromium.org4be2cb02011-11-01 07:36:21 +0900740 // Initializes all statics if needed (this initialization call should be made
741 // while we are single threaded). Returns false if unable to initialize.
742 static bool Initialize();
743
744 // Sets internal status_ to either become ACTIVE, or DEACTIVATED,
initial.commit3f4a7322008-07-27 06:49:38 +0900745 // based on argument being true or false respectively.
jar@chromium.org4be2cb02011-11-01 07:36:21 +0900746 // If tracking is not compiled in, this function will return false.
747 static bool InitializeAndSetTrackingStatus(bool status);
748 static bool tracking_status();
initial.commit3f4a7322008-07-27 06:49:38 +0900749
jar@chromium.org79a58c32011-10-16 08:52:45 +0900750 // Provide a time function that does nothing (runs fast) when we don't have
751 // the profiler enabled. It will generally be optimized away when it is
752 // ifdef'ed to be small enough (allowing the profiler to be "compiled out" of
753 // the code).
jar@chromium.org4be2cb02011-11-01 07:36:21 +0900754 static TrackedTime Now();
initial.commit3f4a7322008-07-27 06:49:38 +0900755
initial.commit3f4a7322008-07-27 06:49:38 +0900756 private:
jar@chromium.org7ad4a622011-11-07 04:14:48 +0900757 // Allow only tests to call ShutdownSingleThreadedCleanup. We NEVER call it
758 // in production code.
759 friend class TrackedObjectsTest;
760
jar@chromium.org666ef9c2011-10-25 03:55:16 +0900761 typedef std::stack<const ThreadData*> ThreadDataPool;
762
763 // Worker thread construction creates a name since there is none.
764 ThreadData();
765 // Message loop based construction should provide a name.
766 explicit ThreadData(const std::string& suggested_name);
767
768 ~ThreadData();
769
770 // Push this instance to the head of all_thread_data_list_head_, linking it to
771 // the previous head. This is performed after each construction, and leaves
772 // the instance permanently on that list.
773 void PushToHeadOfList();
774
775 // In this thread's data, record a new birth.
776 Births* TallyABirth(const Location& location);
777
778 // Find a place to record a death on this thread.
779 void TallyADeath(const Births& birth,
jar@chromium.org4be2cb02011-11-01 07:36:21 +0900780 const Duration& queue_duration,
781 const Duration& duration);
jar@chromium.org666ef9c2011-10-25 03:55:16 +0900782
783 // Using our lock to protect the iteration, Clear all birth and death data.
784 void Reset();
785
786 // This method is called by the TLS system when a thread terminates.
787 // The argument may be NULL if this thread has never tracked a birth or death.
788 static void OnThreadTermination(void* thread_data);
789
790 // This method should be called when a worker thread terminates, so that we
791 // can save all the thread data into a cache of reusable ThreadData instances.
792 void OnThreadTerminationCleanup() const;
793
jar@chromium.org7ad4a622011-11-07 04:14:48 +0900794 // Cleans up data structures, and returns statics to near pristine (mostly
795 // uninitialized) state. If there is any chance that other threads are still
796 // using the data structures, then the |leak| argument should be passed in as
797 // true, and the data structures (birth maps, death maps, ThreadData
798 // insntances, etc.) will be leaked and not deleted. If you have joined all
799 // threads since the time that InitializeAndSetTrackingStatus() was called,
800 // then you can pass in a |leak| value of false, and this function will
801 // delete recursively all data structures, starting with the list of
802 // ThreadData instances.
803 static void ShutdownSingleThreadedCleanup(bool leak);
804
initial.commit3f4a7322008-07-27 06:49:38 +0900805 // We use thread local store to identify which ThreadData to interact with.
brettw@chromium.org63965582010-12-31 07:18:56 +0900806 static base::ThreadLocalStorage::Slot tls_index_;
initial.commit3f4a7322008-07-27 06:49:38 +0900807
808 // Link to the most recently created instance (starts a null terminated list).
jar@chromium.org666ef9c2011-10-25 03:55:16 +0900809 // The list is traversed by about:tracking when it needs to snapshot data.
jar@chromium.org4be2cb02011-11-01 07:36:21 +0900810 // This is only accessed while list_lock_ is held.
jar@chromium.org666ef9c2011-10-25 03:55:16 +0900811 static ThreadData* all_thread_data_list_head_;
812 // Set of ThreadData instances for use with worker threads. When a worker
813 // thread is done (terminating), we push it into this pool. When a new worker
814 // thread is created, we first try to re-use a ThreadData instance from the
815 // pool, and if none are available, construct a new one.
jar@chromium.org4be2cb02011-11-01 07:36:21 +0900816 // This is only accessed while list_lock_ is held.
jar@chromium.org666ef9c2011-10-25 03:55:16 +0900817 static ThreadDataPool* unregistered_thread_data_pool_;
jar@chromium.org4be2cb02011-11-01 07:36:21 +0900818 // The next available thread number. This should only be accessed when the
819 // list_lock_ is held.
820 static int thread_number_counter_;
821 // Incarnation sequence number, indicating how many times (during unittests)
822 // we've either transitioned out of UNINITIALIZED, or into that state. This
823 // value is only accessed while the list_lock_ is held.
824 static int incarnation_counter_;
jar@chromium.org666ef9c2011-10-25 03:55:16 +0900825 // Protection for access to all_thread_data_list_head_, and to
jar@chromium.org4be2cb02011-11-01 07:36:21 +0900826 // unregistered_thread_data_pool_. This lock is leaked at shutdown.
827 static base::Lock* list_lock_;
828
829 // Record of what the incarnation_counter_ was when this instance was created.
830 // If the incarnation_counter_ has changed, then we avoid pushing into the
831 // pool (this is only critical in tests which go through multiple
832 // incarations).
833 int incarnation_count_for_pool_;
initial.commit3f4a7322008-07-27 06:49:38 +0900834
jar@chromium.org79a58c32011-10-16 08:52:45 +0900835 // We set status_ to SHUTDOWN when we shut down the tracking service.
initial.commit3f4a7322008-07-27 06:49:38 +0900836 static Status status_;
837
838 // Link to next instance (null terminated list). Used to globally track all
839 // registered instances (corresponds to all registered threads where we keep
840 // data).
841 ThreadData* next_;
842
jar@chromium.org79a58c32011-10-16 08:52:45 +0900843 // The name of the thread that is being recorded. If this thread has no
844 // message_loop, then this is a worker thread, with a sequence number postfix.
845 std::string thread_name_;
initial.commit3f4a7322008-07-27 06:49:38 +0900846
jar@chromium.org666ef9c2011-10-25 03:55:16 +0900847 // Indicate if this is a worker thread, and the ThreadData contexts should be
848 // stored in the unregistered_thread_data_pool_ when not in use.
849 bool is_a_worker_thread_;
850
initial.commit3f4a7322008-07-27 06:49:38 +0900851 // A map used on each thread to keep track of Births on this thread.
852 // This map should only be accessed on the thread it was constructed on.
853 // When a snapshot is needed, this structure can be locked in place for the
854 // duration of the snapshotting activity.
855 BirthMap birth_map_;
856
857 // Similar to birth_map_, this records informations about death of tracked
858 // instances (i.e., when a tracked instance was destroyed on this thread).
jar@chromium.orgfebe0e42009-12-30 16:31:45 +0900859 // It is locked before changing, and hence other threads may access it by
860 // locking before reading it.
initial.commit3f4a7322008-07-27 06:49:38 +0900861 DeathMap death_map_;
862
jar@chromium.orgfebe0e42009-12-30 16:31:45 +0900863 // Lock to protect *some* access to BirthMap and DeathMap. The maps are
864 // regularly read and written on this thread, but may only be read from other
865 // threads. To support this, we acquire this lock if we are writing from this
866 // thread, or reading from another thread. For reading from this thread we
867 // don't need a lock, as there is no potential for a conflict since the
868 // writing is only done from this thread.
brettw@chromium.orgabe477a2011-01-21 13:55:52 +0900869 mutable base::Lock lock_;
initial.commit3f4a7322008-07-27 06:49:38 +0900870
jar@google.com4cd2c172008-12-31 05:50:01 +0900871 DISALLOW_COPY_AND_ASSIGN(ThreadData);
initial.commit3f4a7322008-07-27 06:49:38 +0900872};
873
jar@google.com4cd2c172008-12-31 05:50:01 +0900874//------------------------------------------------------------------------------
875// Provide simple way to to start global tracking, and to tear down tracking
jar@chromium.org666ef9c2011-10-25 03:55:16 +0900876// when done. The design has evolved to *not* do any teardown (and just leak
877// all allocated data structures). As a result, we don't have any code in this
878// destructor, and perhaps this whole class should go away.
jar@chromium.org4f19fac2009-12-31 16:26:16 +0900879
darin@chromium.orge585bed2011-08-06 00:34:00 +0900880class BASE_EXPORT AutoTracking {
jar@google.com4cd2c172008-12-31 05:50:01 +0900881 public:
jar@chromium.org4f19fac2009-12-31 16:26:16 +0900882 AutoTracking() {
jar@chromium.org4be2cb02011-11-01 07:36:21 +0900883 ThreadData::Initialize();
jar@chromium.org4f19fac2009-12-31 16:26:16 +0900884 }
jar@google.com4cd2c172008-12-31 05:50:01 +0900885
886 ~AutoTracking() {
jar@chromium.org4be2cb02011-11-01 07:36:21 +0900887 // TODO(jar): Consider emitting a CSV dump of the data at this point. This
888 // should be called after the message loops have all terminated (or at least
889 // the main message loop is gone), so there is little chance for additional
890 // tasks to be Run.
jar@google.com4cd2c172008-12-31 05:50:01 +0900891 }
892
893 private:
jar@chromium.org4f19fac2009-12-31 16:26:16 +0900894
jar@google.com4cd2c172008-12-31 05:50:01 +0900895 DISALLOW_COPY_AND_ASSIGN(AutoTracking);
896};
897
initial.commit3f4a7322008-07-27 06:49:38 +0900898} // namespace tracked_objects
899
900#endif // BASE_TRACKED_OBJECTS_H_