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

Side by Side Diff: base/tracked_objects.cc

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