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

Side by Side Diff: base/tracked_objects.cc

Issue 8391019: Fully enable about:tracking by default (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 9 years, 1 month 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 namespace {
20 // Flag to compile out almost all of the task tracking code.
21 static const bool kTrackAllTaskObjects = true;
19 22
20 #if defined(TRACK_ALL_TASK_OBJECTS) 23 // When ThreadData is first initialized, should we start in an ACTIVE state to
21 static const bool kTrackAllTaskObjects = true; 24 // record all of the startup-time tasks, or should we start up DEACTIVATED, so
22 #else 25 // that we only record after parsing the command line flag --enable-tracking.
23 static const bool kTrackAllTaskObjects = false; 26 // Note that the flag may force either state, so this really controls only the
24 #endif 27 // period of time up until that flag is parsed. If there is no flag seen, then
25 28 // this state may prevail for much or all of the process lifetime.
26 // Can we count on thread termination to call for thread cleanup? If not, then 29 static const ThreadData::Status kInitialStartupState = ThreadData::ACTIVE;
27 // we can't risk putting references to ThreadData in TLS, as it will leak on 30 } // anonymous namespace.
28 // worker thread termination.
29 static const bool kWorkerThreadCleanupSupported = true;
30
31 // A TLS slot which points to the ThreadData instance for the current thread. We
32 // do a fake initialization here (zeroing out data), and then the real in-place
33 // construction happens when we call tls_index_.Initialize().
34 // static
35 base::ThreadLocalStorage::Slot ThreadData::tls_index_(base::LINKER_INITIALIZED);
36
37 // A global state variable to prevent repeated initialization during tests.
38 // static
39 AutoTracking::State AutoTracking::state_ = AutoTracking::kNeverBeenRun;
40
41 // A locked protected counter to assign sequence number to threads.
42 // static
43 int ThreadData::thread_number_counter_ = 0;
44 31
45 //------------------------------------------------------------------------------ 32 //------------------------------------------------------------------------------
46 // Death data tallies durations when a death takes place. 33 // Death data tallies durations when a death takes place.
47 34
48 void DeathData::RecordDeath(const TimeDelta& queue_duration, 35 void DeathData::RecordDeath(const Duration& queue_duration,
49 const TimeDelta& run_duration) { 36 const Duration& run_duration) {
50 ++count_; 37 ++count_;
51 queue_duration_ += queue_duration; 38 queue_duration_ += queue_duration;
52 run_duration_ += run_duration; 39 run_duration_ += run_duration;
53 } 40 }
54 41
55 int DeathData::AverageMsRunDuration() const { 42 int DeathData::AverageMsRunDuration() const {
56 if (run_duration_ == base::TimeDelta()) 43 if (run_duration_ == Duration() || !count_)
57 return 0; 44 return 0;
58 return static_cast<int>(run_duration_.InMilliseconds() / count_); 45 // Add half of denominator to achieve rounding.
46 return static_cast<int>(run_duration_.InMilliseconds() + count_ / 2) /
47 count_;
59 } 48 }
60 49
61 int DeathData::AverageMsQueueDuration() const { 50 int DeathData::AverageMsQueueDuration() const {
62 if (queue_duration_ == base::TimeDelta()) 51 if (queue_duration_ == Duration() || !count_)
63 return 0; 52 return 0;
64 return static_cast<int>(queue_duration_.InMilliseconds() / count_); 53 // Add half of denominator to achieve rounding.
54 return (static_cast<int>(queue_duration_.InMilliseconds() + count_ / 2) /
55 count_);
65 } 56 }
66 57
67 void DeathData::AddDeathData(const DeathData& other) { 58 void DeathData::AddDeathData(const DeathData& other) {
68 count_ += other.count_; 59 count_ += other.count_;
69 queue_duration_ += other.queue_duration_; 60 queue_duration_ += other.queue_duration_;
70 run_duration_ += other.run_duration_; 61 run_duration_ += other.run_duration_;
71 } 62 }
72 63
73 void DeathData::WriteHTML(std::string* output) const { 64 void DeathData::WriteHTML(std::string* output) const {
74 if (!count_) 65 if (!count_)
75 return; 66 return;
76 base::StringAppendF(output, "%s:%d, ", 67 base::StringAppendF(output, "%s:%d, ",
77 (count_ == 1) ? "Life" : "Lives", count_); 68 (count_ == 1) ? "Life" : "Lives", count_);
78 base::StringAppendF(output, "Run:%"PRId64"ms(%dms/life) ", 69 // Be careful to leave static_casts intact, as the type returned by
79 run_duration_.InMilliseconds(), 70 // InMilliseconds() may not always be an int, even if it can generally fit
71 // into an int.
72 base::StringAppendF(output, "Run:%dms(%dms/life) ",
73 static_cast<int>(run_duration_.InMilliseconds()),
80 AverageMsRunDuration()); 74 AverageMsRunDuration());
81 base::StringAppendF(output, "Queue:%"PRId64"ms(%dms/life) ", 75 base::StringAppendF(output, "Queue:%dms(%dms/life) ",
82 queue_duration_.InMilliseconds(), 76 static_cast<int>(queue_duration_.InMilliseconds()),
83 AverageMsQueueDuration()); 77 AverageMsQueueDuration());
84 } 78 }
85 79
86 base::DictionaryValue* DeathData::ToValue() const { 80 base::DictionaryValue* DeathData::ToValue() const {
87 base::DictionaryValue* dictionary = new base::DictionaryValue; 81 base::DictionaryValue* dictionary = new base::DictionaryValue;
88 dictionary->Set("count", base::Value::CreateIntegerValue(count_)); 82 dictionary->Set("count", base::Value::CreateIntegerValue(count_));
89 dictionary->Set("run_ms", 83 dictionary->Set("run_ms",
90 base::Value::CreateIntegerValue(run_duration_.InMilliseconds())); 84 base::Value::CreateIntegerValue(run_duration_.InMilliseconds()));
91 dictionary->Set("queue_ms", 85 dictionary->Set("queue_ms",
92 base::Value::CreateIntegerValue(queue_duration_.InMilliseconds())); 86 base::Value::CreateIntegerValue(queue_duration_.InMilliseconds()));
93 return dictionary; 87 return dictionary;
94 } 88 }
95 89
96 void DeathData::Clear() { 90 void DeathData::Clear() {
97 count_ = 0; 91 count_ = 0;
98 queue_duration_ = TimeDelta(); 92 queue_duration_ = Duration();
99 run_duration_ = TimeDelta(); 93 run_duration_ = Duration();
100 } 94 }
101 95
102 //------------------------------------------------------------------------------ 96 //------------------------------------------------------------------------------
103 BirthOnThread::BirthOnThread(const Location& location, 97 BirthOnThread::BirthOnThread(const Location& location,
104 const ThreadData& current) 98 const ThreadData& current)
105 : location_(location), 99 : location_(location),
106 birth_thread_(&current) {} 100 birth_thread_(&current) {}
107 101
108 //------------------------------------------------------------------------------ 102 //------------------------------------------------------------------------------
109 Births::Births(const Location& location, const ThreadData& current) 103 Births::Births(const Location& location, const ThreadData& current)
110 : BirthOnThread(location, current), 104 : BirthOnThread(location, current),
111 birth_count_(1) { } 105 birth_count_(1) { }
112 106
113 //------------------------------------------------------------------------------ 107 //------------------------------------------------------------------------------
114 // ThreadData maintains the central data for all births and deaths. 108 // ThreadData maintains the central data for all births and deaths.
115 109
110 // TODO(jar): We should pull all these static vars together, into a struct, and
111 // optimize layout so that we benefit from locality of reference during accesses
112 // to them.
113
114 // A TLS slot which points to the ThreadData instance for the current thread. We
115 // do a fake initialization here (zeroing out data), and then the real in-place
116 // construction happens when we call tls_index_.Initialize().
117 // static
118 base::ThreadLocalStorage::Slot ThreadData::tls_index_(base::LINKER_INITIALIZED);
119
120 // A lock-protected counter to assign sequence number to threads.
121 // static
122 int ThreadData::thread_number_counter_ = 0;
123
116 // static 124 // static
117 ThreadData* ThreadData::all_thread_data_list_head_ = NULL; 125 ThreadData* ThreadData::all_thread_data_list_head_ = NULL;
118 126
119 // static 127 // static
120 ThreadData::ThreadDataPool* ThreadData::unregistered_thread_data_pool_ = NULL; 128 ThreadData::ThreadDataPool* ThreadData::unregistered_thread_data_pool_ = NULL;
121 129
122 // static 130 // static
123 base::Lock ThreadData::list_lock_; 131 base::Lock* ThreadData::list_lock_;
124 132
125 // static 133 // static
126 ThreadData::Status ThreadData::status_ = ThreadData::UNINITIALIZED; 134 ThreadData::Status ThreadData::status_ = ThreadData::UNINITIALIZED;
127 135
128 ThreadData::ThreadData(const std::string& suggested_name) 136 ThreadData::ThreadData(const std::string& suggested_name)
129 : next_(NULL), 137 : next_(NULL),
130 is_a_worker_thread_(false) { 138 is_a_worker_thread_(false) {
131 DCHECK_GE(suggested_name.size(), 0u); 139 DCHECK_GE(suggested_name.size(), 0u);
132 thread_name_ = suggested_name; 140 thread_name_ = suggested_name;
133 PushToHeadOfList(); 141 PushToHeadOfList();
134 } 142 }
135 143
136 ThreadData::ThreadData() : next_(NULL), is_a_worker_thread_(true) { 144 ThreadData::ThreadData() : next_(NULL), is_a_worker_thread_(true) {
137 int thread_number; 145 int thread_number;
138 { 146 {
139 base::AutoLock lock(list_lock_); 147 base::AutoLock lock(*list_lock_);
140 thread_number = ++thread_number_counter_; 148 thread_number = ++thread_number_counter_;
141 } 149 }
142 base::StringAppendF(&thread_name_, "WorkerThread-%d", thread_number); 150 base::StringAppendF(&thread_name_, "WorkerThread-%d", thread_number);
143 PushToHeadOfList(); 151 PushToHeadOfList();
144 } 152 }
145 153
146 ThreadData::~ThreadData() {} 154 ThreadData::~ThreadData() {}
147 155
148 void ThreadData::PushToHeadOfList() { 156 void ThreadData::PushToHeadOfList() {
149 DCHECK(!next_); 157 DCHECK(!next_);
150 base::AutoLock lock(list_lock_); 158 base::AutoLock lock(*list_lock_);
151 next_ = all_thread_data_list_head_; 159 next_ = all_thread_data_list_head_;
152 all_thread_data_list_head_ = this; 160 all_thread_data_list_head_ = this;
153 } 161 }
154 162
155 // static 163 // static
156 void ThreadData::InitializeThreadContext(const std::string& suggested_name) { 164 void ThreadData::InitializeThreadContext(const std::string& suggested_name) {
157 if (!tls_index_.initialized()) 165 Initialize(); // Always initialize if needed.
ramant (doing other things) 2011/10/28 17:56:09 nit: if not initialized bail.
jar (doing other things) 2011/10/28 19:37:25 Done.
158 return; // For unittests only.
159 DCHECK_EQ(tls_index_.Get(), reinterpret_cast<void*>(NULL)); 166 DCHECK_EQ(tls_index_.Get(), reinterpret_cast<void*>(NULL));
160 ThreadData* current_thread_data = new ThreadData(suggested_name); 167 ThreadData* current_thread_data = new ThreadData(suggested_name);
161 tls_index_.Set(current_thread_data); 168 tls_index_.Set(current_thread_data);
162 } 169 }
163 170
164 // static 171 // static
165 ThreadData* ThreadData::Get() { 172 ThreadData* ThreadData::Get() {
166 if (!tls_index_.initialized()) 173 if (!tls_index_.initialized())
167 return NULL; // For unittests only. 174 return NULL; // For unittests only.
168 ThreadData* registered = reinterpret_cast<ThreadData*>(tls_index_.Get()); 175 ThreadData* registered = reinterpret_cast<ThreadData*>(tls_index_.Get());
169 if (registered) 176 if (registered)
170 return registered; 177 return registered;
171 178
172 // We must be a worker thread, since we didn't pre-register. 179 // We must be a worker thread, since we didn't pre-register.
173 ThreadData* worker_thread_data = NULL; 180 ThreadData* worker_thread_data = NULL;
174 { 181 {
175 base::AutoLock lock(list_lock_); 182 base::AutoLock lock(*list_lock_);
176 if (!unregistered_thread_data_pool_->empty()) { 183 if (!unregistered_thread_data_pool_->empty()) {
177 worker_thread_data = 184 worker_thread_data =
178 const_cast<ThreadData*>(unregistered_thread_data_pool_->top()); 185 const_cast<ThreadData*>(unregistered_thread_data_pool_->top());
179 unregistered_thread_data_pool_->pop(); 186 unregistered_thread_data_pool_->pop();
180 } 187 }
181 } 188 }
182 189
183 // If we can't find a previously used instance, then we have to create one. 190 // If we can't find a previously used instance, then we have to create one.
184 if (!worker_thread_data) 191 if (!worker_thread_data)
185 worker_thread_data = new ThreadData(); 192 worker_thread_data = new ThreadData();
(...skipping 10 matching lines...) Expand all
196 if (!thread_data) 203 if (!thread_data)
197 return; 204 return;
198 reinterpret_cast<ThreadData*>(thread_data)->OnThreadTerminationCleanup(); 205 reinterpret_cast<ThreadData*>(thread_data)->OnThreadTerminationCleanup();
199 DCHECK_EQ(tls_index_.Get(), reinterpret_cast<ThreadData*>(NULL)); 206 DCHECK_EQ(tls_index_.Get(), reinterpret_cast<ThreadData*>(NULL));
200 } 207 }
201 208
202 void ThreadData::OnThreadTerminationCleanup() const { 209 void ThreadData::OnThreadTerminationCleanup() const {
203 tls_index_.Set(NULL); 210 tls_index_.Set(NULL);
204 if (!is_a_worker_thread_) 211 if (!is_a_worker_thread_)
205 return; 212 return;
206 base::AutoLock lock(list_lock_); 213 base::AutoLock lock(*list_lock_);
207 unregistered_thread_data_pool_->push(this); 214 unregistered_thread_data_pool_->push(this);
208 } 215 }
209 216
210 // static 217 // static
211 void ThreadData::WriteHTML(const std::string& query, std::string* output) { 218 void ThreadData::WriteHTML(const std::string& query, std::string* output) {
212 if (!ThreadData::IsActive()) 219 if (!ThreadData::tracking_status())
213 return; // Not yet initialized. 220 return; // Not yet initialized.
214 221
215 DataCollector collected_data; // Gather data. 222 DataCollector collected_data; // Gather data.
216 collected_data.AddListOfLivingObjects(); // Add births that are still alive. 223 collected_data.AddListOfLivingObjects(); // Add births that are still alive.
217 224
218 // Data Gathering is complete. Now to sort/process/render. 225 // Data Gathering is complete. Now to sort/process/render.
219 DataCollector::Collection* collection = collected_data.collection(); 226 DataCollector::Collection* collection = collected_data.collection();
220 227
221 // Create filtering and sort comparison object. 228 // Create filtering and sort comparison object.
222 Comparator comparator; 229 Comparator comparator;
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
309 // Print aggregate stats for the group. 316 // Print aggregate stats for the group.
310 output->append("<br>"); 317 output->append("<br>");
311 subtotals.WriteHTML(output); 318 subtotals.WriteHTML(output);
312 output->append("<br><hr><br>"); 319 output->append("<br><hr><br>");
313 subtotals.Clear(); 320 subtotals.Clear();
314 } 321 }
315 } 322 }
316 } 323 }
317 324
318 // static 325 // static
319 base::Value* ThreadData::ToValue(int process_type) { 326 base::DictionaryValue* ThreadData::ToValue() {
320 DataCollector collected_data; // Gather data. 327 DataCollector collected_data; // Gather data.
321 collected_data.AddListOfLivingObjects(); // Add births that are still alive. 328 collected_data.AddListOfLivingObjects(); // Add births that are still alive.
322 base::ListValue* list = collected_data.ToValue(); 329 base::ListValue* list = collected_data.ToValue();
323 base::DictionaryValue* dictionary = new base::DictionaryValue(); 330 base::DictionaryValue* dictionary = new base::DictionaryValue();
324 dictionary->Set("list", list); 331 dictionary->Set("list", list);
325 dictionary->SetInteger("process", process_type);
326 return dictionary; 332 return dictionary;
327 } 333 }
328 334
329 Births* ThreadData::TallyABirth(const Location& location) { 335 Births* ThreadData::TallyABirth(const Location& location) {
330 BirthMap::iterator it = birth_map_.find(location); 336 BirthMap::iterator it = birth_map_.find(location);
331 if (it != birth_map_.end()) { 337 if (it != birth_map_.end()) {
332 it->second->RecordBirth(); 338 it->second->RecordBirth();
333 return it->second; 339 return it->second;
334 } 340 }
335 341
336 Births* tracker = new Births(location, *this); 342 Births* tracker = new Births(location, *this);
337 // Lock since the map may get relocated now, and other threads sometimes 343 // Lock since the map may get relocated now, and other threads sometimes
338 // snapshot it (but they lock before copying it). 344 // snapshot it (but they lock before copying it).
339 base::AutoLock lock(lock_); 345 base::AutoLock lock(lock_);
340 birth_map_[location] = tracker; 346 birth_map_[location] = tracker;
341 return tracker; 347 return tracker;
342 } 348 }
343 349
344 void ThreadData::TallyADeath(const Births& birth, 350 void ThreadData::TallyADeath(const Births& birth,
345 const TimeDelta& queue_duration, 351 const Duration& queue_duration,
346 const TimeDelta& run_duration) { 352 const Duration& run_duration) {
347 DeathMap::iterator it = death_map_.find(&birth); 353 DeathMap::iterator it = death_map_.find(&birth);
348 DeathData* death_data; 354 DeathData* death_data;
349 if (it != death_map_.end()) { 355 if (it != death_map_.end()) {
350 death_data = &it->second; 356 death_data = &it->second;
351 } else { 357 } else {
352 base::AutoLock lock(lock_); // Lock since the map may get relocated now. 358 base::AutoLock lock(lock_); // Lock since the map may get relocated now.
353 death_data = &death_map_[&birth]; 359 death_data = &death_map_[&birth];
354 } // Release lock ASAP. 360 } // Release lock ASAP.
355 death_data->RecordDeath(queue_duration, run_duration); 361 death_data->RecordDeath(queue_duration, run_duration);
356 } 362 }
357 363
358 // static 364 // static
359 Births* ThreadData::TallyABirthIfActive(const Location& location) { 365 Births* ThreadData::TallyABirthIfActive(const Location& location) {
360 if (!kTrackAllTaskObjects) 366 if (!kTrackAllTaskObjects)
361 return NULL; // Not compiled in. 367 return NULL; // Not compiled in.
362 368
363 if (!IsActive()) 369 if (!tracking_status())
364 return NULL; 370 return NULL;
365 ThreadData* current_thread_data = Get(); 371 ThreadData* current_thread_data = Get();
366 if (!current_thread_data) 372 if (!current_thread_data)
367 return NULL; 373 return NULL;
368 return current_thread_data->TallyABirth(location); 374 return current_thread_data->TallyABirth(location);
369 } 375 }
370 376
371 // static 377 // static
372 void ThreadData::TallyADeathIfActive(const Births* birth, 378 void ThreadData::TallyRunOnNamedThreadIfTracking(
373 const base::TimeTicks& time_posted, 379 const MessageLoop::TrackingInfo& completed_task,
374 const base::TimeTicks& delayed_start_time, 380 const TrackedTime& start_of_run,
375 const base::TimeTicks& start_of_run, 381 const TrackedTime& end_of_run) {
376 const base::TimeTicks& end_of_run) {
377 if (!kTrackAllTaskObjects) 382 if (!kTrackAllTaskObjects)
378 return; // Not compiled in. 383 return; // Not compiled in.
379 384
380 if (!IsActive() || !birth) 385 // Even if we have been DEACTIVATED, we will process any pending births so
386 // that our data structures (which counted the outstanding births) remain
387 // consistent.
388 const Births* birth = completed_task.birth_tally;
389 if (!birth)
381 return; 390 return;
382
383 ThreadData* current_thread_data = Get(); 391 ThreadData* current_thread_data = Get();
384 if (!current_thread_data) 392 if (!current_thread_data)
385 return; 393 return;
386 394
387 // To avoid conflating our stats with the delay duration in a PostDelayedTask, 395 // To avoid conflating our stats with the delay duration in a PostDelayedTask,
388 // we identify such tasks, and replace their post_time with the time they 396 // we identify such tasks, and replace their post_time with the time they
389 // were sechudled (requested?) to emerge from the delayed task queue. This 397 // were scheduled (requested?) to emerge from the delayed task queue. This
390 // means that queueing delay for such tasks will show how long they went 398 // means that queueing delay for such tasks will show how long they went
391 // unserviced, after they *could* be serviced. This is the same stat as we 399 // unserviced, after they *could* be serviced. This is the same stat as we
392 // have for non-delayed tasks, and we consistently call it queueing delay. 400 // have for non-delayed tasks, and we consistently call it queueing delay.
393 base::TimeTicks effective_post_time = 401 TrackedTime effective_post_time = completed_task.delayed_run_time.is_null()
394 (delayed_start_time.is_null()) ? time_posted : delayed_start_time; 402 ? tracked_objects::TrackedTime(completed_task.time_posted)
395 base::TimeDelta queue_duration = start_of_run - effective_post_time; 403 : tracked_objects::TrackedTime(completed_task.delayed_run_time);
396 base::TimeDelta run_duration = end_of_run - start_of_run; 404
405 Duration queue_duration = start_of_run - effective_post_time;
406 Duration run_duration = end_of_run - start_of_run;
407 current_thread_data->TallyADeath(*birth, queue_duration, run_duration);
408 }
409
410 // static
411 void ThreadData::TallyRunOnWorkerThreadIfTracking(
412 const Births* birth,
413 const TrackedTime& time_posted,
414 const TrackedTime& start_of_run,
415 const TrackedTime& end_of_run) {
416 if (!kTrackAllTaskObjects)
417 return; // Not compiled in.
418
419 // Even if we have been DEACTIVATED, we will process any pending births so
420 // that our data structures (which counted the outstanding births) remain
421 // consistent.
422 if (!birth)
423 return;
424
425 // TODO(jar): Support the option to coalesce all worker-thread activity under
426 // one ThreadData instance that uses locks to protect *all* access. This will
427 // reduce memory (making it provably bounded), but run incrementally slower
428 // (since we'll use locks on TallyBirth and TallyDeath). The good news is
429 // that the locks on TallyDeath will be *after* the worker thread has run, and
430 // hence nothing will be waiting for the completion (... besides some other
431 // thread that might like to run). Also, the worker threads tasks are
432 // generally longer, and hence the cost of the lock may perchance be amortized
433 // over the long task's lifetime.
434 ThreadData* current_thread_data = Get();
435 if (!current_thread_data)
436 return;
437
438 Duration queue_duration = start_of_run - time_posted;
439 Duration run_duration = end_of_run - start_of_run;
397 current_thread_data->TallyADeath(*birth, queue_duration, run_duration); 440 current_thread_data->TallyADeath(*birth, queue_duration, run_duration);
398 } 441 }
399 442
400 // static 443 // static
401 ThreadData* ThreadData::first() { 444 ThreadData* ThreadData::first() {
402 base::AutoLock lock(list_lock_); 445 base::AutoLock lock(*list_lock_);
403 return all_thread_data_list_head_; 446 return all_thread_data_list_head_;
404 } 447 }
405 448
406 // This may be called from another thread. 449 // This may be called from another thread.
407 void ThreadData::SnapshotBirthMap(BirthMap *output) const { 450 void ThreadData::SnapshotBirthMap(BirthMap *output) const {
408 base::AutoLock lock(lock_); 451 base::AutoLock lock(lock_);
409 for (BirthMap::const_iterator it = birth_map_.begin(); 452 for (BirthMap::const_iterator it = birth_map_.begin();
410 it != birth_map_.end(); ++it) 453 it != birth_map_.end(); ++it)
411 (*output)[it->first] = it->second; 454 (*output)[it->first] = it->second;
412 } 455 }
(...skipping 19 matching lines...) Expand all
432 void ThreadData::Reset() { 475 void ThreadData::Reset() {
433 base::AutoLock lock(lock_); 476 base::AutoLock lock(lock_);
434 for (DeathMap::iterator it = death_map_.begin(); 477 for (DeathMap::iterator it = death_map_.begin();
435 it != death_map_.end(); ++it) 478 it != death_map_.end(); ++it)
436 it->second.Clear(); 479 it->second.Clear();
437 for (BirthMap::iterator it = birth_map_.begin(); 480 for (BirthMap::iterator it = birth_map_.begin();
438 it != birth_map_.end(); ++it) 481 it != birth_map_.end(); ++it)
439 it->second->Clear(); 482 it->second->Clear();
440 } 483 }
441 484
485 void ThreadData::Initialize() {
486 if (status_ != UNINITIALIZED)
ramant (doing other things) 2011/10/28 17:56:09 nit: return false if not enabled.
jar (doing other things) 2011/10/28 19:37:25 Done.
487 return;
488 // Initialize all leaking constants that are difficult to toggle in and out
489 // of existance.
490 // First call must be made when single threaded at startup.
491 // Perform the "real" TLS initialization now, and leave it intact through
492 // process termination.
493 if (!tls_index_.initialized()) // Testing may have initialized this.
494 tls_index_.Initialize(&ThreadData::OnThreadTermination);
495 DCHECK(tls_index_.initialized());
496 unregistered_thread_data_pool_ = new ThreadDataPool;
497 // TODO(jar): A linker initialized spin lock would be much safer than this
498 // allocation, which relies on being called while single threaded.
499 if (!list_lock_) // In case testing deleted this.
500 list_lock_ = new base::Lock;
501 status_ = kInitialStartupState;
502 }
503
442 // static 504 // static
443 bool ThreadData::StartTracking(bool status) { 505 bool ThreadData::InitializeAndSetTrackingStatus(bool status) {
444 if (!kTrackAllTaskObjects) 506 if (!kTrackAllTaskObjects)
445 return false; // Not compiled in. 507 return false; // Not compiled in.
446 508
447 // Do a bit of class initialization. 509 if (status_ == UNINITIALIZED)
448 if (!unregistered_thread_data_pool_) { 510 Initialize();
449 ThreadDataPool* initial_pool = new ThreadDataPool;
450 {
451 base::AutoLock lock(list_lock_);
452 if (!unregistered_thread_data_pool_) {
453 unregistered_thread_data_pool_ = initial_pool;
454 initial_pool = NULL;
455 }
456 }
457 delete initial_pool; // In case it was not used.
458 }
459 511
460 // Perform the "real" initialization now, and leave it intact through 512 status_ = status ? ACTIVE : DEACTIVATED;
461 // process termination.
462 if (!tls_index_.initialized())
463 tls_index_.Initialize(&ThreadData::OnThreadTermination);
464 DCHECK(tls_index_.initialized());
465
466 if (!status) {
467 base::AutoLock lock(list_lock_);
468 DCHECK(status_ == ACTIVE || status_ == SHUTDOWN);
469 status_ = SHUTDOWN;
470 return true;
471 }
472 base::AutoLock lock(list_lock_);
473 DCHECK_EQ(UNINITIALIZED, status_);
474 status_ = ACTIVE;
475 return true; 513 return true;
476 } 514 }
477 515
478 // static 516 // static
479 bool ThreadData::IsActive() { 517 bool ThreadData::tracking_status() {
480 return status_ == ACTIVE; 518 return status_ == ACTIVE;
481 } 519 }
482 520
483 // static 521 // static
484 base::TimeTicks ThreadData::Now() { 522 TrackedTime ThreadData::Now() {
485 if (kTrackAllTaskObjects && status_ == ACTIVE) 523 if (!kTrackAllTaskObjects || status_ != ACTIVE)
486 return base::TimeTicks::Now(); 524 return TrackedTime(); // Super fast when disabled, or not compiled.
487 return base::TimeTicks(); // Super fast when disabled, or not compiled in. 525 return TrackedTime::Now();
488 } 526 }
489 527
490 // static 528 // static
491 void ThreadData::ShutdownSingleThreadedCleanup() { 529 void ThreadData::ShutdownSingleThreadedCleanup() {
492 // This is only called from test code, where we need to cleanup so that 530 // This is only called from test code, where we need to cleanup so that
493 // additional tests can be run. 531 // additional tests can be run.
494 // We must be single threaded... but be careful anyway. 532 // We must be single threaded... but be careful anyway.
495 if (!StartTracking(false)) 533 if (!InitializeAndSetTrackingStatus(false))
496 return; 534 return;
497 ThreadData* thread_data_list; 535 ThreadData* thread_data_list;
498 ThreadDataPool* final_pool; 536 ThreadDataPool* final_pool;
499 { 537 {
500 base::AutoLock lock(list_lock_); 538 base::AutoLock lock(*list_lock_);
501 thread_data_list = all_thread_data_list_head_; 539 thread_data_list = all_thread_data_list_head_;
502 all_thread_data_list_head_ = NULL; 540 all_thread_data_list_head_ = NULL;
503 final_pool = unregistered_thread_data_pool_; 541 final_pool = unregistered_thread_data_pool_;
504 unregistered_thread_data_pool_ = NULL; 542 unregistered_thread_data_pool_ = NULL;
505 } 543 }
506 544
507 if (final_pool) { 545 if (final_pool) {
508 // The thread_data_list contains *all* the instances, and we'll use it to 546 // The thread_data_list contains *all* the instances, and we'll use it to
509 // delete them. This pool has pointers to some instances, and we just 547 // delete them. This pool has pointers to some instances, and we just
510 // have to drop those pointers (and not do the deletes here). 548 // have to drop those pointers (and not do the deletes here).
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
567 base::DictionaryValue* dictionary = new base::DictionaryValue; 605 base::DictionaryValue* dictionary = new base::DictionaryValue;
568 dictionary->Set("death_data", death_data_.ToValue()); 606 dictionary->Set("death_data", death_data_.ToValue());
569 dictionary->Set("birth_thread", 607 dictionary->Set("birth_thread",
570 base::Value::CreateStringValue(birth_->birth_thread()->thread_name())); 608 base::Value::CreateStringValue(birth_->birth_thread()->thread_name()));
571 dictionary->Set("death_thread", 609 dictionary->Set("death_thread",
572 base::Value::CreateStringValue(DeathThreadName())); 610 base::Value::CreateStringValue(DeathThreadName()));
573 dictionary->Set("location", birth_->location().ToValue()); 611 dictionary->Set("location", birth_->location().ToValue());
574 return dictionary; 612 return dictionary;
575 } 613 }
576 614
577 void Snapshot::Add(const Snapshot& other) {
578 death_data_.AddDeathData(other.death_data_);
579 }
580
581 //------------------------------------------------------------------------------ 615 //------------------------------------------------------------------------------
582 // DataCollector 616 // DataCollector
583 617
584 DataCollector::DataCollector() { 618 DataCollector::DataCollector() {
585 if (!ThreadData::IsActive()) 619 if (!ThreadData::tracking_status())
586 return; 620 return;
587 621
588 // Get an unchanging copy of a ThreadData list. 622 // Get an unchanging copy of a ThreadData list.
589 ThreadData* my_list = ThreadData::first(); 623 ThreadData* my_list = ThreadData::first();
590 624
591 // Gather data serially. 625 // Gather data serially.
592 // This hackish approach *can* get some slighly corrupt tallies, as we are 626 // This hackish approach *can* get some slighly corrupt tallies, as we are
593 // grabbing values without the protection of a lock, but it has the advantage 627 // grabbing values without the protection of a lock, but it has the advantage
594 // of working even with threads that don't have message loops. If a user 628 // of working even with threads that don't have message loops. If a user
595 // sees any strangeness, they can always just run their stats gathering a 629 // sees any strangeness, they can always just run their stats gathering a
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after
733 void Comparator::Clear() { 767 void Comparator::Clear() {
734 if (tiebreaker_) { 768 if (tiebreaker_) {
735 tiebreaker_->Clear(); 769 tiebreaker_->Clear();
736 delete tiebreaker_; 770 delete tiebreaker_;
737 tiebreaker_ = NULL; 771 tiebreaker_ = NULL;
738 } 772 }
739 use_tiebreaker_for_sort_only_ = false; 773 use_tiebreaker_for_sort_only_ = false;
740 selector_ = NIL; 774 selector_ = NIL;
741 } 775 }
742 776
777 // static
778 Comparator::Selector Comparator::FindSelector(const std::string& keyword) {
779 // Sorting and aggretation keywords, which specify how to sort the data, or
780 // can specify a required match from the specified field in the record.
781 if (0 == keyword.compare("count"))
782 return COUNT;
783 if (0 == keyword.compare("totalduration"))
784 return TOTAL_RUN_DURATION;
785 if (0 == keyword.compare("duration"))
786 return AVERAGE_RUN_DURATION;
787 if (0 == keyword.compare("totalqueueduration"))
788 return TOTAL_QUEUE_DURATION;
789 if (0 == keyword.compare("averagequeueduration"))
790 return AVERAGE_QUEUE_DURATION;
791 if (0 == keyword.compare("birth"))
792 return BIRTH_THREAD;
793 if (0 == keyword.compare("death"))
794 return DEATH_THREAD;
795 if (0 == keyword.compare("file"))
796 return BIRTH_FILE;
797 if (0 == keyword.compare("function"))
798 return BIRTH_FUNCTION;
799 if (0 == keyword.compare("line"))
800 return BIRTH_LINE;
801 if (0 == keyword.compare("reset"))
802 return RESET_ALL_DATA;
803 return UNKNOWN_KEYWORD;
804 }
805
743 bool Comparator::operator()(const Snapshot& left, 806 bool Comparator::operator()(const Snapshot& left,
744 const Snapshot& right) const { 807 const Snapshot& right) const {
745 switch (selector_) { 808 switch (selector_) {
746 case BIRTH_THREAD: 809 case BIRTH_THREAD:
747 if (left.birth_thread() != right.birth_thread() && 810 if (left.birth_thread() != right.birth_thread() &&
748 left.birth_thread()->thread_name() != 811 left.birth_thread()->thread_name() !=
749 right.birth_thread()->thread_name()) 812 right.birth_thread()->thread_name())
750 return left.birth_thread()->thread_name() < 813 return left.birth_thread()->thread_name() <
751 right.birth_thread()->thread_name(); 814 right.birth_thread()->thread_name();
752 break; 815 break;
(...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after
949 if (!tiebreaker_) { 1012 if (!tiebreaker_) {
950 use_tiebreaker_for_sort_only_ = true; 1013 use_tiebreaker_for_sort_only_ = true;
951 tiebreaker_ = new Comparator; 1014 tiebreaker_ = new Comparator;
952 tiebreaker_->SetTiebreaker(selector, ""); 1015 tiebreaker_->SetTiebreaker(selector, "");
953 } else { 1016 } else {
954 tiebreaker_->SetSubgroupTiebreaker(selector); 1017 tiebreaker_->SetSubgroupTiebreaker(selector);
955 } 1018 }
956 } 1019 }
957 1020
958 void Comparator::ParseKeyphrase(const std::string& key_phrase) { 1021 void Comparator::ParseKeyphrase(const std::string& key_phrase) {
959 typedef std::map<const std::string, Selector> KeyMap;
960 static KeyMap key_map;
961 static bool initialized = false;
962 if (!initialized) {
963 initialized = true;
964 // Sorting and aggretation keywords, which specify how to sort the data, or
965 // can specify a required match from the specified field in the record.
966 key_map["count"] = COUNT;
967 key_map["totalduration"] = TOTAL_RUN_DURATION;
968 key_map["duration"] = AVERAGE_RUN_DURATION;
969 key_map["totalqueueduration"] = TOTAL_QUEUE_DURATION;
970 key_map["averagequeueduration"] = AVERAGE_QUEUE_DURATION;
971 key_map["birth"] = BIRTH_THREAD;
972 key_map["death"] = DEATH_THREAD;
973 key_map["file"] = BIRTH_FILE;
974 key_map["function"] = BIRTH_FUNCTION;
975 key_map["line"] = BIRTH_LINE;
976
977 // Immediate commands that do not involve setting sort order.
978 key_map["reset"] = RESET_ALL_DATA;
979 }
980
981 std::string required; 1022 std::string required;
982 // Watch for: "sort_key=value" as we parse. 1023 // Watch for: "sort_key=value" as we parse.
983 size_t equal_offset = key_phrase.find('=', 0); 1024 size_t equal_offset = key_phrase.find('=', 0);
984 if (key_phrase.npos != equal_offset) { 1025 if (key_phrase.npos != equal_offset) {
985 // There is a value that must be matched for the data to display. 1026 // There is a value that must be matched for the data to display.
986 required = key_phrase.substr(equal_offset + 1, key_phrase.npos); 1027 required = key_phrase.substr(equal_offset + 1, key_phrase.npos);
987 } 1028 }
988 std::string keyword(key_phrase.substr(0, equal_offset)); 1029 std::string keyword(key_phrase.substr(0, equal_offset));
989 keyword = StringToLowerASCII(keyword); 1030 keyword = StringToLowerASCII(keyword);
990 KeyMap::iterator it = key_map.find(keyword); 1031 Selector selector = FindSelector(keyword);
991 if (key_map.end() == it) 1032 if (selector == UNKNOWN_KEYWORD)
992 return; // Unknown keyword. 1033 return;
993 if (it->second == RESET_ALL_DATA) 1034 if (selector == RESET_ALL_DATA) {
994 ThreadData::ResetAllThreadData(); 1035 ThreadData::ResetAllThreadData();
995 else 1036 return;
996 SetTiebreaker(key_map[keyword], required); 1037 }
1038 SetTiebreaker(selector, required);
997 } 1039 }
998 1040
999 bool Comparator::ParseQuery(const std::string& query) { 1041 bool Comparator::ParseQuery(const std::string& query) {
1000 // Parse each keyphrase between consecutive slashes. 1042 // Parse each keyphrase between consecutive slashes.
1001 for (size_t i = 0; i < query.size();) { 1043 for (size_t i = 0; i < query.size();) {
1002 size_t slash_offset = query.find('/', i); 1044 size_t slash_offset = query.find('/', i);
1003 ParseKeyphrase(query.substr(i, slash_offset - i)); 1045 ParseKeyphrase(query.substr(i, slash_offset - i));
1004 if (query.npos == slash_offset) 1046 if (query.npos == slash_offset)
1005 break; 1047 break;
1006 i = slash_offset + 1; 1048 i = slash_offset + 1;
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
1068 (combined_selectors_ & BIRTH_THREAD) ? "*" : 1110 (combined_selectors_ & BIRTH_THREAD) ? "*" :
1069 sample.birth().birth_thread()->thread_name().c_str(), 1111 sample.birth().birth_thread()->thread_name().c_str(),
1070 (combined_selectors_ & DEATH_THREAD) ? "*" : 1112 (combined_selectors_ & DEATH_THREAD) ? "*" :
1071 sample.DeathThreadName().c_str()); 1113 sample.DeathThreadName().c_str());
1072 sample.birth().location().Write(!(combined_selectors_ & BIRTH_FILE), 1114 sample.birth().location().Write(!(combined_selectors_ & BIRTH_FILE),
1073 !(combined_selectors_ & BIRTH_FUNCTION), 1115 !(combined_selectors_ & BIRTH_FUNCTION),
1074 output); 1116 output);
1075 } 1117 }
1076 1118
1077 } // namespace tracked_objects 1119 } // 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