blob: 159399127c04db3fc0c286608a6e55e890392d36 [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]c62dd9d2011-09-21 18:05:4115#include "base/location.h"
16#include "base/time.h"
[email protected]20305ec2011-01-21 04:55:5217#include "base/synchronization/lock.h"
[email protected]1357c322010-12-30 22:18:5618#include "base/threading/thread_local_storage.h"
[email protected]84baeca2011-10-24 18:55:1619#include "base/values.h"
initial.commitd7cae122008-07-26 21:49:3820
[email protected]75b79202009-12-30 07:31:4521// TrackedObjects provides a database of stats about objects (generally Tasks)
22// that are tracked. Tracking means their birth, death, duration, birth thread,
23// death thread, and birth place are recorded. This data is carefully spread
24// across a series of objects so that the counts and times can be rapidly
25// updated without (usually) having to lock the data, and hence there is usually
26// very little contention caused by the tracking. The data can be viewed via
[email protected]ca1863672011-10-07 18:26:0227// the about:tracking URL, with a variety of sorting and filtering choices.
[email protected]75b79202009-12-30 07:31:4528//
[email protected]ea319e42010-11-08 21:47:2429// These classes serve as the basis of a profiler of sorts for the Tasks system.
30// As a result, design decisions were made to maximize speed, by minimizing
31// recurring allocation/deallocation, lock contention and data copying. In the
32// "stable" state, which is reached relatively quickly, there is no separate
33// marginal allocation cost associated with construction or destruction of
34// tracked objects, no locks are generally employed, and probably the largest
35// computational cost is associated with obtaining start and stop times for
[email protected]84b57952011-10-15 23:52:4536// instances as they are created and destroyed.
[email protected]75b79202009-12-30 07:31:4537//
38// The following describes the lifecycle of tracking an instance.
39//
40// First off, when the instance is created, the FROM_HERE macro is expanded
41// to specify the birth place (file, line, function) where the instance was
42// created. That data is used to create a transient Location instance
43// encapsulating the above triple of information. The strings (like __FILE__)
44// are passed around by reference, with the assumption that they are static, and
45// will never go away. This ensures that the strings can be dealt with as atoms
46// with great efficiency (i.e., copying of strings is never needed, and
47// comparisons for equality can be based on pointer comparisons).
48//
49// Next, a Births instance is created for use ONLY on the thread where this
50// instance was created. That Births instance records (in a base class
51// BirthOnThread) references to the static data provided in a Location instance,
52// as well as a pointer specifying the thread on which the birth takes place.
53// Hence there is at most one Births instance for each Location on each thread.
54// The derived Births class contains slots for recording statistics about all
55// instances born at the same location. Statistics currently include only the
56// count of instances constructed.
[email protected]84b57952011-10-15 23:52:4557//
[email protected]75b79202009-12-30 07:31:4558// Since the base class BirthOnThread contains only constant data, it can be
59// freely accessed by any thread at any time (i.e., only the statistic needs to
[email protected]84b57952011-10-15 23:52:4560// be handled carefully, and stats are updated exclusively on the birth thread).
[email protected]75b79202009-12-30 07:31:4561//
[email protected]c62dd9d2011-09-21 18:05:4162// For Tasks, having now either constructed or found the Births instance
63// described above, a pointer to the Births instance is then recorded into the
64// PendingTask structure in MessageLoop. This fact alone is very useful in
[email protected]75b79202009-12-30 07:31:4565// debugging, when there is a question of where an instance came from. In
[email protected]c62dd9d2011-09-21 18:05:4166// addition, the birth time is also recorded and used to later evaluate the
67// lifetime duration of the whole Task. As a result of the above embedding, we
68// can find out a Task's location of birth, and thread of birth, without using
69// any locks, as all that data is constant across the life of the process.
70//
[email protected]84b57952011-10-15 23:52:4571// The above work *could* also be done for any other object as well by calling
[email protected]6b26b96012011-10-28 21:41:5072// TallyABirthIfActive() and TallyADeathIfActive() as appropriate.
[email protected]75b79202009-12-30 07:31:4573//
74// The amount of memory used in the above data structures depends on how many
75// threads there are, and how many Locations of construction there are.
76// Fortunately, we don't use memory that is the product of those two counts, but
77// rather we only need one Births instance for each thread that constructs an
[email protected]c62dd9d2011-09-21 18:05:4178// instance at a Location. In many cases, instances are only created on one
79// thread, so the memory utilization is actually fairly restrained.
[email protected]75b79202009-12-30 07:31:4580//
81// Lastly, when an instance is deleted, the final tallies of statistics are
82// carefully accumulated. That tallying wrties into slots (members) in a
83// collection of DeathData instances. For each birth place Location that is
84// destroyed on a thread, there is a DeathData instance to record the additional
[email protected]84b57952011-10-15 23:52:4585// death count, as well as accumulate the run-time and queue-time durations for
86// the instance as it is destroyed (dies). By maintaining a single place to
87// aggregate this running sum *only* for the given thread, we avoid the need to
88// lock such DeathData instances. (i.e., these accumulated stats in a DeathData
89// instance are exclusively updated by the singular owning thread).
[email protected]75b79202009-12-30 07:31:4590//
91// With the above lifecycle description complete, the major remaining detail is
92// explaining how each thread maintains a list of DeathData instances, and of
93// Births instances, and is able to avoid additional (redundant/unnecessary)
94// allocations.
95//
96// Each thread maintains a list of data items specific to that thread in a
97// ThreadData instance (for that specific thread only). The two critical items
98// are lists of DeathData and Births instances. These lists are maintained in
99// STL maps, which are indexed by Location. As noted earlier, we can compare
100// locations very efficiently as we consider the underlying data (file,
101// function, line) to be atoms, and hence pointer comparison is used rather than
102// (slow) string comparisons.
103//
104// To provide a mechanism for iterating over all "known threads," which means
105// threads that have recorded a birth or a death, we create a singly linked list
106// of ThreadData instances. Each such instance maintains a pointer to the next
[email protected]84baeca2011-10-24 18:55:16107// one. A static member of ThreadData provides a pointer to the first item on
108// this global list, and access via that all_thread_data_list_head_ item
109// requires the use of the list_lock_.
[email protected]75b79202009-12-30 07:31:45110// When new ThreadData instances is added to the global list, it is pre-pended,
111// which ensures that any prior acquisition of the list is valid (i.e., the
112// holder can iterate over it without fear of it changing, or the necessity of
113// using an additional lock. Iterations are actually pretty rare (used
114// primarilly for cleanup, or snapshotting data for display), so this lock has
115// very little global performance impact.
116//
117// The above description tries to define the high performance (run time)
118// portions of these classes. After gathering statistics, calls instigated
[email protected]ca1863672011-10-07 18:26:02119// by visiting about:tracking will assemble and aggregate data for display. The
[email protected]75b79202009-12-30 07:31:45120// following data structures are used for producing such displays. They are
121// not performance critical, and their only major constraint is that they should
122// be able to run concurrently with ongoing augmentation of the birth and death
123// data.
124//
125// For a given birth location, information about births are spread across data
126// structures that are asynchronously changing on various threads. For display
127// purposes, we need to construct Snapshot instances for each combination of
128// birth thread, death thread, and location, along with the count of such
129// lifetimes. We gather such data into a Snapshot instances, so that such
130// instances can be sorted and aggregated (and remain frozen during our
131// processing). Snapshot instances use pointers to constant portions of the
132// birth and death datastructures, but have local (frozen) copies of the actual
133// statistics (birth count, durations, etc. etc.).
134//
[email protected]84b57952011-10-15 23:52:45135// A DataCollector is a container object that holds a set of Snapshots. The
136// statistics in a snapshot are gathered asynhcronously relative to their
137// ongoing updates. It is possible, though highly unlikely, that stats such
138// as a 64bit counter could incorrectly recorded by this process. The advantage
139// to having fast (non-atomic) updates of the data outweighs the minimal risk
140// of a singular corrupt statistic snapshot (only the snapshot could be corrupt,
141// not the underlying and ongoing stistic). In constrast, pointer data that is
142// accessed during snapshotting is completely invariant, and hence is perfectly
143// acquired (i.e., no potential corruption, and no risk of a bad memory
144// reference).
[email protected]75b79202009-12-30 07:31:45145//
146// After an array of Snapshots instances are colleted into a DataCollector, they
[email protected]84b57952011-10-15 23:52:45147// need to be prepared for display our output. We currently implement a direct
148// renderin to HTML, but we will soon also have a JSON serialization as well.
149
150// For direct HTML display, the data must be sorted, and possibly aggregated
151// (example: how many threads are in a specific consecutive set of Snapshots?
152// What was the total birth count for that set? etc.). Aggregation instances
153// collect running sums of any set of snapshot instances, and are used to print
154// sub-totals in an about:tracking page.
[email protected]75b79202009-12-30 07:31:45155//
156// TODO(jar): I need to store DataCollections, and provide facilities for taking
157// the difference between two gathered DataCollections. For now, I'm just
158// adding a hack that Reset()'s to zero all counts and stats. This is also
159// done in a slighly thread-unsafe fashion, as the reseting is done
160// asynchronously relative to ongoing updates, and worse yet, some data fields
161// are 64bit quantities, and are not atomicly accessed (reset or incremented
162// etc.). For basic profiling, this will work "most of the time," and should be
163// sufficient... but storing away DataCollections is the "right way" to do this.
initial.commitd7cae122008-07-26 21:49:38164
[email protected]c62dd9d2011-09-21 18:05:41165class MessageLoop;
[email protected]75b79202009-12-30 07:31:45166
initial.commitd7cae122008-07-26 21:49:38167namespace tracked_objects {
168
169//------------------------------------------------------------------------------
170// For a specific thread, and a specific birth place, the collection of all
171// death info (with tallies for each death thread, to prevent access conflicts).
172class ThreadData;
[email protected]0bea7252011-08-05 15:34:00173class BASE_EXPORT BirthOnThread {
initial.commitd7cae122008-07-26 21:49:38174 public:
[email protected]84baeca2011-10-24 18:55:16175 BirthOnThread(const Location& location, const ThreadData& current);
initial.commitd7cae122008-07-26 21:49:38176
177 const Location location() const { return location_; }
178 const ThreadData* birth_thread() const { return birth_thread_; }
179
180 private:
[email protected]84b57952011-10-15 23:52:45181 // File/lineno of birth. This defines the essence of the task, as the context
initial.commitd7cae122008-07-26 21:49:38182 // of the birth (construction) often tell what the item is for. This field
183 // is const, and hence safe to access from any thread.
184 const Location location_;
185
186 // The thread that records births into this object. Only this thread is
[email protected]84baeca2011-10-24 18:55:16187 // allowed to update birth_count_ (which changes over time).
188 const ThreadData* const birth_thread_;
initial.commitd7cae122008-07-26 21:49:38189
[email protected]022614ef92008-12-30 20:50:01190 DISALLOW_COPY_AND_ASSIGN(BirthOnThread);
initial.commitd7cae122008-07-26 21:49:38191};
192
193//------------------------------------------------------------------------------
194// A class for accumulating counts of births (without bothering with a map<>).
195
[email protected]0bea7252011-08-05 15:34:00196class BASE_EXPORT Births: public BirthOnThread {
initial.commitd7cae122008-07-26 21:49:38197 public:
[email protected]84baeca2011-10-24 18:55:16198 Births(const Location& location, const ThreadData& current);
initial.commitd7cae122008-07-26 21:49:38199
200 int birth_count() const { return birth_count_; }
201
202 // When we have a birth we update the count for this BirhPLace.
203 void RecordBirth() { ++birth_count_; }
204
205 // When a birthplace is changed (updated), we need to decrement the counter
206 // for the old instance.
207 void ForgetBirth() { --birth_count_; } // We corrected a birth place.
208
[email protected]75b79202009-12-30 07:31:45209 // Hack to quickly reset all counts to zero.
210 void Clear() { birth_count_ = 0; }
211
initial.commitd7cae122008-07-26 21:49:38212 private:
213 // The number of births on this thread for our location_.
214 int birth_count_;
215
[email protected]022614ef92008-12-30 20:50:01216 DISALLOW_COPY_AND_ASSIGN(Births);
initial.commitd7cae122008-07-26 21:49:38217};
218
219//------------------------------------------------------------------------------
[email protected]6b26b96012011-10-28 21:41:50220// Basic info summarizing multiple destructions of an object with a single
221// birthplace (fixed Location). Used both on specific threads, and also used
initial.commitd7cae122008-07-26 21:49:38222// in snapshots when integrating assembled data.
223
[email protected]0bea7252011-08-05 15:34:00224class BASE_EXPORT DeathData {
initial.commitd7cae122008-07-26 21:49:38225 public:
226 // Default initializer.
[email protected]84b57952011-10-15 23:52:45227 DeathData() : count_(0) {}
initial.commitd7cae122008-07-26 21:49:38228
229 // When deaths have not yet taken place, and we gather data from all the
230 // threads, we create DeathData stats that tally the number of births without
231 // a corrosponding death.
[email protected]84b57952011-10-15 23:52:45232 explicit DeathData(int count) : count_(count) {}
initial.commitd7cae122008-07-26 21:49:38233
[email protected]84b57952011-10-15 23:52:45234 // Update stats for a task destruction (death) that had a Run() time of
235 // |duration|, and has had a queueing delay of |queue_duration|.
[email protected]6b26b96012011-10-28 21:41:50236 void RecordDeath(const base::TimeDelta& queue_duration,
237 const base::TimeDelta& run_duration);
initial.commitd7cae122008-07-26 21:49:38238
239 // Metrics accessors.
240 int count() const { return count_; }
[email protected]6b26b96012011-10-28 21:41:50241 base::TimeDelta run_duration() const { return run_duration_; }
[email protected]84b57952011-10-15 23:52:45242 int AverageMsRunDuration() const;
[email protected]6b26b96012011-10-28 21:41:50243 base::TimeDelta queue_duration() const { return queue_duration_; }
[email protected]84b57952011-10-15 23:52:45244 int AverageMsQueueDuration() const;
initial.commitd7cae122008-07-26 21:49:38245
[email protected]84b57952011-10-15 23:52:45246 // Accumulate metrics from other into this. This method is never used on
247 // realtime statistics, and only used in snapshots and aggregatinos.
initial.commitd7cae122008-07-26 21:49:38248 void AddDeathData(const DeathData& other);
249
[email protected]84baeca2011-10-24 18:55:16250 // Simple print of internal state for use in line of HTML.
251 void WriteHTML(std::string* output) const;
252
[email protected]6b26b96012011-10-28 21:41:50253 // Constructe a DictionaryValue instance containing all our stats. The caller
[email protected]84baeca2011-10-24 18:55:16254 // assumes ownership of the returned instance.
255 base::DictionaryValue* ToValue() const;
initial.commitd7cae122008-07-26 21:49:38256
[email protected]84b57952011-10-15 23:52:45257 // Reset all tallies to zero. This is used as a hack on realtime data.
initial.commitd7cae122008-07-26 21:49:38258 void Clear();
259
260 private:
[email protected]84b57952011-10-15 23:52:45261 int count_; // Number of destructions.
[email protected]6b26b96012011-10-28 21:41:50262 base::TimeDelta run_duration_; // Sum of all Run()time durations.
263 base::TimeDelta queue_duration_; // Sum of all queue time durations.
initial.commitd7cae122008-07-26 21:49:38264};
265
266//------------------------------------------------------------------------------
267// A temporary collection of data that can be sorted and summarized. It is
268// gathered (carefully) from many threads. Instances are held in arrays and
269// processed, filtered, and rendered.
270// The source of this data was collected on many threads, and is asynchronously
271// changing. The data in this instance is not asynchronously changing.
272
[email protected]0bea7252011-08-05 15:34:00273class BASE_EXPORT Snapshot {
initial.commitd7cae122008-07-26 21:49:38274 public:
275 // When snapshotting a full life cycle set (birth-to-death), use this:
276 Snapshot(const BirthOnThread& birth_on_thread, const ThreadData& death_thread,
277 const DeathData& death_data);
278
279 // When snapshotting a birth, with no death yet, use this:
280 Snapshot(const BirthOnThread& birth_on_thread, int count);
281
initial.commitd7cae122008-07-26 21:49:38282 const ThreadData* birth_thread() const { return birth_->birth_thread(); }
283 const Location location() const { return birth_->location(); }
284 const BirthOnThread& birth() const { return *birth_; }
285 const ThreadData* death_thread() const {return death_thread_; }
286 const DeathData& death_data() const { return death_data_; }
287 const std::string DeathThreadName() const;
288
289 int count() const { return death_data_.count(); }
[email protected]6b26b96012011-10-28 21:41:50290 base::TimeDelta run_duration() const { return death_data_.run_duration(); }
[email protected]84b57952011-10-15 23:52:45291 int AverageMsRunDuration() const {
292 return death_data_.AverageMsRunDuration();
293 }
[email protected]6b26b96012011-10-28 21:41:50294 base::TimeDelta queue_duration() const {
295 return death_data_.queue_duration();
296 }
[email protected]84b57952011-10-15 23:52:45297 int AverageMsQueueDuration() const {
298 return death_data_.AverageMsQueueDuration();
299 }
initial.commitd7cae122008-07-26 21:49:38300
[email protected]84baeca2011-10-24 18:55:16301 // Emit contents for use in a line of HTML
302 void WriteHTML(std::string* output) const;
303
304 // Construct a DictionaryValue instance containing all our data recursively.
305 // The caller assumes ownership of the memory in the returned instance.
306 base::DictionaryValue* ToValue() const;
initial.commitd7cae122008-07-26 21:49:38307
[email protected]6b26b96012011-10-28 21:41:50308 void Add(const Snapshot& other);
309
initial.commitd7cae122008-07-26 21:49:38310 private:
311 const BirthOnThread* birth_; // Includes Location and birth_thread.
312 const ThreadData* death_thread_;
313 DeathData death_data_;
314};
[email protected]84b57952011-10-15 23:52:45315
initial.commitd7cae122008-07-26 21:49:38316//------------------------------------------------------------------------------
317// DataCollector is a container class for Snapshot and BirthOnThread count
[email protected]84b57952011-10-15 23:52:45318// items.
initial.commitd7cae122008-07-26 21:49:38319
[email protected]0bea7252011-08-05 15:34:00320class BASE_EXPORT DataCollector {
initial.commitd7cae122008-07-26 21:49:38321 public:
[email protected]764be58b2008-08-08 20:03:42322 typedef std::vector<Snapshot> Collection;
initial.commitd7cae122008-07-26 21:49:38323
324 // Construct with a list of how many threads should contribute. This helps us
325 // determine (in the async case) when we are done with all contributions.
326 DataCollector();
[email protected]d4799a32010-09-28 22:54:58327 ~DataCollector();
initial.commitd7cae122008-07-26 21:49:38328
[email protected]6b26b96012011-10-28 21:41:50329 // Add all stats from the indicated thread into our arrays. This function is
330 // mutex protected, and *could* be called from any threads (although current
331 // implementation serialized calls to Append).
initial.commitd7cae122008-07-26 21:49:38332 void Append(const ThreadData& thread_data);
333
[email protected]75b79202009-12-30 07:31:45334 // After the accumulation phase, the following accessor is used to process the
[email protected]6b26b96012011-10-28 21:41:50335 // data.
initial.commitd7cae122008-07-26 21:49:38336 Collection* collection();
337
[email protected]6b26b96012011-10-28 21:41:50338 // After collection of death data is complete, we can add entries for all the
339 // remaining living objects.
initial.commitd7cae122008-07-26 21:49:38340 void AddListOfLivingObjects();
341
[email protected]6b26b96012011-10-28 21:41:50342 // Generate a ListValue representation of the vector of snapshots. The caller
[email protected]84baeca2011-10-24 18:55:16343 // assumes ownership of the memory in the returned instance.
344 base::ListValue* ToValue() const;
345
initial.commitd7cae122008-07-26 21:49:38346 private:
[email protected]a502bbe72011-01-07 18:06:45347 typedef std::map<const BirthOnThread*, int> BirthCount;
348
initial.commitd7cae122008-07-26 21:49:38349 // The array that we collect data into.
350 Collection collection_;
351
352 // The total number of births recorded at each location for which we have not
[email protected]6b26b96012011-10-28 21:41:50353 // seen a death count.
initial.commitd7cae122008-07-26 21:49:38354 BirthCount global_birth_count_;
355
[email protected]022614ef92008-12-30 20:50:01356 DISALLOW_COPY_AND_ASSIGN(DataCollector);
initial.commitd7cae122008-07-26 21:49:38357};
358
359//------------------------------------------------------------------------------
360// Aggregation contains summaries (totals and subtotals) of groups of Snapshot
361// instances to provide printing of these collections on a single line.
362
[email protected]0bea7252011-08-05 15:34:00363class BASE_EXPORT Aggregation: public DeathData {
initial.commitd7cae122008-07-26 21:49:38364 public:
[email protected]d4799a32010-09-28 22:54:58365 Aggregation();
366 ~Aggregation();
initial.commitd7cae122008-07-26 21:49:38367
368 void AddDeathSnapshot(const Snapshot& snapshot);
369 void AddBirths(const Births& births);
370 void AddBirth(const BirthOnThread& birth);
371 void AddBirthPlace(const Location& location);
[email protected]84baeca2011-10-24 18:55:16372 void WriteHTML(std::string* output) const;
initial.commitd7cae122008-07-26 21:49:38373 void Clear();
374
375 private:
376 int birth_count_;
377 std::map<std::string, int> birth_files_;
378 std::map<Location, int> locations_;
379 std::map<const ThreadData*, int> birth_threads_;
380 DeathData death_data_;
381 std::map<const ThreadData*, int> death_threads_;
382
[email protected]022614ef92008-12-30 20:50:01383 DISALLOW_COPY_AND_ASSIGN(Aggregation);
initial.commitd7cae122008-07-26 21:49:38384};
385
386//------------------------------------------------------------------------------
[email protected]75b79202009-12-30 07:31:45387// Comparator is a class that supports the comparison of Snapshot instances.
388// An instance is actually a list of chained Comparitors, that can provide for
[email protected]ca1863672011-10-07 18:26:02389// arbitrary ordering. The path portion of an about:tracking URL is translated
[email protected]75b79202009-12-30 07:31:45390// into such a chain, which is then used to order Snapshot instances in a
391// vector. It orders them into groups (for aggregation), and can also order
392// instances within the groups (for detailed rendering of the instances in an
393// aggregation).
initial.commitd7cae122008-07-26 21:49:38394
[email protected]0bea7252011-08-05 15:34:00395class BASE_EXPORT Comparator {
initial.commitd7cae122008-07-26 21:49:38396 public:
[email protected]75b79202009-12-30 07:31:45397 // Selector enum is the token identifier for each parsed keyword, most of
398 // which specify a sort order.
399 // Since it is not meaningful to sort more than once on a specific key, we
400 // use bitfields to accumulate what we have sorted on so far.
initial.commitd7cae122008-07-26 21:49:38401 enum Selector {
[email protected]75b79202009-12-30 07:31:45402 // Sort orders.
initial.commitd7cae122008-07-26 21:49:38403 NIL = 0,
404 BIRTH_THREAD = 1,
405 DEATH_THREAD = 2,
406 BIRTH_FILE = 4,
407 BIRTH_FUNCTION = 8,
408 BIRTH_LINE = 16,
409 COUNT = 32,
[email protected]84b57952011-10-15 23:52:45410 AVERAGE_RUN_DURATION = 64,
411 TOTAL_RUN_DURATION = 128,
412 AVERAGE_QUEUE_DURATION = 256,
413 TOTAL_QUEUE_DURATION = 512,
[email protected]75b79202009-12-30 07:31:45414
415 // Imediate action keywords.
416 RESET_ALL_DATA = -1,
initial.commitd7cae122008-07-26 21:49:38417 };
418
419 explicit Comparator();
420
[email protected]75b79202009-12-30 07:31:45421 // Reset the comparator to a NIL selector. Clear() and recursively delete any
initial.commitd7cae122008-07-26 21:49:38422 // tiebreaker_ entries. NOTE: We can't use a standard destructor, because
423 // the sort algorithm makes copies of this object, and then deletes them,
424 // which would cause problems (either we'd make expensive deep copies, or we'd
425 // do more thna one delete on a tiebreaker_.
426 void Clear();
427
428 // The less() operator for sorting the array via std::sort().
429 bool operator()(const Snapshot& left, const Snapshot& right) const;
430
431 void Sort(DataCollector::Collection* collection) const;
432
433 // Check to see if the items are sort equivalents (should be aggregated).
434 bool Equivalent(const Snapshot& left, const Snapshot& right) const;
435
436 // Check to see if all required fields are present in the given sample.
437 bool Acceptable(const Snapshot& sample) const;
438
439 // A comparator can be refined by specifying what to do if the selected basis
440 // for comparison is insufficient to establish an ordering. This call adds
441 // the indicated attribute as the new "least significant" basis of comparison.
[email protected]2bce0352009-07-06 20:11:00442 void SetTiebreaker(Selector selector, const std::string& required);
initial.commitd7cae122008-07-26 21:49:38443
444 // Indicate if this instance is set up to sort by the given Selector, thereby
445 // putting that information in the SortGrouping, so it is not needed in each
446 // printed line.
447 bool IsGroupedBy(Selector selector) const;
448
[email protected]84b57952011-10-15 23:52:45449 // Using the tiebreakers as set above, we mostly get an ordering, with some
initial.commitd7cae122008-07-26 21:49:38450 // equivalent groups. If those groups are displayed (rather than just being
451 // aggregated, then the following is used to order them (within the group).
452 void SetSubgroupTiebreaker(Selector selector);
453
454 // Translate a keyword and restriction in URL path to a selector for sorting.
[email protected]2bce0352009-07-06 20:11:00455 void ParseKeyphrase(const std::string& key_phrase);
initial.commitd7cae122008-07-26 21:49:38456
[email protected]be843e22011-06-28 17:35:18457 // Parse a query to decide on sort ordering.
[email protected]2bce0352009-07-06 20:11:00458 bool ParseQuery(const std::string& query);
initial.commitd7cae122008-07-26 21:49:38459
460 // Output a header line that can be used to indicated what items will be
461 // collected in the group. It lists all (potentially) tested attributes and
462 // their values (in the sample item).
463 bool WriteSortGrouping(const Snapshot& sample, std::string* output) const;
464
465 // Output a sample, with SortGroup details not displayed.
[email protected]84baeca2011-10-24 18:55:16466 void WriteSnapshotHTML(const Snapshot& sample, std::string* output) const;
initial.commitd7cae122008-07-26 21:49:38467
468 private:
469 // The selector directs this instance to compare based on the specified
470 // members of the tested elements.
471 enum Selector selector_;
472
473 // For filtering into acceptable and unacceptable snapshot instance, the
474 // following is required to be a substring of the selector_ field.
475 std::string required_;
476
477 // If this instance can't decide on an ordering, we can consult a tie-breaker
478 // which may have a different basis of comparison.
479 Comparator* tiebreaker_;
480
481 // We or together all the selectors we sort on (not counting sub-group
482 // selectors), so that we can tell if we've decided to group on any given
483 // criteria.
484 int combined_selectors_;
485
486 // Some tiebreakrs are for subgroup ordering, and not for basic ordering (in
487 // preparation for aggregation). The subgroup tiebreakers are not consulted
488 // when deciding if two items are in equivalent groups. This flag tells us
489 // to ignore the tiebreaker when doing Equivalent() testing.
490 bool use_tiebreaker_for_sort_only_;
491};
492
initial.commitd7cae122008-07-26 21:49:38493//------------------------------------------------------------------------------
494// For each thread, we have a ThreadData that stores all tracking info generated
495// on this thread. This prevents the need for locking as data accumulates.
496
[email protected]0bea7252011-08-05 15:34:00497class BASE_EXPORT ThreadData {
initial.commitd7cae122008-07-26 21:49:38498 public:
499 typedef std::map<Location, Births*> BirthMap;
500 typedef std::map<const Births*, DeathData> DeathMap;
501
[email protected]84b57952011-10-15 23:52:45502 // Initialize the current thread context with a new instance of ThreadData.
[email protected]6b26b96012011-10-28 21:41:50503 // This is used by all threads that have names, and can be explicitly
504 // set *before* any births are threads have taken place. It is generally
505 // only used by the message loop, which has a well defined name.
[email protected]84b57952011-10-15 23:52:45506 static void InitializeThreadContext(const std::string& suggested_name);
initial.commitd7cae122008-07-26 21:49:38507
508 // Using Thread Local Store, find the current instance for collecting data.
509 // If an instance does not exist, construct one (and remember it for use on
510 // this thread.
[email protected]84baeca2011-10-24 18:55:16511 // This may return NULL if the system is disabled for any reason.
[email protected]84b57952011-10-15 23:52:45512 static ThreadData* Get();
initial.commitd7cae122008-07-26 21:49:38513
[email protected]ca1863672011-10-07 18:26:02514 // For a given (unescaped) about:tracking query, develop resulting HTML, and
[email protected]be843e22011-06-28 17:35:18515 // append to output.
initial.commitd7cae122008-07-26 21:49:38516 static void WriteHTML(const std::string& query, std::string* output);
517
[email protected]6b26b96012011-10-28 21:41:50518 // Constructe a ListValue instance containing all recursive results in our
519 // process. The caller assumes ownership of the memory in the returned
520 // instance. The |process_type| should become an enum, which corresponds
521 // to all possible process types. I'm using an int as a placeholder.
522 static base::Value* ToValue(int process_type);
523
initial.commitd7cae122008-07-26 21:49:38524 // For a given accumulated array of results, use the comparator to sort and
525 // subtotal, writing the results to the output.
526 static void WriteHTMLTotalAndSubtotals(
527 const DataCollector::Collection& match_array,
528 const Comparator& comparator, std::string* output);
529
[email protected]6b26b96012011-10-28 21:41:50530 // Find (or create) a place to count births from the given location in this
[email protected]84baeca2011-10-24 18:55:16531 // thread, and increment that tally.
[email protected]180c85e2011-07-26 18:25:16532 // TallyABirthIfActive will returns NULL if the birth cannot be tallied.
533 static Births* TallyABirthIfActive(const Location& location);
[email protected]84b57952011-10-15 23:52:45534
[email protected]6b26b96012011-10-28 21:41:50535 // Record the end of a timed run of an object. The |birth| is the record for
[email protected]84baeca2011-10-24 18:55:16536 // the instance, the |time_posted| and |start_of_run| are times of posting
[email protected]84b57952011-10-15 23:52:45537 // into a message loop queue, and of starting to perform the run of the task.
[email protected]84baeca2011-10-24 18:55:16538 // The |end_of_run| was just obtained by a call to Now() (just after the task
539 // finished).
[email protected]6b26b96012011-10-28 21:41:50540 static void TallyADeathIfActive(const Births* birth,
541 const base::TimeTicks& time_posted,
542 const base::TimeTicks& delayed_start_time,
543 const base::TimeTicks& start_of_run,
544 const base::TimeTicks& end_of_run);
initial.commitd7cae122008-07-26 21:49:38545
[email protected]84b57952011-10-15 23:52:45546 const std::string thread_name() const { return thread_name_; }
initial.commitd7cae122008-07-26 21:49:38547
[email protected]84baeca2011-10-24 18:55:16548 // ---------------------
549 // The following functions should all be private, and are only public because
550 // the collection is done externally. We need to relocate that code from the
551 // collection class into this class, and then all these methods can be made
552 // private.
553 // (Thread safe) Get start of list of all ThreadData instances.
554 static ThreadData* first();
555 // Iterate through the null terminated list of ThreadData instances.
556 ThreadData* next() const { return next_; }
initial.commitd7cae122008-07-26 21:49:38557 // Using our lock, make a copy of the specified maps. These calls may arrive
[email protected]75b79202009-12-30 07:31:45558 // from non-local threads, and are used to quickly scan data from all threads
[email protected]ca1863672011-10-07 18:26:02559 // in order to build an HTML page for about:tracking.
initial.commitd7cae122008-07-26 21:49:38560 void SnapshotBirthMap(BirthMap *output) const;
561 void SnapshotDeathMap(DeathMap *output) const;
[email protected]84baeca2011-10-24 18:55:16562 // -------- end of should be private methods.
initial.commitd7cae122008-07-26 21:49:38563
[email protected]75b79202009-12-30 07:31:45564 // Hack: asynchronously clear all birth counts and death tallies data values
565 // in all ThreadData instances. The numerical (zeroing) part is done without
566 // use of a locks or atomics exchanges, and may (for int64 values) produce
567 // bogus counts VERY rarely.
568 static void ResetAllThreadData();
569
[email protected]6b26b96012011-10-28 21:41:50570 // Set internal status_ to either become ACTIVE, or later, to be SHUTDOWN,
initial.commitd7cae122008-07-26 21:49:38571 // based on argument being true or false respectively.
[email protected]6b26b96012011-10-28 21:41:50572 // IF tracking is not compiled in, this function will return false.
573 static bool StartTracking(bool status);
574 static bool IsActive();
initial.commitd7cae122008-07-26 21:49:38575
[email protected]84b57952011-10-15 23:52:45576 // Provide a time function that does nothing (runs fast) when we don't have
577 // the profiler enabled. It will generally be optimized away when it is
578 // ifdef'ed to be small enough (allowing the profiler to be "compiled out" of
579 // the code).
[email protected]6b26b96012011-10-28 21:41:50580 static base::TimeTicks Now();
initial.commitd7cae122008-07-26 21:49:38581
582 // WARNING: ONLY call this function when you are running single threaded
583 // (again) and all message loops and threads have terminated. Until that
584 // point some threads may still attempt to write into our data structures.
585 // Delete recursively all data structures, starting with the list of
586 // ThreadData instances.
587 static void ShutdownSingleThreadedCleanup();
588
589 private:
[email protected]6b26b96012011-10-28 21:41:50590 // Current allowable states of the tracking system. The states always
591 // proceed towards SHUTDOWN, and never go backwards.
592 enum Status {
593 UNINITIALIZED,
594 ACTIVE,
595 SHUTDOWN,
596 };
597
[email protected]84baeca2011-10-24 18:55:16598 typedef std::stack<const ThreadData*> ThreadDataPool;
599
600 // Worker thread construction creates a name since there is none.
601 ThreadData();
602 // Message loop based construction should provide a name.
603 explicit ThreadData(const std::string& suggested_name);
604
605 ~ThreadData();
606
607 // Push this instance to the head of all_thread_data_list_head_, linking it to
608 // the previous head. This is performed after each construction, and leaves
609 // the instance permanently on that list.
610 void PushToHeadOfList();
611
612 // In this thread's data, record a new birth.
613 Births* TallyABirth(const Location& location);
614
615 // Find a place to record a death on this thread.
616 void TallyADeath(const Births& birth,
[email protected]6b26b96012011-10-28 21:41:50617 const base::TimeDelta& queue_duration,
618 const base::TimeDelta& duration);
[email protected]84baeca2011-10-24 18:55:16619
620 // Using our lock to protect the iteration, Clear all birth and death data.
621 void Reset();
622
623 // This method is called by the TLS system when a thread terminates.
624 // The argument may be NULL if this thread has never tracked a birth or death.
625 static void OnThreadTermination(void* thread_data);
626
627 // This method should be called when a worker thread terminates, so that we
628 // can save all the thread data into a cache of reusable ThreadData instances.
629 void OnThreadTerminationCleanup() const;
630
initial.commitd7cae122008-07-26 21:49:38631 // We use thread local store to identify which ThreadData to interact with.
[email protected]1357c322010-12-30 22:18:56632 static base::ThreadLocalStorage::Slot tls_index_;
initial.commitd7cae122008-07-26 21:49:38633
634 // Link to the most recently created instance (starts a null terminated list).
[email protected]84baeca2011-10-24 18:55:16635 // The list is traversed by about:tracking when it needs to snapshot data.
636 static ThreadData* all_thread_data_list_head_;
637 // Set of ThreadData instances for use with worker threads. When a worker
638 // thread is done (terminating), we push it into this pool. When a new worker
639 // thread is created, we first try to re-use a ThreadData instance from the
640 // pool, and if none are available, construct a new one.
641 static ThreadDataPool* unregistered_thread_data_pool_;
642 // Protection for access to all_thread_data_list_head_, and to
[email protected]6b26b96012011-10-28 21:41:50643 // unregistered_thread_data_pool_.
644 static base::Lock list_lock_;
initial.commitd7cae122008-07-26 21:49:38645
[email protected]84b57952011-10-15 23:52:45646 // We set status_ to SHUTDOWN when we shut down the tracking service.
initial.commitd7cae122008-07-26 21:49:38647 static Status status_;
648
649 // Link to next instance (null terminated list). Used to globally track all
650 // registered instances (corresponds to all registered threads where we keep
651 // data).
652 ThreadData* next_;
653
[email protected]84b57952011-10-15 23:52:45654 // The name of the thread that is being recorded. If this thread has no
655 // message_loop, then this is a worker thread, with a sequence number postfix.
656 std::string thread_name_;
initial.commitd7cae122008-07-26 21:49:38657
[email protected]84baeca2011-10-24 18:55:16658 // Indicate if this is a worker thread, and the ThreadData contexts should be
659 // stored in the unregistered_thread_data_pool_ when not in use.
660 bool is_a_worker_thread_;
661
initial.commitd7cae122008-07-26 21:49:38662 // A map used on each thread to keep track of Births on this thread.
663 // This map should only be accessed on the thread it was constructed on.
664 // When a snapshot is needed, this structure can be locked in place for the
665 // duration of the snapshotting activity.
666 BirthMap birth_map_;
667
668 // Similar to birth_map_, this records informations about death of tracked
669 // instances (i.e., when a tracked instance was destroyed on this thread).
[email protected]75b79202009-12-30 07:31:45670 // It is locked before changing, and hence other threads may access it by
671 // locking before reading it.
initial.commitd7cae122008-07-26 21:49:38672 DeathMap death_map_;
673
[email protected]75b79202009-12-30 07:31:45674 // Lock to protect *some* access to BirthMap and DeathMap. The maps are
675 // regularly read and written on this thread, but may only be read from other
676 // threads. To support this, we acquire this lock if we are writing from this
677 // thread, or reading from another thread. For reading from this thread we
678 // don't need a lock, as there is no potential for a conflict since the
679 // writing is only done from this thread.
[email protected]20305ec2011-01-21 04:55:52680 mutable base::Lock lock_;
initial.commitd7cae122008-07-26 21:49:38681
[email protected]84b57952011-10-15 23:52:45682 // The next available thread number. This should only be accessed when the
683 // list_lock_ is held.
[email protected]84baeca2011-10-24 18:55:16684 static int thread_number_counter_;
[email protected]84b57952011-10-15 23:52:45685
[email protected]022614ef92008-12-30 20:50:01686 DISALLOW_COPY_AND_ASSIGN(ThreadData);
initial.commitd7cae122008-07-26 21:49:38687};
688
[email protected]022614ef92008-12-30 20:50:01689//------------------------------------------------------------------------------
690// Provide simple way to to start global tracking, and to tear down tracking
[email protected]84baeca2011-10-24 18:55:16691// when done. The design has evolved to *not* do any teardown (and just leak
692// all allocated data structures). As a result, we don't have any code in this
693// destructor, and perhaps this whole class should go away.
[email protected]862aa2f02009-12-31 07:26:16694
[email protected]0bea7252011-08-05 15:34:00695class BASE_EXPORT AutoTracking {
[email protected]022614ef92008-12-30 20:50:01696 public:
[email protected]862aa2f02009-12-31 07:26:16697 AutoTracking() {
[email protected]6b26b96012011-10-28 21:41:50698 if (state_ != kNeverBeenRun)
699 return;
700 ThreadData::StartTracking(true);
701 state_ = kRunning;
[email protected]862aa2f02009-12-31 07:26:16702 }
[email protected]022614ef92008-12-30 20:50:01703
704 ~AutoTracking() {
[email protected]022614ef92008-12-30 20:50:01705 }
706
707 private:
[email protected]6b26b96012011-10-28 21:41:50708 enum State {
709 kNeverBeenRun,
710 kRunning,
711 };
712 static State state_;
[email protected]862aa2f02009-12-31 07:26:16713
[email protected]022614ef92008-12-30 20:50:01714 DISALLOW_COPY_AND_ASSIGN(AutoTracking);
715};
716
initial.commitd7cae122008-07-26 21:49:38717} // namespace tracked_objects
718
719#endif // BASE_TRACKED_OBJECTS_H_