Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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 // Activity tracking provides a low-overhead method of collecting information | 5 // Activity tracking provides a low-overhead method of collecting information |
| 6 // about the state of the application for analysis both while it is running | 6 // about the state of the application for analysis both while it is running |
| 7 // and after it has terminated unexpectedly. Its primary purpose is to help | 7 // and after it has terminated unexpectedly. Its primary purpose is to help |
| 8 // locate reasons the browser becomes unresponsive by providing insight into | 8 // locate reasons the browser becomes unresponsive by providing insight into |
| 9 // what all the various threads and processes are (or were) doing. | 9 // what all the various threads and processes are (or were) doing. |
| 10 | 10 |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 118 static ActivityData ForProcess(const int64_t id) { | 118 static ActivityData ForProcess(const int64_t id) { |
| 119 ActivityData data; | 119 ActivityData data; |
| 120 data.process.process_id = id; | 120 data.process.process_id = id; |
| 121 return data; | 121 return data; |
| 122 } | 122 } |
| 123 }; | 123 }; |
| 124 | 124 |
| 125 // A "null" activity-data that can be passed to indicate "do not change". | 125 // A "null" activity-data that can be passed to indicate "do not change". |
| 126 extern const ActivityData kNullActivityData; | 126 extern const ActivityData kNullActivityData; |
| 127 | 127 |
| 128 | |
| 129 // A helper class that is used for managing memory allocations within a | |
| 130 // persistent memory allocator. Instances of this class are NOT thread-safe. | |
| 131 // Use from a single thread or protect access with a lock. | |
| 132 class ActivityTrackerMemoryAllocator { | |
| 133 public: | |
| 134 using Reference = PersistentMemoryAllocator::Reference; | |
| 135 | |
| 136 // Creates a instance for allocating objects of a fixed |object_type| and | |
| 137 // |object_size|. An internal cache of the last |cache_size| released | |
| 138 // references will be kept for quick future fetches. | |
| 139 ActivityTrackerMemoryAllocator(PersistentMemoryAllocator* allocator, | |
| 140 uint32_t object_type, | |
| 141 size_t object_size, | |
| 142 size_t cache_size); | |
| 143 ~ActivityTrackerMemoryAllocator(); | |
| 144 | |
| 145 // Gets a reference to an object of the configured type. This can return | |
| 146 // a null reference if it was not possible to allocate the memory. | |
| 147 Reference GetObjectReference(); | |
| 148 | |
| 149 // Returns an object to the "free" pool. | |
| 150 void ReleaseObjectReference(Reference ref); | |
| 151 | |
| 152 // The current "used size" of the internal cache, visible for testing. | |
| 153 size_t cache_used() { return cache_used_; } | |
| 154 | |
| 155 private: | |
| 156 PersistentMemoryAllocator* const allocator_; | |
| 157 const uint32_t object_type_; | |
| 158 const size_t object_size_; | |
| 159 const size_t cache_size_; | |
| 160 | |
| 161 // An iterator for going through persistent memory looking for free'd objects. | |
| 162 PersistentMemoryAllocator::Iterator iterator_; | |
| 163 | |
| 164 // The cache of released object memories. | |
| 165 std::unique_ptr<Reference[]> cache_values_; | |
|
manzagop (departed)
2016/10/04 21:02:43
How does a fixed array compare to a vector? Vector
bcwhite
2016/10/05 16:34:11
The implementation of std::vector is not strictly
| |
| 166 size_t cache_used_; | |
| 167 | |
| 168 DISALLOW_COPY_AND_ASSIGN(ActivityTrackerMemoryAllocator); | |
| 169 }; | |
| 170 | |
| 171 | |
| 128 // This structure is the full contents recorded for every activity pushed | 172 // This structure is the full contents recorded for every activity pushed |
| 129 // onto the stack. The |activity_type| indicates what is actually stored in | 173 // onto the stack. The |activity_type| indicates what is actually stored in |
| 130 // the |data| field. All fields must be explicitly sized types to ensure no | 174 // the |data| field. All fields must be explicitly sized types to ensure no |
| 131 // interoperability problems between 32-bit and 64-bit systems. | 175 // interoperability problems between 32-bit and 64-bit systems. |
| 132 struct Activity { | 176 struct Activity { |
| 133 // The type of an activity on the stack. Activities are broken into | 177 // The type of an activity on the stack. Activities are broken into |
| 134 // categories with the category ID taking the top 4 bits and the lower | 178 // categories with the category ID taking the top 4 bits and the lower |
| 135 // bits representing an action within that category. This combination | 179 // bits representing an action within that category. This combination |
| 136 // makes it easy to "switch" based on the type during analysis. | 180 // makes it easy to "switch" based on the type during analysis. |
| 137 enum Type : uint8_t { | 181 enum Type : uint8_t { |
| (...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 337 base::ThreadChecker thread_checker_; | 381 base::ThreadChecker thread_checker_; |
| 338 | 382 |
| 339 DISALLOW_COPY_AND_ASSIGN(ThreadActivityTracker); | 383 DISALLOW_COPY_AND_ASSIGN(ThreadActivityTracker); |
| 340 }; | 384 }; |
| 341 | 385 |
| 342 | 386 |
| 343 // The global tracker manages all the individual thread trackers. Memory for | 387 // The global tracker manages all the individual thread trackers. Memory for |
| 344 // the thread trackers is taken from a PersistentMemoryAllocator which allows | 388 // the thread trackers is taken from a PersistentMemoryAllocator which allows |
| 345 // for the data to be analyzed by a parallel process or even post-mortem. | 389 // for the data to be analyzed by a parallel process or even post-mortem. |
| 346 class BASE_EXPORT GlobalActivityTracker { | 390 class BASE_EXPORT GlobalActivityTracker { |
| 347 template <typename T> | |
| 348 class ThreadSafeStack { | |
| 349 public: | |
| 350 ThreadSafeStack(size_t size) | |
| 351 : size_(size), values_(new T[size]), used_(0) {} | |
| 352 ~ThreadSafeStack() {} | |
| 353 | |
| 354 size_t size() { return size_; } | |
| 355 size_t used() { | |
| 356 base::AutoLock autolock(lock_); | |
| 357 return used_; | |
| 358 } | |
| 359 | |
| 360 bool push(T value) { | |
| 361 base::AutoLock autolock(lock_); | |
| 362 if (used_ == size_) | |
| 363 return false; | |
| 364 values_[used_++] = value; | |
| 365 return true; | |
| 366 } | |
| 367 | |
| 368 bool pop(T* out_value) { | |
| 369 base::AutoLock autolock(lock_); | |
| 370 if (used_ == 0) | |
| 371 return false; | |
| 372 *out_value = values_[--used_]; | |
| 373 return true; | |
| 374 } | |
| 375 | |
| 376 private: | |
| 377 const size_t size_; | |
| 378 | |
| 379 std::unique_ptr<T[]> values_; | |
| 380 size_t used_; | |
| 381 base::Lock lock_; | |
| 382 | |
| 383 private: | |
| 384 DISALLOW_COPY_AND_ASSIGN(ThreadSafeStack); | |
| 385 }; | |
| 386 | |
| 387 public: | 391 public: |
| 388 // Type identifiers used when storing in persistent memory so they can be | 392 // Type identifiers used when storing in persistent memory so they can be |
| 389 // identified during extraction; the first 4 bytes of the SHA1 of the name | 393 // identified during extraction; the first 4 bytes of the SHA1 of the name |
| 390 // is used as a unique integer. A "version number" is added to the base | 394 // is used as a unique integer. A "version number" is added to the base |
| 391 // so that, if the structure of that object changes, stored older versions | 395 // so that, if the structure of that object changes, stored older versions |
| 392 // will be safely ignored. These are public so that an external process | 396 // will be safely ignored. These are public so that an external process |
| 393 // can recognize records of this type within an allocator. | 397 // can recognize records of this type within an allocator. |
| 394 enum : uint32_t { | 398 enum : uint32_t { |
| 395 kTypeIdActivityTracker = 0x5D7381AF + 1, // SHA1(ActivityTracker) v1 | 399 kTypeIdActivityTracker = 0x5D7381AF + 1, // SHA1(ActivityTracker) v1 |
| 396 kTypeIdActivityTrackerFree = 0x3F0272FB + 1, // SHA1(ActivityTrackerFree) | |
| 397 }; | 400 }; |
| 398 | 401 |
| 399 // This is a thin wrapper around the thread-tracker's ScopedActivity that | 402 // This is a thin wrapper around the thread-tracker's ScopedActivity that |
| 400 // accesses the global tracker to provide some of the information, notably | 403 // accesses the global tracker to provide some of the information, notably |
| 401 // which thread-tracker to use. It is safe to create even if activity | 404 // which thread-tracker to use. It is safe to create even if activity |
| 402 // tracking is not enabled. | 405 // tracking is not enabled. |
| 403 class BASE_EXPORT ScopedThreadActivity | 406 class BASE_EXPORT ScopedThreadActivity |
| 404 : public ThreadActivityTracker::ScopedActivity { | 407 : public ThreadActivityTracker::ScopedActivity { |
| 405 public: | 408 public: |
| 406 ScopedThreadActivity(const void* origin, | 409 ScopedThreadActivity(const void* origin, |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 492 // Releases the activity-tracker for the current thread (for testing only). | 495 // Releases the activity-tracker for the current thread (for testing only). |
| 493 void ReleaseTrackerForCurrentThreadForTesting(); | 496 void ReleaseTrackerForCurrentThreadForTesting(); |
| 494 | 497 |
| 495 private: | 498 private: |
| 496 friend class ActivityTrackerTest; | 499 friend class ActivityTrackerTest; |
| 497 | 500 |
| 498 enum : int { | 501 enum : int { |
| 499 // The maximum number of threads that can be tracked within a process. If | 502 // The maximum number of threads that can be tracked within a process. If |
| 500 // more than this number run concurrently, tracking of new ones may cease. | 503 // more than this number run concurrently, tracking of new ones may cease. |
| 501 kMaxThreadCount = 100, | 504 kMaxThreadCount = 100, |
| 505 kCachedThreadMemories = 10, | |
|
manzagop (departed)
2016/10/04 21:02:43
Can you comment on why 10? IIUC caching is cheap c
bcwhite
2016/10/05 16:34:11
It's arbitrary. If it's too small (many resources
| |
| 502 }; | 506 }; |
| 503 | 507 |
| 504 // A thin wrapper around the main thread-tracker that keeps additional | 508 // A thin wrapper around the main thread-tracker that keeps additional |
| 505 // information that the global tracker needs to handle joined threads. | 509 // information that the global tracker needs to handle joined threads. |
| 506 class ManagedActivityTracker : public ThreadActivityTracker { | 510 class ManagedActivityTracker : public ThreadActivityTracker { |
| 507 public: | 511 public: |
| 508 ManagedActivityTracker(PersistentMemoryAllocator::Reference mem_reference, | 512 ManagedActivityTracker(PersistentMemoryAllocator::Reference mem_reference, |
| 509 void* base, | 513 void* base, |
| 510 size_t size); | 514 size_t size); |
| 511 ~ManagedActivityTracker() override; | 515 ~ManagedActivityTracker() override; |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 543 // The size (in bytes) of memory required by a ThreadActivityTracker to | 547 // The size (in bytes) of memory required by a ThreadActivityTracker to |
| 544 // provide the stack-depth requested during construction. | 548 // provide the stack-depth requested during construction. |
| 545 const size_t stack_memory_size_; | 549 const size_t stack_memory_size_; |
| 546 | 550 |
| 547 // The activity tracker for the currently executing thread. | 551 // The activity tracker for the currently executing thread. |
| 548 base::ThreadLocalStorage::Slot this_thread_tracker_; | 552 base::ThreadLocalStorage::Slot this_thread_tracker_; |
| 549 | 553 |
| 550 // The number of thread trackers currently active. | 554 // The number of thread trackers currently active. |
| 551 std::atomic<int> thread_tracker_count_; | 555 std::atomic<int> thread_tracker_count_; |
| 552 | 556 |
| 553 // A cache of thread-tracker memories that have been previously freed and | 557 // A caching memory allocator for thread-tracker objects. |
| 554 // thus can be re-used instead of allocating new ones. | 558 ActivityTrackerMemoryAllocator thread_tracker_allocator_; |
| 555 ThreadSafeStack<PersistentMemoryAllocator::Reference> available_memories_; | 559 base::Lock thread_tracker_allocator_lock_; |
| 556 | 560 |
| 557 // The active global activity tracker. | 561 // The active global activity tracker. |
| 558 static GlobalActivityTracker* g_tracker_; | 562 static GlobalActivityTracker* g_tracker_; |
| 559 | 563 |
| 560 DISALLOW_COPY_AND_ASSIGN(GlobalActivityTracker); | 564 DISALLOW_COPY_AND_ASSIGN(GlobalActivityTracker); |
| 561 }; | 565 }; |
| 562 | 566 |
| 563 | 567 |
| 564 // Record entry in to and out of an arbitrary block of code. | 568 // Record entry in to and out of an arbitrary block of code. |
| 565 class BASE_EXPORT ScopedActivity | 569 class BASE_EXPORT ScopedActivity |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 649 explicit ScopedProcessWaitActivity(const base::Process* process); | 653 explicit ScopedProcessWaitActivity(const base::Process* process); |
| 650 private: | 654 private: |
| 651 DISALLOW_COPY_AND_ASSIGN(ScopedProcessWaitActivity); | 655 DISALLOW_COPY_AND_ASSIGN(ScopedProcessWaitActivity); |
| 652 }; | 656 }; |
| 653 #endif | 657 #endif |
| 654 | 658 |
| 655 } // namespace debug | 659 } // namespace debug |
| 656 } // namespace base | 660 } // namespace base |
| 657 | 661 |
| 658 #endif // BASE_DEBUG_ACTIVITY_TRACKER_H_ | 662 #endif // BASE_DEBUG_ACTIVITY_TRACKER_H_ |
| OLD | NEW |