OLD | NEW |
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/stringprintf.h" | 11 #include "base/stringprintf.h" |
12 #include "base/threading/thread_restrictions.h" | 12 #include "base/threading/thread_restrictions.h" |
13 #include "build/build_config.h" | 13 #include "build/build_config.h" |
| 14 #include "base/port.h" |
14 | 15 |
15 using base::TimeDelta; | 16 using base::TimeDelta; |
16 | 17 |
17 namespace tracked_objects { | 18 namespace tracked_objects { |
18 | 19 |
19 namespace { | 20 namespace { |
20 // Flag to compile out almost all of the task tracking code. | 21 // Flag to compile out almost all of the task tracking code. |
21 static const bool kTrackAllTaskObjects = true; | 22 static const bool kTrackAllTaskObjects = true; |
22 | 23 |
23 // When ThreadData is first initialized, should we start in an ACTIVE state to | 24 // When ThreadData is first initialized, should we start in an ACTIVE state to |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
140 base::LazyInstance<base::Lock, | 141 base::LazyInstance<base::Lock, |
141 base::LeakyLazyInstanceTraits<base::Lock> > | 142 base::LeakyLazyInstanceTraits<base::Lock> > |
142 ThreadData::list_lock_ = LAZY_INSTANCE_INITIALIZER; | 143 ThreadData::list_lock_ = LAZY_INSTANCE_INITIALIZER; |
143 | 144 |
144 // static | 145 // static |
145 ThreadData::Status ThreadData::status_ = ThreadData::UNINITIALIZED; | 146 ThreadData::Status ThreadData::status_ = ThreadData::UNINITIALIZED; |
146 | 147 |
147 ThreadData::ThreadData(const std::string& suggested_name) | 148 ThreadData::ThreadData(const std::string& suggested_name) |
148 : incarnation_count_for_pool_(-1), | 149 : incarnation_count_for_pool_(-1), |
149 next_(NULL), | 150 next_(NULL), |
150 is_a_worker_thread_(false) { | 151 worker_thread_number_(0) { |
151 DCHECK_GE(suggested_name.size(), 0u); | 152 DCHECK_GE(suggested_name.size(), 0u); |
152 thread_name_ = suggested_name; | 153 thread_name_ = suggested_name; |
153 PushToHeadOfList(); // Which sets real incarnation_count_for_pool_. | 154 PushToHeadOfList(); // Which sets real incarnation_count_for_pool_. |
154 } | 155 } |
155 | 156 |
156 ThreadData::ThreadData() | 157 ThreadData::ThreadData(size_t thread_number) |
157 : incarnation_count_for_pool_(-1), | 158 : incarnation_count_for_pool_(-1), |
158 next_(NULL), | 159 next_(NULL), |
159 is_a_worker_thread_(true) { | 160 worker_thread_number_(thread_number) { |
160 int thread_number; | 161 CHECK_NE(thread_number, 0u); |
161 { | 162 base::StringAppendF(&thread_name_, "WorkerThread-%"PRIuS, thread_number); |
162 base::AutoLock lock(*list_lock_.Pointer()); | |
163 thread_number = ++thread_number_counter_; | |
164 } | |
165 base::StringAppendF(&thread_name_, "WorkerThread-%d", thread_number); | |
166 PushToHeadOfList(); // Which sets real incarnation_count_for_pool_. | 163 PushToHeadOfList(); // Which sets real incarnation_count_for_pool_. |
167 } | 164 } |
168 | 165 |
169 ThreadData::~ThreadData() {} | 166 ThreadData::~ThreadData() {} |
170 | 167 |
171 void ThreadData::PushToHeadOfList() { | 168 void ThreadData::PushToHeadOfList() { |
172 DCHECK(!next_); | 169 DCHECK(!next_); |
173 base::AutoLock lock(*list_lock_.Pointer()); | 170 base::AutoLock lock(*list_lock_.Pointer()); |
174 incarnation_count_for_pool_ = incarnation_counter_; | 171 incarnation_count_for_pool_ = incarnation_counter_; |
175 next_ = all_thread_data_list_head_; | 172 next_ = all_thread_data_list_head_; |
(...skipping 15 matching lines...) Expand all Loading... |
191 // static | 188 // static |
192 ThreadData* ThreadData::Get() { | 189 ThreadData* ThreadData::Get() { |
193 if (!tls_index_.initialized()) | 190 if (!tls_index_.initialized()) |
194 return NULL; // For unittests only. | 191 return NULL; // For unittests only. |
195 ThreadData* registered = reinterpret_cast<ThreadData*>(tls_index_.Get()); | 192 ThreadData* registered = reinterpret_cast<ThreadData*>(tls_index_.Get()); |
196 if (registered) | 193 if (registered) |
197 return registered; | 194 return registered; |
198 | 195 |
199 // We must be a worker thread, since we didn't pre-register. | 196 // We must be a worker thread, since we didn't pre-register. |
200 ThreadData* worker_thread_data = NULL; | 197 ThreadData* worker_thread_data = NULL; |
| 198 size_t thread_number = 0; |
201 { | 199 { |
202 base::AutoLock lock(*list_lock_.Pointer()); | 200 base::AutoLock lock(*list_lock_.Pointer()); |
203 if (unregistered_thread_data_pool_ && | 201 if (!unregistered_thread_data_pool_) |
204 !unregistered_thread_data_pool_->empty()) { | 202 unregistered_thread_data_pool_ = new ThreadDataPool; |
| 203 if (!unregistered_thread_data_pool_->empty()) { |
205 worker_thread_data = | 204 worker_thread_data = |
206 const_cast<ThreadData*>(unregistered_thread_data_pool_->top()); | 205 const_cast<ThreadData*>(unregistered_thread_data_pool_->top()); |
207 unregistered_thread_data_pool_->pop(); | 206 unregistered_thread_data_pool_->pop(); |
| 207 } else { |
| 208 thread_number = ++thread_number_counter_; |
| 209 unregistered_thread_data_pool_->reserve(thread_number); |
208 } | 210 } |
209 } | 211 } |
210 | 212 |
211 // If we can't find a previously used instance, then we have to create one. | 213 // If we can't find a previously used instance, then we have to create one. |
212 if (!worker_thread_data) | 214 if (!worker_thread_data) |
213 worker_thread_data = new ThreadData(); | 215 worker_thread_data = new ThreadData(thread_number); |
| 216 DCHECK_GT(worker_thread_data->worker_thread_number_, 0u); |
214 | 217 |
215 tls_index_.Set(worker_thread_data); | 218 tls_index_.Set(worker_thread_data); |
216 return worker_thread_data; | 219 return worker_thread_data; |
217 } | 220 } |
218 | 221 |
219 // static | 222 // static |
220 void ThreadData::OnThreadTermination(void* thread_data) { | 223 void ThreadData::OnThreadTermination(void* thread_data) { |
221 if (!kTrackAllTaskObjects) | 224 if (!kTrackAllTaskObjects) |
222 return; // Not compiled in. | 225 return; // Not compiled in. |
223 if (!thread_data) | 226 if (!thread_data) |
224 return; | 227 return; |
225 reinterpret_cast<ThreadData*>(thread_data)->OnThreadTerminationCleanup(); | 228 reinterpret_cast<ThreadData*>(thread_data)->OnThreadTerminationCleanup(); |
226 } | 229 } |
227 | 230 |
228 void ThreadData::OnThreadTerminationCleanup() const { | 231 void ThreadData::OnThreadTerminationCleanup() const { |
229 if (!is_a_worker_thread_) | 232 if (!worker_thread_number_) |
230 return; | 233 return; |
231 base::AutoLock lock(*list_lock_.Pointer()); | 234 base::AutoLock lock(*list_lock_.Pointer()); |
232 if (incarnation_counter_ != incarnation_count_for_pool_) | 235 if (incarnation_counter_ != incarnation_count_for_pool_) |
233 return; // ThreadData was constructed in an earlier unit test. | 236 return; // ThreadData was constructed in an earlier unit test. |
234 | 237 // The following will never have to do an allocation. |
235 // Handle case where we are in unit tests, and have become UNINITIALIZED. | |
236 // In that case, the pool might be NULL. We really should detect this via the | |
237 // incarnation_counter_, but this call is rarely made, so we can afford to | |
238 // code defensively. | |
239 if (!unregistered_thread_data_pool_) | |
240 unregistered_thread_data_pool_ = new ThreadDataPool; | |
241 unregistered_thread_data_pool_->push(this); | 238 unregistered_thread_data_pool_->push(this); |
242 } | 239 } |
243 | 240 |
244 // static | 241 // static |
245 base::DictionaryValue* ThreadData::ToValue() { | 242 base::DictionaryValue* ThreadData::ToValue() { |
246 DataCollector collected_data; // Gather data. | 243 DataCollector collected_data; // Gather data. |
247 collected_data.AddListOfLivingObjects(); // Add births that are still alive. | 244 collected_data.AddListOfLivingObjects(); // Add births that are still alive. |
248 base::ListValue* list = collected_data.ToValue(); | 245 base::ListValue* list = collected_data.ToValue(); |
249 base::DictionaryValue* dictionary = new base::DictionaryValue(); | 246 base::DictionaryValue* dictionary = new base::DictionaryValue(); |
250 dictionary->Set("list", list); | 247 dictionary->Set("list", list); |
(...skipping 304 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
555 for (BirthMap::iterator it = next_thread_data->birth_map_.begin(); | 552 for (BirthMap::iterator it = next_thread_data->birth_map_.begin(); |
556 next_thread_data->birth_map_.end() != it; ++it) | 553 next_thread_data->birth_map_.end() != it; ++it) |
557 delete it->second; // Delete the Birth Records. | 554 delete it->second; // Delete the Birth Records. |
558 next_thread_data->birth_map_.clear(); | 555 next_thread_data->birth_map_.clear(); |
559 next_thread_data->death_map_.clear(); | 556 next_thread_data->death_map_.clear(); |
560 delete next_thread_data; // Includes all Death Records. | 557 delete next_thread_data; // Includes all Death Records. |
561 } | 558 } |
562 } | 559 } |
563 | 560 |
564 //------------------------------------------------------------------------------ | 561 //------------------------------------------------------------------------------ |
| 562 // Small partial implementation of a stack that never has to allocate during a |
| 563 // push() operation, because it is always prepared to accept the maximum number |
| 564 // of ThreadData instances (all the worker thread related instances). |
| 565 |
| 566 ThreadData::ThreadDataPool::ThreadDataPool() : empty_slot_(0) {}; |
| 567 ThreadData::ThreadDataPool::~ThreadDataPool() {}; |
| 568 |
| 569 bool ThreadData::ThreadDataPool::empty() const { return empty_slot_ == 0; } |
| 570 |
| 571 void ThreadData::ThreadDataPool::reserve(size_t largest_worker_pool_number) { |
| 572 // Worker pool numbers start at 1, and exclude 0, so the number is exactly |
| 573 // the least size needed. |
| 574 // Due to asynchronous construction of worker-pool numbers (and associated |
| 575 // ThreadData), we might not hear about the numbers sequentially. |
| 576 if (largest_worker_pool_number > stack_.size()) |
| 577 stack_.resize(largest_worker_pool_number); |
| 578 } |
| 579 |
| 580 const ThreadData* ThreadData::ThreadDataPool::top() const { |
| 581 if (empty_slot_ > 0) |
| 582 return stack_[empty_slot_ - 1]; |
| 583 NOTREACHED(); |
| 584 return NULL; |
| 585 } |
| 586 |
| 587 void ThreadData::ThreadDataPool::push(const ThreadData* thread_data) { |
| 588 if (empty_slot_ < stack_.size()) { |
| 589 stack_[empty_slot_] = thread_data; |
| 590 ++empty_slot_; |
| 591 return; |
| 592 } |
| 593 NOTREACHED(); |
| 594 } |
| 595 |
| 596 void ThreadData::ThreadDataPool::pop() { |
| 597 if (empty_slot_ > 0) { |
| 598 --empty_slot_; |
| 599 return; |
| 600 } |
| 601 NOTREACHED(); |
| 602 } |
| 603 |
| 604 //------------------------------------------------------------------------------ |
565 // Individual 3-tuple of birth (place and thread) along with death thread, and | 605 // Individual 3-tuple of birth (place and thread) along with death thread, and |
566 // the accumulated stats for instances (DeathData). | 606 // the accumulated stats for instances (DeathData). |
567 | 607 |
568 Snapshot::Snapshot(const BirthOnThread& birth_on_thread, | 608 Snapshot::Snapshot(const BirthOnThread& birth_on_thread, |
569 const ThreadData& death_thread, | 609 const ThreadData& death_thread, |
570 const DeathData& death_data) | 610 const DeathData& death_data) |
571 : birth_(&birth_on_thread), | 611 : birth_(&birth_on_thread), |
572 death_thread_(&death_thread), | 612 death_thread_(&death_thread), |
573 death_data_(death_data) { | 613 death_data_(death_data) { |
574 } | 614 } |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
655 | 695 |
656 base::ListValue* DataCollector::ToValue() const { | 696 base::ListValue* DataCollector::ToValue() const { |
657 base::ListValue* list = new base::ListValue; | 697 base::ListValue* list = new base::ListValue; |
658 for (size_t i = 0; i < collection_.size(); ++i) { | 698 for (size_t i = 0; i < collection_.size(); ++i) { |
659 list->Append(collection_[i].ToValue()); | 699 list->Append(collection_[i].ToValue()); |
660 } | 700 } |
661 return list; | 701 return list; |
662 } | 702 } |
663 | 703 |
664 } // namespace tracked_objects | 704 } // namespace tracked_objects |
OLD | NEW |