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

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
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& duration) {
31 ++count_; 35 ++count_;
32 life_duration_ += duration; 36 life_duration_ += duration;
33 int64 milliseconds = duration.InMilliseconds();
34 square_duration_ += milliseconds * milliseconds;
35 } 37 }
36 38
37 int DeathData::AverageMsDuration() const { 39 int DeathData::AverageMsDuration() const {
38 return static_cast<int>(life_duration_.InMilliseconds() / count_); 40 return static_cast<int>(life_duration_.InMilliseconds() / count_);
39 } 41 }
40 42
41 double DeathData::StandardDeviation() const {
42 double average = AverageMsDuration();
43 double variance = static_cast<float>(square_duration_)/count_
44 - average * average;
45 return sqrt(variance);
46 }
47
48
49 void DeathData::AddDeathData(const DeathData& other) { 43 void DeathData::AddDeathData(const DeathData& other) {
50 count_ += other.count_; 44 count_ += other.count_;
51 life_duration_ += other.life_duration_; 45 life_duration_ += other.life_duration_;
52 square_duration_ += other.square_duration_;
53 } 46 }
54 47
55 void DeathData::Write(std::string* output) const { 48 void DeathData::Write(std::string* output) const {
56 if (!count_) 49 if (!count_)
57 return; 50 return;
58 if (1 == count_) { 51 base::StringAppendF(output, "Lives:%d, Total:%dms Avg:%dms/life ",
59 base::StringAppendF(output, "(1)Life in %dms ", AverageMsDuration()); 52 count_,
60 } else { 53 static_cast<int>(life_duration_.InMilliseconds()),
61 base::StringAppendF(output, "(%d)Lives %dms/life ", 54 AverageMsDuration());
62 count_, AverageMsDuration());
63 }
64 } 55 }
65 56
66 void DeathData::Clear() { 57 void DeathData::Clear() {
67 count_ = 0; 58 count_ = 0;
68 life_duration_ = TimeDelta(); 59 life_duration_ = TimeDelta();
69 square_duration_ = 0;
70 } 60 }
71 61
72 //------------------------------------------------------------------------------ 62 //------------------------------------------------------------------------------
73 BirthOnThread::BirthOnThread(const Location& location) 63 BirthOnThread::BirthOnThread(const Location& location)
74 : location_(location), 64 : location_(location),
75 birth_thread_(ThreadData::current()) { } 65 birth_thread_(ThreadData::FactoryGet(NULL)) { }
76 66
77 //------------------------------------------------------------------------------ 67 //------------------------------------------------------------------------------
78 Births::Births(const Location& location) 68 Births::Births(const Location& location)
79 : BirthOnThread(location), 69 : BirthOnThread(location),
80 birth_count_(1) { } 70 birth_count_(1) { }
81 71
82 //------------------------------------------------------------------------------ 72 //------------------------------------------------------------------------------
83 // ThreadData maintains the central data for all births and death. 73 // ThreadData maintains the central data for all births and death.
84 74
85 // static 75 // static
86 ThreadData* ThreadData::first_ = NULL; 76 ThreadData* ThreadData::first_ = NULL;
87 // static 77 // static
88 base::Lock ThreadData::list_lock_; 78 base::Lock ThreadData::list_lock_;
89 79
90 // static 80 // static
91 ThreadData::Status ThreadData::status_ = ThreadData::UNINITIALIZED; 81 ThreadData::Status ThreadData::status_ = ThreadData::UNINITIALIZED;
92 82
93 ThreadData::ThreadData() : next_(NULL) { 83 ThreadData::ThreadData(const char* suggested_name)
94 // This shouldn't use the MessageLoop::current() LazyInstance since this might 84 : next_(NULL),
95 // be used on a non-joinable thread. 85 thread_number_(0) {
96 // http://crbug.com/62728 86 if (suggested_name) {
97 base::ThreadRestrictions::ScopedAllowSingleton scoped_allow_singleton; 87 DCHECK_GE(strlen(suggested_name), 0u);
98 message_loop_ = MessageLoop::current(); 88 thread_name_ = suggested_name;
89 return;
90 }
91 {
92 base::AutoLock lock(list_lock_);
93 thread_number_ = ++thread_number_counter;
94 }
95 base::StringAppendF(&thread_name_, "WorkerThread-%d", thread_number_);
99 } 96 }
100 97
101 ThreadData::~ThreadData() {} 98 ThreadData::~ThreadData() {}
102 99
103 // static 100 // static
104 ThreadData* ThreadData::current() { 101 ThreadData* ThreadData::FactoryGet(const char* suggested_name) {
105 if (!tls_index_.initialized()) 102 if (!tls_index_.initialized())
106 return NULL; 103 return NULL;
107 104
108 ThreadData* registry = static_cast<ThreadData*>(tls_index_.Get()); 105 ThreadData* registered = static_cast<ThreadData*>(tls_index_.Get());
109 if (!registry) { 106 if (!registered) {
110 // We have to create a new registry for ThreadData. 107 // We have to create a new registry entry for this ThreadData.
111 bool too_late_to_create = false; 108 bool too_late_to_create = false;
109 // TODO(jar): Host all unamed (Worker) threads in *one* ThreadData instance,
110 // (with locking protection on that instance) or else recycle and re-use
111 // worker thread ThreadData when the worker thread terminates.
112 registered = new ThreadData(suggested_name);
112 { 113 {
113 registry = new ThreadData;
114 base::AutoLock lock(list_lock_); 114 base::AutoLock lock(list_lock_);
115 // Use lock to insure we have most recent status. 115 // Use lock to insure we have most recent status.
116 if (!IsActive()) { 116 if (!IsActive()) {
117 too_late_to_create = true; 117 too_late_to_create = true;
118 } else { 118 } else {
119 // Use lock to insert into list. 119 // Use list_lock_ to insert as new head of list.
120 registry->next_ = first_; 120 registered->next_ = first_;
121 first_ = registry; 121 first_ = registered;
122 } 122 }
123 } // Release lock. 123 } // Release lock.
124 if (too_late_to_create) { 124 if (too_late_to_create) {
125 delete registry; 125 delete registered;
126 registry = NULL; 126 registered = NULL;
127 } else { 127 } else {
128 tls_index_.Set(registry); 128 tls_index_.Set(registered);
129 } 129 }
130 } 130 }
131 return registry; 131 DCHECK_GT(registered->thread_name_.size(), 0u);
132 // If this DCHECK fails, then a task was *probabably* created on this thread
133 // before the thread object was initialized with a name etc.
134 DCHECK(!suggested_name ||
135 registered->thread_name_.compare(suggested_name) == 0);
136
137 return registered;
132 } 138 }
133 139
134 // static 140 // static
135 void ThreadData::WriteHTML(const std::string& query, std::string* output) { 141 void ThreadData::WriteHTML(const std::string& query, std::string* output) {
136 if (!ThreadData::IsActive()) 142 if (!ThreadData::IsActive())
137 return; // Not yet initialized. 143 return; // Not yet initialized.
138 144
139 DCHECK(ThreadData::current());
140 DataCollector collected_data; // Gather data. 145 DataCollector collected_data; // Gather data.
141 collected_data.AddListOfLivingObjects(); // Add births that are still alive. 146 collected_data.AddListOfLivingObjects(); // Add births that are still alive.
142 147
143 // Data Gathering is complete. Now to sort/process/render. 148 // Data Gathering is complete. Now to sort/process/render.
144 DataCollector::Collection* collection = collected_data.collection(); 149 DataCollector::Collection* collection = collected_data.collection();
145 150
146 // Create filtering and sort comparison object. 151 // Create filtering and sort comparison object.
147 Comparator comparator; 152 Comparator comparator;
148 comparator.ParseQuery(query); 153 comparator.ParseQuery(query);
149 154
150 // Filter out acceptable (matching) instances. 155 // Filter out acceptable (matching) instances.
151 DataCollector::Collection match_array; 156 DataCollector::Collection match_array;
152 for (DataCollector::Collection::iterator it = collection->begin(); 157 for (DataCollector::Collection::iterator it = collection->begin();
153 it != collection->end(); ++it) { 158 it != collection->end(); ++it) {
154 if (comparator.Acceptable(*it)) 159 if (comparator.Acceptable(*it))
155 match_array.push_back(*it); 160 match_array.push_back(*it);
156 } 161 }
157 162
158 comparator.Sort(&match_array); 163 comparator.Sort(&match_array);
159 164
160 WriteHTMLTotalAndSubtotals(match_array, comparator, output); 165 WriteHTMLTotalAndSubtotals(match_array, comparator, output);
161 166
162 comparator.Clear(); // Delete tiebreaker_ instances. 167 comparator.Clear(); // Delete tiebreaker_ instances.
163 168
164 output->append("</pre>"); 169 output->append("</pre>");
165 170
166 const char* help_string = "The following are the keywords that can be used to" 171 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>" 172 " sort and aggregate the data, or to select data.<br><ul>"
168 "<li><b>count</b> Number of instances seen." 173 "<li><b>count</b> Number of instances seen."
169 "<li><b>duration</b> Duration in ms from construction to descrution." 174 "<li><b>duration</b> Average duration in ms of Run() time."
175 "<li><b>totalduration</b> Summed durations in ms of Run() times."
170 "<li><b>birth</b> Thread on which the task was constructed." 176 "<li><b>birth</b> Thread on which the task was constructed."
171 "<li><b>death</b> Thread on which the task was run and deleted." 177 "<li><b>death</b> Thread on which the task was run and deleted."
172 "<li><b>file</b> File in which the task was contructed." 178 "<li><b>file</b> File in which the task was contructed."
173 "<li><b>function</b> Function in which the task was constructed." 179 "<li><b>function</b> Function in which the task was constructed."
174 "<li><b>line</b> Line number of the file in which the task was constructed." 180 "<li><b>line</b> Line number of the file in which the task was constructed."
175 "</ul><br>" 181 "</ul><br>"
176 "As examples:<ul>" 182 "As examples:<ul>"
177 "<li><b>about:tracking/file</b> would sort the above data by file, and" 183 "<li><b>about:tracking/file</b> would sort the above data by file, and"
178 " aggregate data on a per-file basis." 184 " aggregate data on a per-file basis."
179 "<li><b>about:tracking/file=Dns</b> would only list data for tasks" 185 "<li><b>about:tracking/file=Dns</b> would only list data for tasks"
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
227 output->append("<br>"); 233 output->append("<br>");
228 subtotals.Write(output); 234 subtotals.Write(output);
229 output->append("<br><hr><br>"); 235 output->append("<br><hr><br>");
230 subtotals.Clear(); 236 subtotals.Clear();
231 } 237 }
232 } 238 }
233 } 239 }
234 } 240 }
235 241
236 Births* ThreadData::TallyABirth(const Location& location) { 242 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
jar (doing other things) 2011/10/14 02:29:53 This was the primary motivation for this cleanup C
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); 243 BirthMap::iterator it = birth_map_.find(location);
247 if (it != birth_map_.end()) { 244 if (it != birth_map_.end()) {
248 it->second->RecordBirth(); 245 it->second->RecordBirth();
249 return it->second; 246 return it->second;
250 } 247 }
251 248
252 Births* tracker = new Births(location); 249 Births* tracker = new Births(location);
253 // Lock since the map may get relocated now, and other threads sometimes 250 // Lock since the map may get relocated now, and other threads sometimes
254 // snapshot it (but they lock before copying it). 251 // snapshot it (but they lock before copying it).
255 base::AutoLock lock(lock_); 252 base::AutoLock lock(lock_);
256 birth_map_[location] = tracker; 253 birth_map_[location] = tracker;
257 return tracker; 254 return tracker;
258 } 255 }
259 256
260 void ThreadData::TallyADeath(const Births& lifetimes, 257 void ThreadData::TallyADeath(const Births& the_birth,
261 const TimeDelta& duration) { 258 const TimeDelta& duration) {
262 { 259 DeathMap::iterator it = death_map_.find(&the_birth);
263 // http://crbug.com/62728
jar (doing other things) 2011/10/14 02:29:53 Again... the motivation for the CL.
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()) { 260 if (it != death_map_.end()) {
271 it->second.RecordDeath(duration); 261 it->second.RecordDeath(duration);
272 return; 262 return;
273 } 263 }
274 264
275 base::AutoLock lock(lock_); // Lock since the map may get relocated now. 265 base::AutoLock lock(lock_); // Lock since the map may get relocated now.
276 death_map_[&lifetimes].RecordDeath(duration); 266 death_map_[&the_birth].RecordDeath(duration);
277 } 267 }
278 268
279 // static 269 // static
280 Births* ThreadData::TallyABirthIfActive(const Location& location) { 270 Births* ThreadData::TallyABirthIfActive(const Location& location) {
281 if (IsActive()) { 271 #if !defined(TRACK_ALL_TASK_OBJECTS)
282 ThreadData* current_thread_data = current(); 272 return NULL; // Not compiled in.
283 if (current_thread_data) { 273 #endif
284 return current_thread_data->TallyABirth(location); 274 if (!IsActive())
285 } 275 return NULL;
286 } 276 ThreadData* current_thread_data = FactoryGet(NULL);
287 277 if (!current_thread_data)
288 return NULL; 278 return NULL;
279 return current_thread_data->TallyABirth(location);
289 } 280 }
290 281
291 // static 282 // static
292 void ThreadData::TallyADeathIfActive(const Births* the_birth, 283 void ThreadData::TallyADeathIfActive(const Births* the_birth,
293 const base::TimeDelta& duration) { 284 const base::TimeTicks& time_posted,
294 if (IsActive() && the_birth) { 285 const base::TimeTicks& start_of_run,
295 current()->TallyADeath(*the_birth, duration); 286 const MessageLoop* message_loop) {
296 } 287 #if !defined(TRACK_ALL_TASK_OBJECTS)
288 return; // Not compiled in.
289 #endif
290 if (!IsActive() || !the_birth)
291 return;
292 ThreadData* current_thread_data = FactoryGet(NULL);
293 if (!current_thread_data)
294 return;
295 DCHECK(!message_loop ||
296 message_loop->thread_name() == current_thread_data->thread_name_);
297 // We don't currently handle queueing time duration, since time_posted, so
298 // we discard time_posted.
299 current_thread_data->TallyADeath(*the_birth,
300 base::TimeTicks::Now() - start_of_run);
297 } 301 }
298 302
299 // static 303 // static
300 ThreadData* ThreadData::first() { 304 ThreadData* ThreadData::first() {
301 base::AutoLock lock(list_lock_); 305 base::AutoLock lock(list_lock_);
302 return first_; 306 return first_;
303 } 307 }
304 308
305 const std::string ThreadData::ThreadName() const {
306 if (message_loop_)
307 return message_loop_->thread_name();
jar (doing other things) 2011/10/14 02:29:53 We now store the thread name, and don't need to ke
308 return "ThreadWithoutMessageLoop";
309 }
310
311 // This may be called from another thread. 309 // This may be called from another thread.
312 void ThreadData::SnapshotBirthMap(BirthMap *output) const { 310 void ThreadData::SnapshotBirthMap(BirthMap *output) const {
313 base::AutoLock lock(lock_); 311 base::AutoLock lock(lock_);
314 for (BirthMap::const_iterator it = birth_map_.begin(); 312 for (BirthMap::const_iterator it = birth_map_.begin();
315 it != birth_map_.end(); ++it) 313 it != birth_map_.end(); ++it)
316 (*output)[it->first] = it->second; 314 (*output)[it->first] = it->second;
317 } 315 }
318 316
319 // This may be called from another thread. 317 // This may be called from another thread.
320 void ThreadData::SnapshotDeathMap(DeathMap *output) const { 318 void ThreadData::SnapshotDeathMap(DeathMap *output) const {
321 base::AutoLock lock(lock_); 319 base::AutoLock lock(lock_);
322 for (DeathMap::const_iterator it = death_map_.begin(); 320 for (DeathMap::const_iterator it = death_map_.begin();
323 it != death_map_.end(); ++it) 321 it != death_map_.end(); ++it)
324 (*output)[it->first] = it->second; 322 (*output)[it->first] = it->second;
325 } 323 }
326 324
327 // static 325 // static
328 void ThreadData::ResetAllThreadData() { 326 void ThreadData::ResetAllThreadData() {
329 ThreadData* my_list = ThreadData::current()->first(); 327 ThreadData* my_list = ThreadData::FactoryGet(NULL)->first();
330 328
331 for (ThreadData* thread_data = my_list; 329 for (ThreadData* thread_data = my_list;
332 thread_data; 330 thread_data;
333 thread_data = thread_data->next()) 331 thread_data = thread_data->next())
334 thread_data->Reset(); 332 thread_data->Reset();
335 } 333 }
336 334
337 void ThreadData::Reset() { 335 void ThreadData::Reset() {
338 base::AutoLock lock(lock_); 336 base::AutoLock lock(lock_);
339 for (DeathMap::iterator it = death_map_.begin(); 337 for (DeathMap::iterator it = death_map_.begin();
340 it != death_map_.end(); ++it) 338 it != death_map_.end(); ++it)
341 it->second.Clear(); 339 it->second.Clear();
342 for (BirthMap::iterator it = birth_map_.begin(); 340 for (BirthMap::iterator it = birth_map_.begin();
343 it != birth_map_.end(); ++it) 341 it != birth_map_.end(); ++it)
344 it->second->Clear(); 342 it->second->Clear();
345 } 343 }
346 344
347 #ifdef OS_WIN
348 // A class used to count down which is accessed by several threads. This is
jar (doing other things) 2011/10/14 02:29:53 We no longer do any terminaition cleanup... so all
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());
jar (doing other things) 2011/10/14 02:29:53 Since we don't do this racy cleanup attempt, we do
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 345 // static
445 bool ThreadData::StartTracking(bool status) { 346 bool ThreadData::StartTracking(bool status) {
446 #if !defined(TRACK_ALL_TASK_OBJECTS) 347 #if !defined(TRACK_ALL_TASK_OBJECTS)
447 return false; // Not compiled in. 348 return false; // Not compiled in.
448 #endif 349 #endif
449 350
450 if (!status) { 351 if (!status) {
451 base::AutoLock lock(list_lock_); 352 base::AutoLock lock(list_lock_);
452 DCHECK(status_ == ACTIVE || status_ == SHUTDOWN); 353 DCHECK(status_ == ACTIVE || status_ == SHUTDOWN);
453 status_ = SHUTDOWN; 354 status_ = SHUTDOWN;
454 return true; 355 return true;
455 } 356 }
456 base::AutoLock lock(list_lock_); 357 base::AutoLock lock(list_lock_);
457 DCHECK_EQ(UNINITIALIZED, status_); 358 DCHECK_EQ(UNINITIALIZED, status_);
458 CHECK(tls_index_.Initialize(NULL)); 359 CHECK(tls_index_.Initialize(NULL));
459 status_ = ACTIVE; 360 status_ = ACTIVE;
460 return true; 361 return true;
461 } 362 }
462 363
463 // static 364 // static
464 bool ThreadData::IsActive() { 365 bool ThreadData::IsActive() {
465 return status_ == ACTIVE; 366 return status_ == ACTIVE;
466 } 367 }
467 368
468 #ifdef OS_WIN
469 // static 369 // static
470 void ThreadData::ShutdownMultiThreadTracking() { 370 base::TimeTicks ThreadData::Now() {
471 // Using lock, guarantee that no new ThreadData instances will be created. 371 #if defined(TRACK_ALL_TASK_OBJECTS)
472 if (!StartTracking(false)) 372 if (status_ == ACTIVE)
473 return; 373 return base::TimeTicks::Now();
474 374 #endif
475 RunOnAllThreads(ShutdownDisablingFurtherTracking); 375 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 } 376 }
485 #endif
486 377
487 // static 378 // static
488 void ThreadData::ShutdownSingleThreadedCleanup() { 379 void ThreadData::ShutdownSingleThreadedCleanup() {
380 NOTREACHED();
jar (doing other things) 2011/10/14 15:48:42 This has to be removed. This code is used is sing
489 // We must be single threaded... but be careful anyway. 381 // We must be single threaded... but be careful anyway.
490 if (!StartTracking(false)) 382 if (!StartTracking(false))
491 return; 383 return;
492 ThreadData* thread_data_list; 384 ThreadData* thread_data_list;
493 { 385 {
494 base::AutoLock lock(list_lock_); 386 base::AutoLock lock(list_lock_);
495 thread_data_list = first_; 387 thread_data_list = first_;
496 first_ = NULL; 388 first_ = NULL;
497 } 389 }
498 390
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
534 } 426 }
535 427
536 Snapshot::Snapshot(const BirthOnThread& birth_on_thread, int count) 428 Snapshot::Snapshot(const BirthOnThread& birth_on_thread, int count)
537 : birth_(&birth_on_thread), 429 : birth_(&birth_on_thread),
538 death_thread_(NULL), 430 death_thread_(NULL),
539 death_data_(DeathData(count)) { 431 death_data_(DeathData(count)) {
540 } 432 }
541 433
542 const std::string Snapshot::DeathThreadName() const { 434 const std::string Snapshot::DeathThreadName() const {
543 if (death_thread_) 435 if (death_thread_)
544 return death_thread_->ThreadName(); 436 return death_thread_->thread_name();
545 return "Still_Alive"; 437 return "Still_Alive";
546 } 438 }
547 439
548 void Snapshot::Write(std::string* output) const { 440 void Snapshot::Write(std::string* output) const {
549 death_data_.Write(output); 441 death_data_.Write(output);
550 base::StringAppendF(output, "%s->%s ", 442 base::StringAppendF(output, "%s->%s ",
551 birth_->birth_thread()->ThreadName().c_str(), 443 birth_->birth_thread()->thread_name().c_str(),
552 death_thread_->ThreadName().c_str()); 444 death_thread_->thread_name().c_str());
553 birth_->location().Write(true, true, output); 445 birth_->location().Write(true, true, output);
554 } 446 }
555 447
556 void Snapshot::Add(const Snapshot& other) { 448 void Snapshot::Add(const Snapshot& other) {
557 death_data_.AddDeathData(other.death_data_); 449 death_data_.AddDeathData(other.death_data_);
558 } 450 }
559 451
560 //------------------------------------------------------------------------------ 452 //------------------------------------------------------------------------------
561 // DataCollector 453 // DataCollector
562 454
563 DataCollector::DataCollector() { 455 DataCollector::DataCollector() {
564 DCHECK(ThreadData::IsActive()); 456 DCHECK(ThreadData::IsActive());
565 457
566 // Get an unchanging copy of a ThreadData list. 458 // Get an unchanging copy of a ThreadData list.
567 ThreadData* my_list = ThreadData::current()->first(); 459 ThreadData* my_list = ThreadData::FactoryGet(NULL)->first();
568 460
569 count_of_contributing_threads_ = 0; 461 count_of_contributing_threads_ = 0;
570 for (ThreadData* thread_data = my_list; 462 for (ThreadData* thread_data = my_list;
571 thread_data; 463 thread_data;
572 thread_data = thread_data->next()) { 464 thread_data = thread_data->next()) {
573 ++count_of_contributing_threads_; 465 ++count_of_contributing_threads_;
574 } 466 }
575 467
576 // Gather data serially. A different constructor could be used to do in 468 // Gather data serially.
577 // parallel, and then invoke an OnCompletion task.
578 // This hackish approach *can* get some slighly corrupt tallies, as we are 469 // 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 470 // 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 471 // 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 472 // sees any strangeness, they can always just run their stats gathering a
582 // second time. 473 // 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; 474 for (ThreadData* thread_data = my_list;
587 thread_data; 475 thread_data;
588 thread_data = thread_data->next()) { 476 thread_data = thread_data->next()) {
589 Append(*thread_data); 477 Append(*thread_data);
590 } 478 }
591 } 479 }
592 480
593 DataCollector::~DataCollector() { 481 DataCollector::~DataCollector() {
594 } 482 }
595 483
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
674 base::StringAppendF(output, "All born in %s. ", 562 base::StringAppendF(output, "All born in %s. ",
675 birth_files_.begin()->first.c_str()); 563 birth_files_.begin()->first.c_str());
676 } 564 }
677 } 565 }
678 566
679 if (birth_threads_.size() > 1) { 567 if (birth_threads_.size() > 1) {
680 base::StringAppendF(output, "%" PRIuS " BirthingThreads. ", 568 base::StringAppendF(output, "%" PRIuS " BirthingThreads. ",
681 birth_threads_.size()); 569 birth_threads_.size());
682 } else { 570 } else {
683 base::StringAppendF(output, "All born on %s. ", 571 base::StringAppendF(output, "All born on %s. ",
684 birth_threads_.begin()->first->ThreadName().c_str()); 572 birth_threads_.begin()->first->thread_name().c_str());
685 } 573 }
686 574
687 if (death_threads_.size() > 1) { 575 if (death_threads_.size() > 1) {
688 base::StringAppendF(output, "%" PRIuS " DeathThreads. ", 576 base::StringAppendF(output, "%" PRIuS " DeathThreads. ",
689 death_threads_.size()); 577 death_threads_.size());
690 } else { 578 } else {
691 if (death_threads_.begin()->first) { 579 if (death_threads_.begin()->first) {
692 base::StringAppendF(output, "All deleted on %s. ", 580 base::StringAppendF(output, "All deleted on %s. ",
693 death_threads_.begin()->first->ThreadName().c_str()); 581 death_threads_.begin()->first->thread_name().c_str());
694 } else { 582 } else {
695 output->append("All these objects are still alive."); 583 output->append("All these objects are still alive.");
696 } 584 }
697 } 585 }
698 586
699 if (birth_count_ > 1) 587 if (birth_count_ > 1)
700 base::StringAppendF(output, "Births=%d ", birth_count_); 588 base::StringAppendF(output, "Births=%d ", birth_count_);
701 589
702 DeathData::Write(output); 590 DeathData::Write(output);
703 } 591 }
(...skipping 24 matching lines...) Expand all
728 } 616 }
729 use_tiebreaker_for_sort_only_ = false; 617 use_tiebreaker_for_sort_only_ = false;
730 selector_ = NIL; 618 selector_ = NIL;
731 } 619 }
732 620
733 bool Comparator::operator()(const Snapshot& left, 621 bool Comparator::operator()(const Snapshot& left,
734 const Snapshot& right) const { 622 const Snapshot& right) const {
735 switch (selector_) { 623 switch (selector_) {
736 case BIRTH_THREAD: 624 case BIRTH_THREAD:
737 if (left.birth_thread() != right.birth_thread() && 625 if (left.birth_thread() != right.birth_thread() &&
738 left.birth_thread()->ThreadName() != 626 left.birth_thread()->thread_name() !=
739 right.birth_thread()->ThreadName()) 627 right.birth_thread()->thread_name())
740 return left.birth_thread()->ThreadName() < 628 return left.birth_thread()->thread_name() <
741 right.birth_thread()->ThreadName(); 629 right.birth_thread()->thread_name();
742 break; 630 break;
743 631
744 case DEATH_THREAD: 632 case DEATH_THREAD:
745 if (left.death_thread() != right.death_thread() && 633 if (left.death_thread() != right.death_thread() &&
746 left.DeathThreadName() != 634 left.DeathThreadName() !=
747 right.DeathThreadName()) { 635 right.DeathThreadName()) {
748 if (!left.death_thread()) 636 if (!left.death_thread())
749 return true; 637 return true;
750 if (!right.death_thread()) 638 if (!right.death_thread())
751 return false; 639 return false;
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
783 return left.count() > right.count(); // Sort large at front of vector. 671 return left.count() > right.count(); // Sort large at front of vector.
784 break; 672 break;
785 673
786 case AVERAGE_DURATION: 674 case AVERAGE_DURATION:
787 if (!left.count() || !right.count()) 675 if (!left.count() || !right.count())
788 break; 676 break;
789 if (left.AverageMsDuration() != right.AverageMsDuration()) 677 if (left.AverageMsDuration() != right.AverageMsDuration())
790 return left.AverageMsDuration() > right.AverageMsDuration(); 678 return left.AverageMsDuration() > right.AverageMsDuration();
791 break; 679 break;
792 680
681 case TOTAL_DURATION:
682 if (!left.count() || !right.count())
683 break;
684 if (left.life_duration() != right.life_duration())
685 return left.life_duration() > right.life_duration();
686 break;
687
793 default: 688 default:
794 break; 689 break;
795 } 690 }
796 if (tiebreaker_) 691 if (tiebreaker_)
797 return tiebreaker_->operator()(left, right); 692 return tiebreaker_->operator()(left, right);
798 return false; 693 return false;
799 } 694 }
800 695
801 void Comparator::Sort(DataCollector::Collection* collection) const { 696 void Comparator::Sort(DataCollector::Collection* collection) const {
802 std::sort(collection->begin(), collection->end(), *this); 697 std::sort(collection->begin(), collection->end(), *this);
803 } 698 }
804 699
805 bool Comparator::Equivalent(const Snapshot& left, 700 bool Comparator::Equivalent(const Snapshot& left,
806 const Snapshot& right) const { 701 const Snapshot& right) const {
807 switch (selector_) { 702 switch (selector_) {
808 case BIRTH_THREAD: 703 case BIRTH_THREAD:
809 if (left.birth_thread() != right.birth_thread() && 704 if (left.birth_thread() != right.birth_thread() &&
810 left.birth_thread()->ThreadName() != 705 left.birth_thread()->thread_name() !=
811 right.birth_thread()->ThreadName()) 706 right.birth_thread()->thread_name())
812 return false; 707 return false;
813 break; 708 break;
814 709
815 case DEATH_THREAD: 710 case DEATH_THREAD:
816 if (left.death_thread() != right.death_thread() && 711 if (left.death_thread() != right.death_thread() &&
817 left.DeathThreadName() != right.DeathThreadName()) 712 left.DeathThreadName() != right.DeathThreadName())
818 return false; 713 return false;
819 break; 714 break;
820 715
821 case BIRTH_FILE: 716 case BIRTH_FILE:
822 if (left.location().file_name() != right.location().file_name()) { 717 if (left.location().file_name() != right.location().file_name()) {
823 int comp = strcmp(left.location().file_name(), 718 int comp = strcmp(left.location().file_name(),
824 right.location().file_name()); 719 right.location().file_name());
825 if (comp) 720 if (comp)
826 return false; 721 return false;
827 } 722 }
828 break; 723 break;
829 724
830 case BIRTH_FUNCTION: 725 case BIRTH_FUNCTION:
831 if (left.location().function_name() != right.location().function_name()) { 726 if (left.location().function_name() != right.location().function_name()) {
832 int comp = strcmp(left.location().function_name(), 727 int comp = strcmp(left.location().function_name(),
833 right.location().function_name()); 728 right.location().function_name());
834 if (comp) 729 if (comp)
835 return false; 730 return false;
836 } 731 }
837 break; 732 break;
838 733
839 case COUNT: 734 case COUNT:
840 if (left.count() != right.count())
jar (doing other things) 2011/10/14 02:29:53 I decided it was stupid to aggregate groups of res
841 return false;
842 break;
843
844 case AVERAGE_DURATION: 735 case AVERAGE_DURATION:
845 if (left.life_duration() != right.life_duration()) 736 case TOTAL_DURATION:
846 return false; 737 // We don't produce separate aggretation when only counts or times differ.
847 break; 738 break;
848 739
849 default: 740 default:
850 break; 741 break;
851 } 742 }
852 if (tiebreaker_ && !use_tiebreaker_for_sort_only_) 743 if (tiebreaker_ && !use_tiebreaker_for_sort_only_)
853 return tiebreaker_->Equivalent(left, right); 744 return tiebreaker_->Equivalent(left, right);
854 return true; 745 return true;
855 } 746 }
856 747
857 bool Comparator::Acceptable(const Snapshot& sample) const { 748 bool Comparator::Acceptable(const Snapshot& sample) const {
858 if (required_.size()) { 749 if (required_.size()) {
859 switch (selector_) { 750 switch (selector_) {
860 case BIRTH_THREAD: 751 case BIRTH_THREAD:
861 if (sample.birth_thread()->ThreadName().find(required_) == 752 if (sample.birth_thread()->thread_name().find(required_) ==
862 std::string::npos) 753 std::string::npos)
863 return false; 754 return false;
864 break; 755 break;
865 756
866 case DEATH_THREAD: 757 case DEATH_THREAD:
867 if (sample.DeathThreadName().find(required_) == std::string::npos) 758 if (sample.DeathThreadName().find(required_) == std::string::npos)
868 return false; 759 return false;
869 break; 760 break;
870 761
871 case BIRTH_FILE: 762 case BIRTH_FILE:
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
927 } 818 }
928 819
929 void Comparator::ParseKeyphrase(const std::string& key_phrase) { 820 void Comparator::ParseKeyphrase(const std::string& key_phrase) {
930 typedef std::map<const std::string, Selector> KeyMap; 821 typedef std::map<const std::string, Selector> KeyMap;
931 static KeyMap key_map; 822 static KeyMap key_map;
932 static bool initialized = false; 823 static bool initialized = false;
933 if (!initialized) { 824 if (!initialized) {
934 initialized = true; 825 initialized = true;
935 // Sorting and aggretation keywords, which specify how to sort the data, or 826 // 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. 827 // can specify a required match from the specified field in the record.
937 key_map["count"] = COUNT; 828 key_map["count"] = COUNT;
938 key_map["duration"] = AVERAGE_DURATION; 829 key_map["totalduration"] = TOTAL_DURATION;
939 key_map["birth"] = BIRTH_THREAD; 830 key_map["duration"] = AVERAGE_DURATION;
940 key_map["death"] = DEATH_THREAD; 831 key_map["birth"] = BIRTH_THREAD;
941 key_map["file"] = BIRTH_FILE; 832 key_map["death"] = DEATH_THREAD;
942 key_map["function"] = BIRTH_FUNCTION; 833 key_map["file"] = BIRTH_FILE;
943 key_map["line"] = BIRTH_LINE; 834 key_map["function"] = BIRTH_FUNCTION;
835 key_map["line"] = BIRTH_LINE;
944 836
945 // Immediate commands that do not involve setting sort order. 837 // Immediate commands that do not involve setting sort order.
946 key_map["reset"] = RESET_ALL_DATA; 838 key_map["reset"] = RESET_ALL_DATA;
947 } 839 }
948 840
949 std::string required; 841 std::string required;
950 // Watch for: "sort_key=value" as we parse. 842 // Watch for: "sort_key=value" as we parse.
951 size_t equal_offset = key_phrase.find('=', 0); 843 size_t equal_offset = key_phrase.find('=', 0);
952 if (key_phrase.npos != equal_offset) { 844 if (key_phrase.npos != equal_offset) {
953 // There is a value that must be matched for the data to display. 845 // 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();) { 861 for (size_t i = 0; i < query.size();) {
970 size_t slash_offset = query.find('/', i); 862 size_t slash_offset = query.find('/', i);
971 ParseKeyphrase(query.substr(i, slash_offset - i)); 863 ParseKeyphrase(query.substr(i, slash_offset - i));
972 if (query.npos == slash_offset) 864 if (query.npos == slash_offset)
973 break; 865 break;
974 i = slash_offset + 1; 866 i = slash_offset + 1;
975 } 867 }
976 868
977 // Select subgroup ordering (if we want to display the subgroup) 869 // Select subgroup ordering (if we want to display the subgroup)
978 SetSubgroupTiebreaker(COUNT); 870 SetSubgroupTiebreaker(COUNT);
871 SetSubgroupTiebreaker(TOTAL_DURATION);
979 SetSubgroupTiebreaker(AVERAGE_DURATION); 872 SetSubgroupTiebreaker(AVERAGE_DURATION);
980 SetSubgroupTiebreaker(BIRTH_THREAD); 873 SetSubgroupTiebreaker(BIRTH_THREAD);
981 SetSubgroupTiebreaker(DEATH_THREAD); 874 SetSubgroupTiebreaker(DEATH_THREAD);
982 SetSubgroupTiebreaker(BIRTH_FUNCTION); 875 SetSubgroupTiebreaker(BIRTH_FUNCTION);
983 SetSubgroupTiebreaker(BIRTH_FILE); 876 SetSubgroupTiebreaker(BIRTH_FILE);
984 SetSubgroupTiebreaker(BIRTH_LINE); 877 SetSubgroupTiebreaker(BIRTH_LINE);
985 878
986 return true; 879 return true;
987 } 880 }
988 881
989 bool Comparator::WriteSortGrouping(const Snapshot& sample, 882 bool Comparator::WriteSortGrouping(const Snapshot& sample,
990 std::string* output) const { 883 std::string* output) const {
991 bool wrote_data = false; 884 bool wrote_data = false;
992 switch (selector_) { 885 switch (selector_) {
993 case BIRTH_THREAD: 886 case BIRTH_THREAD:
994 base::StringAppendF(output, "All new on %s ", 887 base::StringAppendF(output, "All new on %s ",
995 sample.birth_thread()->ThreadName().c_str()); 888 sample.birth_thread()->thread_name().c_str());
996 wrote_data = true; 889 wrote_data = true;
997 break; 890 break;
998 891
999 case DEATH_THREAD: 892 case DEATH_THREAD:
1000 if (sample.death_thread()) { 893 if (sample.death_thread()) {
1001 base::StringAppendF(output, "All deleted on %s ", 894 base::StringAppendF(output, "All deleted on %s ",
1002 sample.DeathThreadName().c_str()); 895 sample.DeathThreadName().c_str());
1003 } else { 896 } else {
1004 output->append("All still alive "); 897 output->append("All still alive ");
1005 } 898 }
(...skipping 20 matching lines...) Expand all
1026 return wrote_data; 919 return wrote_data;
1027 } 920 }
1028 921
1029 void Comparator::WriteSnapshot(const Snapshot& sample, 922 void Comparator::WriteSnapshot(const Snapshot& sample,
1030 std::string* output) const { 923 std::string* output) const {
1031 sample.death_data().Write(output); 924 sample.death_data().Write(output);
1032 if (!(combined_selectors_ & BIRTH_THREAD) || 925 if (!(combined_selectors_ & BIRTH_THREAD) ||
1033 !(combined_selectors_ & DEATH_THREAD)) 926 !(combined_selectors_ & DEATH_THREAD))
1034 base::StringAppendF(output, "%s->%s ", 927 base::StringAppendF(output, "%s->%s ",
1035 (combined_selectors_ & BIRTH_THREAD) ? "*" : 928 (combined_selectors_ & BIRTH_THREAD) ? "*" :
1036 sample.birth().birth_thread()->ThreadName().c_str(), 929 sample.birth().birth_thread()->thread_name().c_str(),
1037 (combined_selectors_ & DEATH_THREAD) ? "*" : 930 (combined_selectors_ & DEATH_THREAD) ? "*" :
1038 sample.DeathThreadName().c_str()); 931 sample.DeathThreadName().c_str());
1039 sample.birth().location().Write(!(combined_selectors_ & BIRTH_FILE), 932 sample.birth().location().Write(!(combined_selectors_ & BIRTH_FILE),
1040 !(combined_selectors_ & BIRTH_FUNCTION), 933 !(combined_selectors_ & BIRTH_FUNCTION),
1041 output); 934 output);
1042 } 935 }
1043 936
1044 } // namespace tracked_objects 937 } // namespace tracked_objects
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698