| 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|, a |
| 137 // corresponding |object_free| type, and the |object_size|. An internal |
| 138 // cache of the last |cache_size| released references will be kept for |
| 139 // quick future fetches. |
| 140 ActivityTrackerMemoryAllocator(PersistentMemoryAllocator* allocator, |
| 141 uint32_t object_type, |
| 142 uint32_t object_free_type, |
| 143 size_t object_size, |
| 144 size_t cache_size); |
| 145 ~ActivityTrackerMemoryAllocator(); |
| 146 |
| 147 // Gets a reference to an object of the configured type. This can return |
| 148 // a null reference if it was not possible to allocate the memory. |
| 149 Reference GetObjectReference(); |
| 150 |
| 151 // Returns an object to the "free" pool. |
| 152 void ReleaseObjectReference(Reference ref); |
| 153 |
| 154 // The current "used size" of the internal cache, visible for testing. |
| 155 size_t cache_used() const { return cache_used_; } |
| 156 |
| 157 private: |
| 158 PersistentMemoryAllocator* const allocator_; |
| 159 const uint32_t object_type_; |
| 160 const uint32_t object_free_type_; |
| 161 const size_t object_size_; |
| 162 const size_t cache_size_; |
| 163 |
| 164 // An iterator for going through persistent memory looking for free'd objects. |
| 165 PersistentMemoryAllocator::Iterator iterator_; |
| 166 |
| 167 // The cache of released object memories. |
| 168 std::unique_ptr<Reference[]> cache_values_; |
| 169 size_t cache_used_; |
| 170 |
| 171 DISALLOW_COPY_AND_ASSIGN(ActivityTrackerMemoryAllocator); |
| 172 }; |
| 173 |
| 174 |
| 128 // This structure is the full contents recorded for every activity pushed | 175 // This structure is the full contents recorded for every activity pushed |
| 129 // onto the stack. The |activity_type| indicates what is actually stored in | 176 // 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 | 177 // the |data| field. All fields must be explicitly sized types to ensure no |
| 131 // interoperability problems between 32-bit and 64-bit systems. | 178 // interoperability problems between 32-bit and 64-bit systems. |
| 132 struct Activity { | 179 struct Activity { |
| 133 // The type of an activity on the stack. Activities are broken into | 180 // 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 | 181 // categories with the category ID taking the top 4 bits and the lower |
| 135 // bits representing an action within that category. This combination | 182 // bits representing an action within that category. This combination |
| 136 // makes it easy to "switch" based on the type during analysis. | 183 // makes it easy to "switch" based on the type during analysis. |
| 137 enum Type : uint8_t { | 184 enum Type : uint8_t { |
| (...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 337 base::ThreadChecker thread_checker_; | 384 base::ThreadChecker thread_checker_; |
| 338 | 385 |
| 339 DISALLOW_COPY_AND_ASSIGN(ThreadActivityTracker); | 386 DISALLOW_COPY_AND_ASSIGN(ThreadActivityTracker); |
| 340 }; | 387 }; |
| 341 | 388 |
| 342 | 389 |
| 343 // The global tracker manages all the individual thread trackers. Memory for | 390 // The global tracker manages all the individual thread trackers. Memory for |
| 344 // the thread trackers is taken from a PersistentMemoryAllocator which allows | 391 // 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. | 392 // for the data to be analyzed by a parallel process or even post-mortem. |
| 346 class BASE_EXPORT GlobalActivityTracker { | 393 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: | 394 public: |
| 388 // Type identifiers used when storing in persistent memory so they can be | 395 // 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 | 396 // 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 | 397 // 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 | 398 // 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 | 399 // will be safely ignored. These are public so that an external process |
| 393 // can recognize records of this type within an allocator. | 400 // can recognize records of this type within an allocator. |
| 394 enum : uint32_t { | 401 enum : uint32_t { |
| 395 kTypeIdActivityTracker = 0x5D7381AF + 1, // SHA1(ActivityTracker) v1 | 402 kTypeIdActivityTracker = 0x5D7381AF + 1, // SHA1(ActivityTracker) v1 |
| 396 kTypeIdActivityTrackerFree = 0x3F0272FB + 1, // SHA1(ActivityTrackerFree) | 403 kTypeIdActivityTrackerFree = ~kTypeIdActivityTracker, |
| 397 }; | 404 }; |
| 398 | 405 |
| 399 // This is a thin wrapper around the thread-tracker's ScopedActivity that | 406 // This is a thin wrapper around the thread-tracker's ScopedActivity that |
| 400 // accesses the global tracker to provide some of the information, notably | 407 // 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 | 408 // which thread-tracker to use. It is safe to create even if activity |
| 402 // tracking is not enabled. | 409 // tracking is not enabled. |
| 403 class BASE_EXPORT ScopedThreadActivity | 410 class BASE_EXPORT ScopedThreadActivity |
| 404 : public ThreadActivityTracker::ScopedActivity { | 411 : public ThreadActivityTracker::ScopedActivity { |
| 405 public: | 412 public: |
| 406 ScopedThreadActivity(const void* origin, | 413 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). | 499 // Releases the activity-tracker for the current thread (for testing only). |
| 493 void ReleaseTrackerForCurrentThreadForTesting(); | 500 void ReleaseTrackerForCurrentThreadForTesting(); |
| 494 | 501 |
| 495 private: | 502 private: |
| 496 friend class ActivityTrackerTest; | 503 friend class ActivityTrackerTest; |
| 497 | 504 |
| 498 enum : int { | 505 enum : int { |
| 499 // The maximum number of threads that can be tracked within a process. If | 506 // 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. | 507 // more than this number run concurrently, tracking of new ones may cease. |
| 501 kMaxThreadCount = 100, | 508 kMaxThreadCount = 100, |
| 509 kCachedThreadMemories = 10, |
| 502 }; | 510 }; |
| 503 | 511 |
| 504 // A thin wrapper around the main thread-tracker that keeps additional | 512 // A thin wrapper around the main thread-tracker that keeps additional |
| 505 // information that the global tracker needs to handle joined threads. | 513 // information that the global tracker needs to handle joined threads. |
| 506 class ManagedActivityTracker : public ThreadActivityTracker { | 514 class ManagedActivityTracker : public ThreadActivityTracker { |
| 507 public: | 515 public: |
| 508 ManagedActivityTracker(PersistentMemoryAllocator::Reference mem_reference, | 516 ManagedActivityTracker(PersistentMemoryAllocator::Reference mem_reference, |
| 509 void* base, | 517 void* base, |
| 510 size_t size); | 518 size_t size); |
| 511 ~ManagedActivityTracker() override; | 519 ~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 | 551 // The size (in bytes) of memory required by a ThreadActivityTracker to |
| 544 // provide the stack-depth requested during construction. | 552 // provide the stack-depth requested during construction. |
| 545 const size_t stack_memory_size_; | 553 const size_t stack_memory_size_; |
| 546 | 554 |
| 547 // The activity tracker for the currently executing thread. | 555 // The activity tracker for the currently executing thread. |
| 548 base::ThreadLocalStorage::Slot this_thread_tracker_; | 556 base::ThreadLocalStorage::Slot this_thread_tracker_; |
| 549 | 557 |
| 550 // The number of thread trackers currently active. | 558 // The number of thread trackers currently active. |
| 551 std::atomic<int> thread_tracker_count_; | 559 std::atomic<int> thread_tracker_count_; |
| 552 | 560 |
| 553 // A cache of thread-tracker memories that have been previously freed and | 561 // A caching memory allocator for thread-tracker objects. |
| 554 // thus can be re-used instead of allocating new ones. | 562 ActivityTrackerMemoryAllocator thread_tracker_allocator_; |
| 555 ThreadSafeStack<PersistentMemoryAllocator::Reference> available_memories_; | 563 base::Lock thread_tracker_allocator_lock_; |
| 556 | 564 |
| 557 // The active global activity tracker. | 565 // The active global activity tracker. |
| 558 static GlobalActivityTracker* g_tracker_; | 566 static GlobalActivityTracker* g_tracker_; |
| 559 | 567 |
| 560 DISALLOW_COPY_AND_ASSIGN(GlobalActivityTracker); | 568 DISALLOW_COPY_AND_ASSIGN(GlobalActivityTracker); |
| 561 }; | 569 }; |
| 562 | 570 |
| 563 | 571 |
| 564 // Record entry in to and out of an arbitrary block of code. | 572 // Record entry in to and out of an arbitrary block of code. |
| 565 class BASE_EXPORT ScopedActivity | 573 class BASE_EXPORT ScopedActivity |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 649 explicit ScopedProcessWaitActivity(const base::Process* process); | 657 explicit ScopedProcessWaitActivity(const base::Process* process); |
| 650 private: | 658 private: |
| 651 DISALLOW_COPY_AND_ASSIGN(ScopedProcessWaitActivity); | 659 DISALLOW_COPY_AND_ASSIGN(ScopedProcessWaitActivity); |
| 652 }; | 660 }; |
| 653 #endif | 661 #endif |
| 654 | 662 |
| 655 } // namespace debug | 663 } // namespace debug |
| 656 } // namespace base | 664 } // namespace base |
| 657 | 665 |
| 658 #endif // BASE_DEBUG_ACTIVITY_TRACKER_H_ | 666 #endif // BASE_DEBUG_ACTIVITY_TRACKER_H_ |
| OLD | NEW |