Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(73)

Side by Side Diff: base/tracked_objects.cc

Issue 8233037: Update task tracking to not depend on message_loop_ singleton (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 9 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « base/tracked_objects.h ('k') | base/tracked_objects_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/tracked_objects.h" 5 #include "base/tracked_objects.h"
6 6
7 #include <math.h> 7 #include <math.h>
8 8
9 #include "base/format_macros.h" 9 #include "base/format_macros.h"
10 #include "base/message_loop.h" 10 #include "base/message_loop.h"
11 #include "base/string_util.h" 11 #include "base/string_util.h"
12 #include "base/stringprintf.h" 12 #include "base/stringprintf.h"
13 #include "base/threading/thread_restrictions.h" 13 #include "base/threading/thread_restrictions.h"
14 14
15 using base::TimeDelta; 15 using base::TimeDelta;
16 16
17 namespace tracked_objects { 17 namespace tracked_objects {
18 18
19 // A TLS slot to the TrackRegistry for the current thread. 19 // A TLS slot to the TrackRegistry for the current thread.
20 // static 20 // static
21 base::ThreadLocalStorage::Slot ThreadData::tls_index_(base::LINKER_INITIALIZED); 21 base::ThreadLocalStorage::Slot ThreadData::tls_index_(base::LINKER_INITIALIZED);
22 22
23 // A global state variable to prevent repeated initialization during tests. 23 // A global state variable to prevent repeated initialization during tests.
24 // static 24 // static
25 AutoTracking::State AutoTracking::state_ = AutoTracking::kNeverBeenRun; 25 AutoTracking::State AutoTracking::state_ = AutoTracking::kNeverBeenRun;
26 26
27 // A locked protected counter to assign sequence number to threads.
28 // static
29 int ThreadData::thread_number_counter = 0;
30
27 //------------------------------------------------------------------------------ 31 //------------------------------------------------------------------------------
28 // Death data tallies durations when a death takes place. 32 // Death data tallies durations when a death takes place.
29 33
30 void DeathData::RecordDeath(const TimeDelta& duration) { 34 void DeathData::RecordDeath(const TimeDelta& queue_duration,
35 const TimeDelta& run_duration) {
31 ++count_; 36 ++count_;
32 life_duration_ += duration; 37 queue_duration_ += queue_duration;
33 int64 milliseconds = duration.InMilliseconds(); 38 run_duration_ += run_duration;
34 square_duration_ += milliseconds * milliseconds;
35 } 39 }
36 40
37 int DeathData::AverageMsDuration() const { 41 int DeathData::AverageMsRunDuration() const {
38 return static_cast<int>(life_duration_.InMilliseconds() / count_); 42 return static_cast<int>(run_duration_.InMilliseconds() / count_);
39 } 43 }
40 44
41 double DeathData::StandardDeviation() const { 45 int DeathData::AverageMsQueueDuration() const {
42 double average = AverageMsDuration(); 46 return static_cast<int>(queue_duration_.InMilliseconds() / count_);
43 double variance = static_cast<float>(square_duration_)/count_
44 - average * average;
45 return sqrt(variance);
46 } 47 }
47 48
48
49 void DeathData::AddDeathData(const DeathData& other) { 49 void DeathData::AddDeathData(const DeathData& other) {
50 count_ += other.count_; 50 count_ += other.count_;
51 life_duration_ += other.life_duration_; 51 queue_duration_ += other.queue_duration_;
52 square_duration_ += other.square_duration_; 52 run_duration_ += other.run_duration_;
53 } 53 }
54 54
55 void DeathData::Write(std::string* output) const { 55 void DeathData::Write(std::string* output) const {
56 if (!count_) 56 if (!count_)
57 return; 57 return;
58 if (1 == count_) { 58 base::StringAppendF(output, "%s:%d, ",
59 base::StringAppendF(output, "(1)Life in %dms ", AverageMsDuration()); 59 (count_ == 1) ? "Life" : "Lives", count_);
60 } else { 60 base::StringAppendF(output, "Run:%"PRId64"ms(%dms/life) ",
61 base::StringAppendF(output, "(%d)Lives %dms/life ", 61 run_duration_.InMilliseconds(),
62 count_, AverageMsDuration()); 62 AverageMsRunDuration());
63 } 63 base::StringAppendF(output, "Queue:%"PRId64"ms(%dms/life) ",
64 queue_duration_.InMilliseconds(),
65 AverageMsQueueDuration());
64 } 66 }
65 67
66 void DeathData::Clear() { 68 void DeathData::Clear() {
67 count_ = 0; 69 count_ = 0;
68 life_duration_ = TimeDelta(); 70 queue_duration_ = TimeDelta();
69 square_duration_ = 0; 71 run_duration_ = TimeDelta();
70 } 72 }
71 73
72 //------------------------------------------------------------------------------ 74 //------------------------------------------------------------------------------
73 BirthOnThread::BirthOnThread(const Location& location) 75 BirthOnThread::BirthOnThread(const Location& location)
74 : location_(location), 76 : location_(location),
75 birth_thread_(ThreadData::current()) { } 77 birth_thread_(ThreadData::Get()) { }
76 78
77 //------------------------------------------------------------------------------ 79 //------------------------------------------------------------------------------
78 Births::Births(const Location& location) 80 Births::Births(const Location& location)
79 : BirthOnThread(location), 81 : BirthOnThread(location),
80 birth_count_(1) { } 82 birth_count_(1) { }
81 83
82 //------------------------------------------------------------------------------ 84 //------------------------------------------------------------------------------
83 // ThreadData maintains the central data for all births and death. 85 // ThreadData maintains the central data for all births and death.
84 86
85 // static 87 // static
86 ThreadData* ThreadData::first_ = NULL; 88 ThreadData* ThreadData::first_ = NULL;
87 // static 89 // static
88 base::Lock ThreadData::list_lock_; 90 base::Lock ThreadData::list_lock_;
89 91
90 // static 92 // static
91 ThreadData::Status ThreadData::status_ = ThreadData::UNINITIALIZED; 93 ThreadData::Status ThreadData::status_ = ThreadData::UNINITIALIZED;
92 94
95 ThreadData::ThreadData(const std::string& suggested_name) : next_(NULL) {
96 DCHECK_GE(suggested_name.size(), 0u);
97 thread_name_ = suggested_name;
98 }
99
93 ThreadData::ThreadData() : next_(NULL) { 100 ThreadData::ThreadData() : next_(NULL) {
94 // This shouldn't use the MessageLoop::current() LazyInstance since this might 101 int thread_number;
95 // be used on a non-joinable thread. 102 {
96 // http://crbug.com/62728 103 base::AutoLock lock(list_lock_);
97 base::ThreadRestrictions::ScopedAllowSingleton scoped_allow_singleton; 104 thread_number = ++thread_number_counter;
98 message_loop_ = MessageLoop::current(); 105 }
106 base::StringAppendF(&thread_name_, "WorkerThread-%d", thread_number);
99 } 107 }
100 108
101 ThreadData::~ThreadData() {} 109 ThreadData::~ThreadData() {}
102 110
103 // static 111 // static
104 ThreadData* ThreadData::current() { 112 void ThreadData::InitializeThreadContext(const std::string& suggested_name) {
105 if (!tls_index_.initialized()) 113 if (!tls_index_.initialized())
106 return NULL; 114 return; // For unittests only.
107 115 RegisterCurrentContext(new ThreadData(suggested_name));
108 ThreadData* registry = static_cast<ThreadData*>(tls_index_.Get());
109 if (!registry) {
110 // We have to create a new registry for ThreadData.
111 bool too_late_to_create = false;
112 {
113 registry = new ThreadData;
114 base::AutoLock lock(list_lock_);
115 // Use lock to insure we have most recent status.
116 if (!IsActive()) {
117 too_late_to_create = true;
118 } else {
119 // Use lock to insert into list.
120 registry->next_ = first_;
121 first_ = registry;
122 }
123 } // Release lock.
124 if (too_late_to_create) {
125 delete registry;
126 registry = NULL;
127 } else {
128 tls_index_.Set(registry);
129 }
130 }
131 return registry;
132 } 116 }
133 117
134 // static 118 // static
119 ThreadData* ThreadData::Get() {
120 if (!tls_index_.initialized())
121 return NULL; // For unittests only.
122 ThreadData* registered = static_cast<ThreadData*>(tls_index_.Get());
123 if (!registered) {
124 // We have to create a new registry entry for this ThreadData.
125 // TODO(jar): Host all unamed (Worker) threads in *one* ThreadData instance,
126 // (with locking protection on that instance) or else recycle and re-use
127 // worker thread ThreadData when the worker thread terminates.
128 registered = RegisterCurrentContext(new ThreadData());
129 }
130 return registered;
131 }
132
133 // static
134 ThreadData* ThreadData::RegisterCurrentContext(ThreadData* unregistered) {
135 DCHECK_EQ(tls_index_.Get(), static_cast<void*>(0));
136 bool too_late_to_register = false;
137 {
138 base::AutoLock lock(list_lock_);
139 // Use lock to insure we have most recent status.
140 if (!IsActive()) {
141 too_late_to_register = true;
142 } else {
143 // Use list_lock_ to insert as new head of list.
144 unregistered->next_ = first_;
145 first_ = unregistered;
146 }
147 } // Release lock.
148 if (too_late_to_register) {
149 delete unregistered;
150 unregistered = NULL;
151 } else {
152 tls_index_.Set(unregistered);
153 }
154 return unregistered;
155 }
156
157 // static
135 void ThreadData::WriteHTML(const std::string& query, std::string* output) { 158 void ThreadData::WriteHTML(const std::string& query, std::string* output) {
136 if (!ThreadData::IsActive()) 159 if (!ThreadData::IsActive())
137 return; // Not yet initialized. 160 return; // Not yet initialized.
138 161
139 DCHECK(ThreadData::current());
140 DataCollector collected_data; // Gather data. 162 DataCollector collected_data; // Gather data.
141 collected_data.AddListOfLivingObjects(); // Add births that are still alive. 163 collected_data.AddListOfLivingObjects(); // Add births that are still alive.
142 164
143 // Data Gathering is complete. Now to sort/process/render. 165 // Data Gathering is complete. Now to sort/process/render.
144 DataCollector::Collection* collection = collected_data.collection(); 166 DataCollector::Collection* collection = collected_data.collection();
145 167
146 // Create filtering and sort comparison object. 168 // Create filtering and sort comparison object.
147 Comparator comparator; 169 Comparator comparator;
148 comparator.ParseQuery(query); 170 comparator.ParseQuery(query);
149 171
150 // Filter out acceptable (matching) instances. 172 // Filter out acceptable (matching) instances.
151 DataCollector::Collection match_array; 173 DataCollector::Collection match_array;
152 for (DataCollector::Collection::iterator it = collection->begin(); 174 for (DataCollector::Collection::iterator it = collection->begin();
153 it != collection->end(); ++it) { 175 it != collection->end(); ++it) {
154 if (comparator.Acceptable(*it)) 176 if (comparator.Acceptable(*it))
155 match_array.push_back(*it); 177 match_array.push_back(*it);
156 } 178 }
157 179
158 comparator.Sort(&match_array); 180 comparator.Sort(&match_array);
159 181
160 WriteHTMLTotalAndSubtotals(match_array, comparator, output); 182 WriteHTMLTotalAndSubtotals(match_array, comparator, output);
161 183
162 comparator.Clear(); // Delete tiebreaker_ instances. 184 comparator.Clear(); // Delete tiebreaker_ instances.
163 185
164 output->append("</pre>"); 186 output->append("</pre>");
165 187
166 const char* help_string = "The following are the keywords that can be used to" 188 const char* help_string = "The following are the keywords that can be used to"
167 " sort and aggregate the data, or to select data.<br><ul>" 189 " sort and aggregate the data, or to select data.<br><ul>"
168 "<li><b>count</b> Number of instances seen." 190 "<li><b>Count</b> Number of instances seen."
169 "<li><b>duration</b> Duration in ms from construction to descrution." 191 "<li><b>Duration</b> Average duration in ms of Run() time."
170 "<li><b>birth</b> Thread on which the task was constructed." 192 "<li><b>TotalDuration</b> Summed durations in ms of Run() times."
171 "<li><b>death</b> Thread on which the task was run and deleted." 193 "<li><b>AverageQueueDuration</b> Average duration in ms of queueing time."
172 "<li><b>file</b> File in which the task was contructed." 194 "<li><b>TotalQueueDuration</b> Summed durations in ms of Run() times."
173 "<li><b>function</b> Function in which the task was constructed." 195 "<li><b>Birth</b> Thread on which the task was constructed."
174 "<li><b>line</b> Line number of the file in which the task was constructed." 196 "<li><b>Death</b> Thread on which the task was run and deleted."
197 "<li><b>File</b> File in which the task was contructed."
198 "<li><b>Function</b> Function in which the task was constructed."
199 "<li><b>Line</b> Line number of the file in which the task was constructed."
175 "</ul><br>" 200 "</ul><br>"
176 "As examples:<ul>" 201 "As examples:<ul>"
177 "<li><b>about:tracking/file</b> would sort the above data by file, and" 202 "<li><b>about:tracking/file</b> would sort the above data by file, and"
178 " aggregate data on a per-file basis." 203 " aggregate data on a per-file basis."
179 "<li><b>about:tracking/file=Dns</b> would only list data for tasks" 204 "<li><b>about:tracking/file=Dns</b> would only list data for tasks"
180 " constructed in a file containing the text |Dns|." 205 " constructed in a file containing the text |Dns|."
206 "<li><b>about:tracking/death/duration</b> would sort the data by death"
207 " thread(i.e., where tasks ran) and then by the average runtime for the"
208 " tasks. Form an aggregation group, one per thread, showing the results on"
209 " each thread."
181 "<li><b>about:tracking/birth/death</b> would sort the above list by birth" 210 "<li><b>about:tracking/birth/death</b> would sort the above list by birth"
182 " thread, and then by death thread, and would aggregate data for each pair" 211 " thread, and then by death thread, and would aggregate data for each pair"
183 " of lifetime events." 212 " of lifetime events."
184 "</ul>" 213 "</ul>"
185 " The data can be reset to zero (discarding all births, deaths, etc.) using" 214 " The data can be reset to zero (discarding all births, deaths, etc.) using"
186 " <b>about:tracking/reset</b>. The existing stats will be displayed, but" 215 " <b>about:tracking/reset</b>. The existing stats will be displayed, but"
187 " the internal stats will be set to zero, and start accumulating afresh." 216 " the internal stats will be set to zero, and start accumulating afresh."
188 " This option is very helpful if you only wish to consider tasks created" 217 " This option is very helpful if you only wish to consider tasks created"
189 " after some point in time.<br><br>" 218 " after some point in time.<br><br>"
190 "If you wish to monitor Renderer events, be sure to run in --single-process" 219 "If you wish to monitor Renderer events, be sure to run in --single-process"
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
227 output->append("<br>"); 256 output->append("<br>");
228 subtotals.Write(output); 257 subtotals.Write(output);
229 output->append("<br><hr><br>"); 258 output->append("<br><hr><br>");
230 subtotals.Clear(); 259 subtotals.Clear();
231 } 260 }
232 } 261 }
233 } 262 }
234 } 263 }
235 264
236 Births* ThreadData::TallyABirth(const Location& location) { 265 Births* ThreadData::TallyABirth(const Location& location) {
237 {
238 // This shouldn't use the MessageLoop::current() LazyInstance since this
239 // might be used on a non-joinable thread.
240 // http://crbug.com/62728
241 base::ThreadRestrictions::ScopedAllowSingleton scoped_allow_singleton;
242 if (!message_loop_) // In case message loop wasn't yet around...
243 message_loop_ = MessageLoop::current(); // Find it now.
244 }
245
246 BirthMap::iterator it = birth_map_.find(location); 266 BirthMap::iterator it = birth_map_.find(location);
247 if (it != birth_map_.end()) { 267 if (it != birth_map_.end()) {
248 it->second->RecordBirth(); 268 it->second->RecordBirth();
249 return it->second; 269 return it->second;
250 } 270 }
251 271
252 Births* tracker = new Births(location); 272 Births* tracker = new Births(location);
253 // Lock since the map may get relocated now, and other threads sometimes 273 // Lock since the map may get relocated now, and other threads sometimes
254 // snapshot it (but they lock before copying it). 274 // snapshot it (but they lock before copying it).
255 base::AutoLock lock(lock_); 275 base::AutoLock lock(lock_);
256 birth_map_[location] = tracker; 276 birth_map_[location] = tracker;
257 return tracker; 277 return tracker;
258 } 278 }
259 279
260 void ThreadData::TallyADeath(const Births& lifetimes, 280 void ThreadData::TallyADeath(const Births& the_birth,
261 const TimeDelta& duration) { 281 const TimeDelta& queue_duration,
262 { 282 const TimeDelta& run_duration) {
263 // http://crbug.com/62728 283 DeathMap::iterator it = death_map_.find(&the_birth);
264 base::ThreadRestrictions::ScopedAllowSingleton scoped_allow_singleton;
265 if (!message_loop_) // In case message loop wasn't yet around...
266 message_loop_ = MessageLoop::current(); // Find it now.
267 }
268
269 DeathMap::iterator it = death_map_.find(&lifetimes);
270 if (it != death_map_.end()) { 284 if (it != death_map_.end()) {
271 it->second.RecordDeath(duration); 285 it->second.RecordDeath(queue_duration, run_duration);
272 return; 286 return;
273 } 287 }
274 288
275 base::AutoLock lock(lock_); // Lock since the map may get relocated now. 289 base::AutoLock lock(lock_); // Lock since the map may get relocated now.
276 death_map_[&lifetimes].RecordDeath(duration); 290 death_map_[&the_birth].RecordDeath(queue_duration, run_duration);
277 } 291 }
278 292
279 // static 293 // static
280 Births* ThreadData::TallyABirthIfActive(const Location& location) { 294 Births* ThreadData::TallyABirthIfActive(const Location& location) {
281 if (IsActive()) { 295 #if !defined(TRACK_ALL_TASK_OBJECTS)
282 ThreadData* current_thread_data = current(); 296 return NULL; // Not compiled in.
283 if (current_thread_data) { 297 #else
284 return current_thread_data->TallyABirth(location); 298 if (!IsActive())
285 } 299 return NULL;
286 } 300 ThreadData* current_thread_data = Get();
287 301 if (!current_thread_data)
288 return NULL; 302 return NULL;
303 return current_thread_data->TallyABirth(location);
304 #endif
289 } 305 }
290 306
291 // static 307 // static
292 void ThreadData::TallyADeathIfActive(const Births* the_birth, 308 void ThreadData::TallyADeathIfActive(const Births* the_birth,
293 const base::TimeDelta& duration) { 309 const base::TimeTicks& time_posted,
294 if (IsActive() && the_birth) { 310 const base::TimeTicks& delayed_start_time,
295 current()->TallyADeath(*the_birth, duration); 311 const base::TimeTicks& start_of_run) {
296 } 312 #if !defined(TRACK_ALL_TASK_OBJECTS)
313 return; // Not compiled in.
314 #else
315 if (!IsActive() || !the_birth)
316 return;
317 ThreadData* current_thread_data = Get();
318 if (!current_thread_data)
319 return;
320
321 // To avoid conflating our stats with the delay duration in a PostDelayedTask,
322 // we identify such tasks, and replace their post_time with the time they
323 // were sechudled (requested?) to emerge from the delayed task queue. This
324 // means that queueing delay for such tasks will show how long they went
325 // unserviced, after they *could* be serviced. This is the same stat as we
326 // have for non-delayed tasks, and we consistently call it queueing delay.
327 base::TimeTicks effective_post_time =
328 (delayed_start_time.is_null()) ? time_posted : delayed_start_time;
329 base::TimeDelta queue_duration = start_of_run - effective_post_time;
330 base::TimeDelta run_duration = Now() - start_of_run;
331 current_thread_data->TallyADeath(*the_birth, queue_duration, run_duration);
332 #endif
297 } 333 }
298 334
299 // static 335 // static
300 ThreadData* ThreadData::first() { 336 ThreadData* ThreadData::first() {
301 base::AutoLock lock(list_lock_); 337 base::AutoLock lock(list_lock_);
302 return first_; 338 return first_;
303 } 339 }
304 340
305 const std::string ThreadData::ThreadName() const {
306 if (message_loop_)
307 return message_loop_->thread_name();
308 return "ThreadWithoutMessageLoop";
309 }
310
311 // This may be called from another thread. 341 // This may be called from another thread.
312 void ThreadData::SnapshotBirthMap(BirthMap *output) const { 342 void ThreadData::SnapshotBirthMap(BirthMap *output) const {
313 base::AutoLock lock(lock_); 343 base::AutoLock lock(lock_);
314 for (BirthMap::const_iterator it = birth_map_.begin(); 344 for (BirthMap::const_iterator it = birth_map_.begin();
315 it != birth_map_.end(); ++it) 345 it != birth_map_.end(); ++it)
316 (*output)[it->first] = it->second; 346 (*output)[it->first] = it->second;
317 } 347 }
318 348
319 // This may be called from another thread. 349 // This may be called from another thread.
320 void ThreadData::SnapshotDeathMap(DeathMap *output) const { 350 void ThreadData::SnapshotDeathMap(DeathMap *output) const {
321 base::AutoLock lock(lock_); 351 base::AutoLock lock(lock_);
322 for (DeathMap::const_iterator it = death_map_.begin(); 352 for (DeathMap::const_iterator it = death_map_.begin();
323 it != death_map_.end(); ++it) 353 it != death_map_.end(); ++it)
324 (*output)[it->first] = it->second; 354 (*output)[it->first] = it->second;
325 } 355 }
326 356
327 // static 357 // static
328 void ThreadData::ResetAllThreadData() { 358 void ThreadData::ResetAllThreadData() {
329 ThreadData* my_list = ThreadData::current()->first(); 359 ThreadData* my_list = Get()->first();
330 360
331 for (ThreadData* thread_data = my_list; 361 for (ThreadData* thread_data = my_list;
332 thread_data; 362 thread_data;
333 thread_data = thread_data->next()) 363 thread_data = thread_data->next())
334 thread_data->Reset(); 364 thread_data->Reset();
335 } 365 }
336 366
337 void ThreadData::Reset() { 367 void ThreadData::Reset() {
338 base::AutoLock lock(lock_); 368 base::AutoLock lock(lock_);
339 for (DeathMap::iterator it = death_map_.begin(); 369 for (DeathMap::iterator it = death_map_.begin();
340 it != death_map_.end(); ++it) 370 it != death_map_.end(); ++it)
341 it->second.Clear(); 371 it->second.Clear();
342 for (BirthMap::iterator it = birth_map_.begin(); 372 for (BirthMap::iterator it = birth_map_.begin();
343 it != birth_map_.end(); ++it) 373 it != birth_map_.end(); ++it)
344 it->second->Clear(); 374 it->second->Clear();
345 } 375 }
346 376
347 #ifdef OS_WIN
348 // A class used to count down which is accessed by several threads. This is
349 // used to make sure RunOnAllThreads() actually runs a task on the expected
350 // count of threads.
351 class ThreadData::ThreadSafeDownCounter {
352 public:
353 // Constructor sets the count, once and for all.
354 explicit ThreadSafeDownCounter(size_t count);
355
356 // Decrement the count, and return true if we hit zero. Also delete this
357 // instance automatically when we hit zero.
358 bool LastCaller();
359
360 private:
361 size_t remaining_count_;
362 base::Lock lock_; // protect access to remaining_count_.
363 };
364
365 ThreadData::ThreadSafeDownCounter::ThreadSafeDownCounter(size_t count)
366 : remaining_count_(count) {
367 DCHECK_GT(remaining_count_, 0u);
368 }
369
370 bool ThreadData::ThreadSafeDownCounter::LastCaller() {
371 {
372 base::AutoLock lock(lock_);
373 if (--remaining_count_)
374 return false;
375 } // Release lock, so we can delete everything in this instance.
376 delete this;
377 return true;
378 }
379
380 // A Task class that runs a static method supplied, and checks to see if this
381 // is the last tasks instance (on last thread) that will run the method.
382 // IF this is the last run, then the supplied event is signalled.
383 class ThreadData::RunTheStatic : public Task {
384 public:
385 typedef void (*FunctionPointer)();
386 RunTheStatic(FunctionPointer function,
387 HANDLE completion_handle,
388 ThreadSafeDownCounter* counter);
389 // Run the supplied static method, and optionally set the event.
390 void Run();
391
392 private:
393 FunctionPointer function_;
394 HANDLE completion_handle_;
395 // Make sure enough tasks are called before completion is signaled.
396 ThreadSafeDownCounter* counter_;
397
398 DISALLOW_COPY_AND_ASSIGN(RunTheStatic);
399 };
400
401 ThreadData::RunTheStatic::RunTheStatic(FunctionPointer function,
402 HANDLE completion_handle,
403 ThreadSafeDownCounter* counter)
404 : function_(function),
405 completion_handle_(completion_handle),
406 counter_(counter) {
407 }
408
409 void ThreadData::RunTheStatic::Run() {
410 function_();
411 if (counter_->LastCaller())
412 SetEvent(completion_handle_);
413 }
414
415 // TODO(jar): This should use condition variables, and be cross platform.
416 void ThreadData::RunOnAllThreads(void (*function)()) {
417 ThreadData* list = first(); // Get existing list.
418
419 std::vector<MessageLoop*> message_loops;
420 for (ThreadData* it = list; it; it = it->next()) {
421 if (current() != it && it->message_loop())
422 message_loops.push_back(it->message_loop());
423 }
424
425 ThreadSafeDownCounter* counter =
426 new ThreadSafeDownCounter(message_loops.size() + 1); // Extra one for us!
427
428 HANDLE completion_handle = CreateEvent(NULL, false, false, NULL);
429 // Tell all other threads to run.
430 for (size_t i = 0; i < message_loops.size(); ++i)
431 message_loops[i]->PostTask(
432 FROM_HERE, new RunTheStatic(function, completion_handle, counter));
433
434 // Also run Task on our thread.
435 RunTheStatic local_task(function, completion_handle, counter);
436 local_task.Run();
437
438 WaitForSingleObject(completion_handle, INFINITE);
439 int ret_val = CloseHandle(completion_handle);
440 DCHECK(ret_val);
441 }
442 #endif // OS_WIN
443
444 // static 377 // static
445 bool ThreadData::StartTracking(bool status) { 378 bool ThreadData::StartTracking(bool status) {
446 #if !defined(TRACK_ALL_TASK_OBJECTS) 379 #if !defined(TRACK_ALL_TASK_OBJECTS)
447 return false; // Not compiled in. 380 return false; // Not compiled in.
448 #endif 381 #else
449
450 if (!status) { 382 if (!status) {
451 base::AutoLock lock(list_lock_); 383 base::AutoLock lock(list_lock_);
452 DCHECK(status_ == ACTIVE || status_ == SHUTDOWN); 384 DCHECK(status_ == ACTIVE || status_ == SHUTDOWN);
453 status_ = SHUTDOWN; 385 status_ = SHUTDOWN;
454 return true; 386 return true;
455 } 387 }
456 base::AutoLock lock(list_lock_); 388 base::AutoLock lock(list_lock_);
457 DCHECK_EQ(UNINITIALIZED, status_); 389 DCHECK_EQ(UNINITIALIZED, status_);
458 CHECK(tls_index_.Initialize(NULL)); 390 CHECK(tls_index_.Initialize(NULL));
459 status_ = ACTIVE; 391 status_ = ACTIVE;
460 return true; 392 return true;
393 #endif
461 } 394 }
462 395
463 // static 396 // static
464 bool ThreadData::IsActive() { 397 bool ThreadData::IsActive() {
465 return status_ == ACTIVE; 398 return status_ == ACTIVE;
466 } 399 }
467 400
468 #ifdef OS_WIN
469 // static 401 // static
470 void ThreadData::ShutdownMultiThreadTracking() { 402 base::TimeTicks ThreadData::Now() {
471 // Using lock, guarantee that no new ThreadData instances will be created. 403 #if defined(TRACK_ALL_TASK_OBJECTS)
472 if (!StartTracking(false)) 404 if (status_ == ACTIVE)
473 return; 405 return base::TimeTicks::Now();
474 406 #endif
475 RunOnAllThreads(ShutdownDisablingFurtherTracking); 407 return base::TimeTicks(); // Super fast when disabled, or not compiled in.
476
477 // Now the *only* threads that might change the database are the threads with
478 // no messages loops. They might still be adding data to their birth records,
479 // but since no objects are deleted on those threads, there will be no further
480 // access to to cross-thread data.
481 // We could do a cleanup on all threads except for the ones without
482 // MessageLoops, but we won't bother doing cleanup (destruction of data) yet.
483 return;
484 } 408 }
485 #endif
486 409
487 // static 410 // static
488 void ThreadData::ShutdownSingleThreadedCleanup() { 411 void ThreadData::ShutdownSingleThreadedCleanup() {
489 // We must be single threaded... but be careful anyway. 412 // We must be single threaded... but be careful anyway.
490 if (!StartTracking(false)) 413 if (!StartTracking(false))
491 return; 414 return;
492 ThreadData* thread_data_list; 415 ThreadData* thread_data_list;
493 { 416 {
494 base::AutoLock lock(list_lock_); 417 base::AutoLock lock(list_lock_);
495 thread_data_list = first_; 418 thread_data_list = first_;
(...skipping 11 matching lines...) Expand all
507 next_thread_data->death_map_.clear(); 430 next_thread_data->death_map_.clear();
508 delete next_thread_data; // Includes all Death Records. 431 delete next_thread_data; // Includes all Death Records.
509 } 432 }
510 433
511 CHECK(tls_index_.initialized()); 434 CHECK(tls_index_.initialized());
512 tls_index_.Free(); 435 tls_index_.Free();
513 DCHECK(!tls_index_.initialized()); 436 DCHECK(!tls_index_.initialized());
514 status_ = UNINITIALIZED; 437 status_ = UNINITIALIZED;
515 } 438 }
516 439
517 // static
518 void ThreadData::ShutdownDisablingFurtherTracking() {
519 // Redundantly set status SHUTDOWN on this thread.
520 if (!StartTracking(false))
521 return;
522 }
523
524 //------------------------------------------------------------------------------ 440 //------------------------------------------------------------------------------
525 // Individual 3-tuple of birth (place and thread) along with death thread, and 441 // Individual 3-tuple of birth (place and thread) along with death thread, and
526 // the accumulated stats for instances (DeathData). 442 // the accumulated stats for instances (DeathData).
527 443
528 Snapshot::Snapshot(const BirthOnThread& birth_on_thread, 444 Snapshot::Snapshot(const BirthOnThread& birth_on_thread,
529 const ThreadData& death_thread, 445 const ThreadData& death_thread,
530 const DeathData& death_data) 446 const DeathData& death_data)
531 : birth_(&birth_on_thread), 447 : birth_(&birth_on_thread),
532 death_thread_(&death_thread), 448 death_thread_(&death_thread),
533 death_data_(death_data) { 449 death_data_(death_data) {
534 } 450 }
535 451
536 Snapshot::Snapshot(const BirthOnThread& birth_on_thread, int count) 452 Snapshot::Snapshot(const BirthOnThread& birth_on_thread, int count)
537 : birth_(&birth_on_thread), 453 : birth_(&birth_on_thread),
538 death_thread_(NULL), 454 death_thread_(NULL),
539 death_data_(DeathData(count)) { 455 death_data_(DeathData(count)) {
540 } 456 }
541 457
542 const std::string Snapshot::DeathThreadName() const { 458 const std::string Snapshot::DeathThreadName() const {
543 if (death_thread_) 459 if (death_thread_)
544 return death_thread_->ThreadName(); 460 return death_thread_->thread_name();
545 return "Still_Alive"; 461 return "Still_Alive";
546 } 462 }
547 463
548 void Snapshot::Write(std::string* output) const { 464 void Snapshot::Write(std::string* output) const {
549 death_data_.Write(output); 465 death_data_.Write(output);
550 base::StringAppendF(output, "%s->%s ", 466 base::StringAppendF(output, "%s->%s ",
551 birth_->birth_thread()->ThreadName().c_str(), 467 birth_->birth_thread()->thread_name().c_str(),
552 death_thread_->ThreadName().c_str()); 468 death_thread_->thread_name().c_str());
553 birth_->location().Write(true, true, output); 469 birth_->location().Write(true, true, output);
554 } 470 }
555 471
556 void Snapshot::Add(const Snapshot& other) { 472 void Snapshot::Add(const Snapshot& other) {
557 death_data_.AddDeathData(other.death_data_); 473 death_data_.AddDeathData(other.death_data_);
558 } 474 }
559 475
560 //------------------------------------------------------------------------------ 476 //------------------------------------------------------------------------------
561 // DataCollector 477 // DataCollector
562 478
563 DataCollector::DataCollector() { 479 DataCollector::DataCollector() {
564 DCHECK(ThreadData::IsActive()); 480 DCHECK(ThreadData::IsActive());
565 481
566 // Get an unchanging copy of a ThreadData list. 482 // Get an unchanging copy of a ThreadData list.
567 ThreadData* my_list = ThreadData::current()->first(); 483 ThreadData* my_list = ThreadData::Get()->first();
568 484
569 count_of_contributing_threads_ = 0; 485 // Gather data serially.
570 for (ThreadData* thread_data = my_list;
571 thread_data;
572 thread_data = thread_data->next()) {
573 ++count_of_contributing_threads_;
574 }
575
576 // Gather data serially. A different constructor could be used to do in
577 // parallel, and then invoke an OnCompletion task.
578 // This hackish approach *can* get some slighly corrupt tallies, as we are 486 // This hackish approach *can* get some slighly corrupt tallies, as we are
579 // grabbing values without the protection of a lock, but it has the advantage 487 // grabbing values without the protection of a lock, but it has the advantage
580 // of working even with threads that don't have message loops. If a user 488 // of working even with threads that don't have message loops. If a user
581 // sees any strangeness, they can always just run their stats gathering a 489 // sees any strangeness, they can always just run their stats gathering a
582 // second time. 490 // second time.
583 // TODO(jar): Provide version that gathers stats safely via PostTask in all
584 // cases where thread_data supplies a message_loop to post to. Be careful to
585 // handle message_loops that are destroyed!?!
586 for (ThreadData* thread_data = my_list; 491 for (ThreadData* thread_data = my_list;
587 thread_data; 492 thread_data;
588 thread_data = thread_data->next()) { 493 thread_data = thread_data->next()) {
589 Append(*thread_data); 494 Append(*thread_data);
590 } 495 }
591 } 496 }
592 497
593 DataCollector::~DataCollector() { 498 DataCollector::~DataCollector() {
594 } 499 }
595 500
596 void DataCollector::Append(const ThreadData& thread_data) { 501 void DataCollector::Append(const ThreadData& thread_data) {
597 // Get copy of data (which is done under ThreadData's lock). 502 // Get copy of data.
598 ThreadData::BirthMap birth_map; 503 ThreadData::BirthMap birth_map;
599 thread_data.SnapshotBirthMap(&birth_map); 504 thread_data.SnapshotBirthMap(&birth_map);
600 ThreadData::DeathMap death_map; 505 ThreadData::DeathMap death_map;
601 thread_data.SnapshotDeathMap(&death_map); 506 thread_data.SnapshotDeathMap(&death_map);
602 507
603 // Use our lock to protect our accumulation activity.
604 base::AutoLock lock(accumulation_lock_);
605
606 DCHECK(count_of_contributing_threads_);
607
608 for (ThreadData::DeathMap::const_iterator it = death_map.begin(); 508 for (ThreadData::DeathMap::const_iterator it = death_map.begin();
609 it != death_map.end(); ++it) { 509 it != death_map.end(); ++it) {
610 collection_.push_back(Snapshot(*it->first, thread_data, it->second)); 510 collection_.push_back(Snapshot(*it->first, thread_data, it->second));
611 global_birth_count_[it->first] -= it->first->birth_count(); 511 global_birth_count_[it->first] -= it->first->birth_count();
612 } 512 }
613 513
614 for (ThreadData::BirthMap::const_iterator it = birth_map.begin(); 514 for (ThreadData::BirthMap::const_iterator it = birth_map.begin();
615 it != birth_map.end(); ++it) { 515 it != birth_map.end(); ++it) {
616 global_birth_count_[it->second] += it->second->birth_count(); 516 global_birth_count_[it->second] += it->second->birth_count();
617 } 517 }
618
619 --count_of_contributing_threads_;
620 } 518 }
621 519
622 DataCollector::Collection* DataCollector::collection() { 520 DataCollector::Collection* DataCollector::collection() {
623 DCHECK(!count_of_contributing_threads_);
624 return &collection_; 521 return &collection_;
625 } 522 }
626 523
627 void DataCollector::AddListOfLivingObjects() { 524 void DataCollector::AddListOfLivingObjects() {
628 DCHECK(!count_of_contributing_threads_);
629 for (BirthCount::iterator it = global_birth_count_.begin(); 525 for (BirthCount::iterator it = global_birth_count_.begin();
630 it != global_birth_count_.end(); ++it) { 526 it != global_birth_count_.end(); ++it) {
631 if (it->second > 0) 527 if (it->second > 0)
632 collection_.push_back(Snapshot(*it->first, it->second)); 528 collection_.push_back(Snapshot(*it->first, it->second));
633 } 529 }
634 } 530 }
635 531
636 //------------------------------------------------------------------------------ 532 //------------------------------------------------------------------------------
637 // Aggregation 533 // Aggregation
638 534
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
674 base::StringAppendF(output, "All born in %s. ", 570 base::StringAppendF(output, "All born in %s. ",
675 birth_files_.begin()->first.c_str()); 571 birth_files_.begin()->first.c_str());
676 } 572 }
677 } 573 }
678 574
679 if (birth_threads_.size() > 1) { 575 if (birth_threads_.size() > 1) {
680 base::StringAppendF(output, "%" PRIuS " BirthingThreads. ", 576 base::StringAppendF(output, "%" PRIuS " BirthingThreads. ",
681 birth_threads_.size()); 577 birth_threads_.size());
682 } else { 578 } else {
683 base::StringAppendF(output, "All born on %s. ", 579 base::StringAppendF(output, "All born on %s. ",
684 birth_threads_.begin()->first->ThreadName().c_str()); 580 birth_threads_.begin()->first->thread_name().c_str());
685 } 581 }
686 582
687 if (death_threads_.size() > 1) { 583 if (death_threads_.size() > 1) {
688 base::StringAppendF(output, "%" PRIuS " DeathThreads. ", 584 base::StringAppendF(output, "%" PRIuS " DeathThreads. ",
689 death_threads_.size()); 585 death_threads_.size());
690 } else { 586 } else {
691 if (death_threads_.begin()->first) { 587 if (death_threads_.begin()->first) {
692 base::StringAppendF(output, "All deleted on %s. ", 588 base::StringAppendF(output, "All deleted on %s. ",
693 death_threads_.begin()->first->ThreadName().c_str()); 589 death_threads_.begin()->first->thread_name().c_str());
694 } else { 590 } else {
695 output->append("All these objects are still alive."); 591 output->append("All these objects are still alive.");
696 } 592 }
697 } 593 }
698 594
699 if (birth_count_ > 1) 595 if (birth_count_ > 1)
700 base::StringAppendF(output, "Births=%d ", birth_count_); 596 base::StringAppendF(output, "Births=%d ", birth_count_);
701 597
702 DeathData::Write(output); 598 DeathData::Write(output);
703 } 599 }
(...skipping 24 matching lines...) Expand all
728 } 624 }
729 use_tiebreaker_for_sort_only_ = false; 625 use_tiebreaker_for_sort_only_ = false;
730 selector_ = NIL; 626 selector_ = NIL;
731 } 627 }
732 628
733 bool Comparator::operator()(const Snapshot& left, 629 bool Comparator::operator()(const Snapshot& left,
734 const Snapshot& right) const { 630 const Snapshot& right) const {
735 switch (selector_) { 631 switch (selector_) {
736 case BIRTH_THREAD: 632 case BIRTH_THREAD:
737 if (left.birth_thread() != right.birth_thread() && 633 if (left.birth_thread() != right.birth_thread() &&
738 left.birth_thread()->ThreadName() != 634 left.birth_thread()->thread_name() !=
739 right.birth_thread()->ThreadName()) 635 right.birth_thread()->thread_name())
740 return left.birth_thread()->ThreadName() < 636 return left.birth_thread()->thread_name() <
741 right.birth_thread()->ThreadName(); 637 right.birth_thread()->thread_name();
742 break; 638 break;
743 639
744 case DEATH_THREAD: 640 case DEATH_THREAD:
745 if (left.death_thread() != right.death_thread() && 641 if (left.death_thread() != right.death_thread() &&
746 left.DeathThreadName() != 642 left.DeathThreadName() !=
747 right.DeathThreadName()) { 643 right.DeathThreadName()) {
748 if (!left.death_thread()) 644 if (!left.death_thread())
749 return true; 645 return true;
750 if (!right.death_thread()) 646 if (!right.death_thread())
751 return false; 647 return false;
(...skipping 24 matching lines...) Expand all
776 if (left.location().line_number() != right.location().line_number()) 672 if (left.location().line_number() != right.location().line_number())
777 return left.location().line_number() < 673 return left.location().line_number() <
778 right.location().line_number(); 674 right.location().line_number();
779 break; 675 break;
780 676
781 case COUNT: 677 case COUNT:
782 if (left.count() != right.count()) 678 if (left.count() != right.count())
783 return left.count() > right.count(); // Sort large at front of vector. 679 return left.count() > right.count(); // Sort large at front of vector.
784 break; 680 break;
785 681
786 case AVERAGE_DURATION: 682 case AVERAGE_RUN_DURATION:
787 if (!left.count() || !right.count()) 683 if (!left.count() || !right.count())
788 break; 684 break;
789 if (left.AverageMsDuration() != right.AverageMsDuration()) 685 if (left.AverageMsRunDuration() != right.AverageMsRunDuration())
790 return left.AverageMsDuration() > right.AverageMsDuration(); 686 return left.AverageMsRunDuration() > right.AverageMsRunDuration();
687 break;
688
689 case TOTAL_RUN_DURATION:
690 if (!left.count() || !right.count())
691 break;
692 if (left.run_duration() != right.run_duration())
693 return left.run_duration() > right.run_duration();
694 break;
695
696 case AVERAGE_QUEUE_DURATION:
697 if (!left.count() || !right.count())
698 break;
699 if (left.AverageMsQueueDuration() != right.AverageMsQueueDuration())
700 return left.AverageMsQueueDuration() > right.AverageMsQueueDuration();
701 break;
702
703 case TOTAL_QUEUE_DURATION:
704 if (!left.count() || !right.count())
705 break;
706 if (left.queue_duration() != right.queue_duration())
707 return left.queue_duration() > right.queue_duration();
791 break; 708 break;
792 709
793 default: 710 default:
794 break; 711 break;
795 } 712 }
796 if (tiebreaker_) 713 if (tiebreaker_)
797 return tiebreaker_->operator()(left, right); 714 return tiebreaker_->operator()(left, right);
798 return false; 715 return false;
799 } 716 }
800 717
801 void Comparator::Sort(DataCollector::Collection* collection) const { 718 void Comparator::Sort(DataCollector::Collection* collection) const {
802 std::sort(collection->begin(), collection->end(), *this); 719 std::sort(collection->begin(), collection->end(), *this);
803 } 720 }
804 721
805 bool Comparator::Equivalent(const Snapshot& left, 722 bool Comparator::Equivalent(const Snapshot& left,
806 const Snapshot& right) const { 723 const Snapshot& right) const {
807 switch (selector_) { 724 switch (selector_) {
808 case BIRTH_THREAD: 725 case BIRTH_THREAD:
809 if (left.birth_thread() != right.birth_thread() && 726 if (left.birth_thread() != right.birth_thread() &&
810 left.birth_thread()->ThreadName() != 727 left.birth_thread()->thread_name() !=
811 right.birth_thread()->ThreadName()) 728 right.birth_thread()->thread_name())
812 return false; 729 return false;
813 break; 730 break;
814 731
815 case DEATH_THREAD: 732 case DEATH_THREAD:
816 if (left.death_thread() != right.death_thread() && 733 if (left.death_thread() != right.death_thread() &&
817 left.DeathThreadName() != right.DeathThreadName()) 734 left.DeathThreadName() != right.DeathThreadName())
818 return false; 735 return false;
819 break; 736 break;
820 737
821 case BIRTH_FILE: 738 case BIRTH_FILE:
822 if (left.location().file_name() != right.location().file_name()) { 739 if (left.location().file_name() != right.location().file_name()) {
823 int comp = strcmp(left.location().file_name(), 740 int comp = strcmp(left.location().file_name(),
824 right.location().file_name()); 741 right.location().file_name());
825 if (comp) 742 if (comp)
826 return false; 743 return false;
827 } 744 }
828 break; 745 break;
829 746
830 case BIRTH_FUNCTION: 747 case BIRTH_FUNCTION:
831 if (left.location().function_name() != right.location().function_name()) { 748 if (left.location().function_name() != right.location().function_name()) {
832 int comp = strcmp(left.location().function_name(), 749 int comp = strcmp(left.location().function_name(),
833 right.location().function_name()); 750 right.location().function_name());
834 if (comp) 751 if (comp)
835 return false; 752 return false;
836 } 753 }
837 break; 754 break;
838 755
839 case COUNT: 756 case COUNT:
840 if (left.count() != right.count()) 757 case AVERAGE_RUN_DURATION:
841 return false; 758 case TOTAL_RUN_DURATION:
842 break; 759 case AVERAGE_QUEUE_DURATION:
843 760 case TOTAL_QUEUE_DURATION:
844 case AVERAGE_DURATION: 761 // We don't produce separate aggretation when only counts or times differ.
845 if (left.life_duration() != right.life_duration())
846 return false;
847 break; 762 break;
848 763
849 default: 764 default:
850 break; 765 break;
851 } 766 }
852 if (tiebreaker_ && !use_tiebreaker_for_sort_only_) 767 if (tiebreaker_ && !use_tiebreaker_for_sort_only_)
853 return tiebreaker_->Equivalent(left, right); 768 return tiebreaker_->Equivalent(left, right);
854 return true; 769 return true;
855 } 770 }
856 771
857 bool Comparator::Acceptable(const Snapshot& sample) const { 772 bool Comparator::Acceptable(const Snapshot& sample) const {
858 if (required_.size()) { 773 if (required_.size()) {
859 switch (selector_) { 774 switch (selector_) {
860 case BIRTH_THREAD: 775 case BIRTH_THREAD:
861 if (sample.birth_thread()->ThreadName().find(required_) == 776 if (sample.birth_thread()->thread_name().find(required_) ==
862 std::string::npos) 777 std::string::npos)
863 return false; 778 return false;
864 break; 779 break;
865 780
866 case DEATH_THREAD: 781 case DEATH_THREAD:
867 if (sample.DeathThreadName().find(required_) == std::string::npos) 782 if (sample.DeathThreadName().find(required_) == std::string::npos)
868 return false; 783 return false;
869 break; 784 break;
870 785
871 case BIRTH_FILE: 786 case BIRTH_FILE:
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
927 } 842 }
928 843
929 void Comparator::ParseKeyphrase(const std::string& key_phrase) { 844 void Comparator::ParseKeyphrase(const std::string& key_phrase) {
930 typedef std::map<const std::string, Selector> KeyMap; 845 typedef std::map<const std::string, Selector> KeyMap;
931 static KeyMap key_map; 846 static KeyMap key_map;
932 static bool initialized = false; 847 static bool initialized = false;
933 if (!initialized) { 848 if (!initialized) {
934 initialized = true; 849 initialized = true;
935 // Sorting and aggretation keywords, which specify how to sort the data, or 850 // Sorting and aggretation keywords, which specify how to sort the data, or
936 // can specify a required match from the specified field in the record. 851 // can specify a required match from the specified field in the record.
937 key_map["count"] = COUNT; 852 key_map["count"] = COUNT;
938 key_map["duration"] = AVERAGE_DURATION; 853 key_map["totalduration"] = TOTAL_RUN_DURATION;
939 key_map["birth"] = BIRTH_THREAD; 854 key_map["duration"] = AVERAGE_RUN_DURATION;
940 key_map["death"] = DEATH_THREAD; 855 key_map["totalqueueduration"] = TOTAL_QUEUE_DURATION;
941 key_map["file"] = BIRTH_FILE; 856 key_map["averagequeueduration"] = AVERAGE_QUEUE_DURATION;
942 key_map["function"] = BIRTH_FUNCTION; 857 key_map["birth"] = BIRTH_THREAD;
943 key_map["line"] = BIRTH_LINE; 858 key_map["death"] = DEATH_THREAD;
859 key_map["file"] = BIRTH_FILE;
860 key_map["function"] = BIRTH_FUNCTION;
861 key_map["line"] = BIRTH_LINE;
944 862
945 // Immediate commands that do not involve setting sort order. 863 // Immediate commands that do not involve setting sort order.
946 key_map["reset"] = RESET_ALL_DATA; 864 key_map["reset"] = RESET_ALL_DATA;
947 } 865 }
948 866
949 std::string required; 867 std::string required;
950 // Watch for: "sort_key=value" as we parse. 868 // Watch for: "sort_key=value" as we parse.
951 size_t equal_offset = key_phrase.find('=', 0); 869 size_t equal_offset = key_phrase.find('=', 0);
952 if (key_phrase.npos != equal_offset) { 870 if (key_phrase.npos != equal_offset) {
953 // There is a value that must be matched for the data to display. 871 // There is a value that must be matched for the data to display.
(...skipping 15 matching lines...) Expand all
969 for (size_t i = 0; i < query.size();) { 887 for (size_t i = 0; i < query.size();) {
970 size_t slash_offset = query.find('/', i); 888 size_t slash_offset = query.find('/', i);
971 ParseKeyphrase(query.substr(i, slash_offset - i)); 889 ParseKeyphrase(query.substr(i, slash_offset - i));
972 if (query.npos == slash_offset) 890 if (query.npos == slash_offset)
973 break; 891 break;
974 i = slash_offset + 1; 892 i = slash_offset + 1;
975 } 893 }
976 894
977 // Select subgroup ordering (if we want to display the subgroup) 895 // Select subgroup ordering (if we want to display the subgroup)
978 SetSubgroupTiebreaker(COUNT); 896 SetSubgroupTiebreaker(COUNT);
979 SetSubgroupTiebreaker(AVERAGE_DURATION); 897 SetSubgroupTiebreaker(AVERAGE_RUN_DURATION);
898 SetSubgroupTiebreaker(TOTAL_RUN_DURATION);
980 SetSubgroupTiebreaker(BIRTH_THREAD); 899 SetSubgroupTiebreaker(BIRTH_THREAD);
981 SetSubgroupTiebreaker(DEATH_THREAD); 900 SetSubgroupTiebreaker(DEATH_THREAD);
982 SetSubgroupTiebreaker(BIRTH_FUNCTION); 901 SetSubgroupTiebreaker(BIRTH_FUNCTION);
983 SetSubgroupTiebreaker(BIRTH_FILE); 902 SetSubgroupTiebreaker(BIRTH_FILE);
984 SetSubgroupTiebreaker(BIRTH_LINE); 903 SetSubgroupTiebreaker(BIRTH_LINE);
985 904
986 return true; 905 return true;
987 } 906 }
988 907
989 bool Comparator::WriteSortGrouping(const Snapshot& sample, 908 bool Comparator::WriteSortGrouping(const Snapshot& sample,
990 std::string* output) const { 909 std::string* output) const {
991 bool wrote_data = false; 910 bool wrote_data = false;
992 switch (selector_) { 911 switch (selector_) {
993 case BIRTH_THREAD: 912 case BIRTH_THREAD:
994 base::StringAppendF(output, "All new on %s ", 913 base::StringAppendF(output, "All new on %s ",
995 sample.birth_thread()->ThreadName().c_str()); 914 sample.birth_thread()->thread_name().c_str());
996 wrote_data = true; 915 wrote_data = true;
997 break; 916 break;
998 917
999 case DEATH_THREAD: 918 case DEATH_THREAD:
1000 if (sample.death_thread()) { 919 if (sample.death_thread()) {
1001 base::StringAppendF(output, "All deleted on %s ", 920 base::StringAppendF(output, "All deleted on %s ",
1002 sample.DeathThreadName().c_str()); 921 sample.DeathThreadName().c_str());
1003 } else { 922 } else {
1004 output->append("All still alive "); 923 output->append("All still alive ");
1005 } 924 }
(...skipping 20 matching lines...) Expand all
1026 return wrote_data; 945 return wrote_data;
1027 } 946 }
1028 947
1029 void Comparator::WriteSnapshot(const Snapshot& sample, 948 void Comparator::WriteSnapshot(const Snapshot& sample,
1030 std::string* output) const { 949 std::string* output) const {
1031 sample.death_data().Write(output); 950 sample.death_data().Write(output);
1032 if (!(combined_selectors_ & BIRTH_THREAD) || 951 if (!(combined_selectors_ & BIRTH_THREAD) ||
1033 !(combined_selectors_ & DEATH_THREAD)) 952 !(combined_selectors_ & DEATH_THREAD))
1034 base::StringAppendF(output, "%s->%s ", 953 base::StringAppendF(output, "%s->%s ",
1035 (combined_selectors_ & BIRTH_THREAD) ? "*" : 954 (combined_selectors_ & BIRTH_THREAD) ? "*" :
1036 sample.birth().birth_thread()->ThreadName().c_str(), 955 sample.birth().birth_thread()->thread_name().c_str(),
1037 (combined_selectors_ & DEATH_THREAD) ? "*" : 956 (combined_selectors_ & DEATH_THREAD) ? "*" :
1038 sample.DeathThreadName().c_str()); 957 sample.DeathThreadName().c_str());
1039 sample.birth().location().Write(!(combined_selectors_ & BIRTH_FILE), 958 sample.birth().location().Write(!(combined_selectors_ & BIRTH_FILE),
1040 !(combined_selectors_ & BIRTH_FUNCTION), 959 !(combined_selectors_ & BIRTH_FUNCTION),
1041 output); 960 output);
1042 } 961 }
1043 962
1044 } // namespace tracked_objects 963 } // namespace tracked_objects
OLDNEW
« no previous file with comments | « base/tracked_objects.h ('k') | base/tracked_objects_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698