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

Side by Side Diff: base/debug/activity_tracker.h

Issue 2483473002: Include calling address in tracked activities. (Closed)
Patch Set: force inlining of methods that call GetProgramCounter() Created 4 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
« no previous file with comments | « base/debug/activity_analyzer.cc ('k') | base/debug/activity_tracker.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 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
11 #ifndef BASE_DEBUG_ACTIVITY_TRACKER_H_ 11 #ifndef BASE_DEBUG_ACTIVITY_TRACKER_H_
12 #define BASE_DEBUG_ACTIVITY_TRACKER_H_ 12 #define BASE_DEBUG_ACTIVITY_TRACKER_H_
13 13
14 // std::atomic is undesired due to performance issues when used as global 14 // std::atomic is undesired due to performance issues when used as global
15 // variables. There are no such instances here. This module uses the 15 // variables. There are no such instances here. This module uses the
16 // PersistentMemoryAllocator which also uses std::atomic and is written 16 // PersistentMemoryAllocator which also uses std::atomic and is written
17 // by the same author. 17 // by the same author.
18 #include <atomic> 18 #include <atomic>
19 #include <memory> 19 #include <memory>
20 #include <string> 20 #include <string>
21 #include <vector> 21 #include <vector>
22 22
23 #include "base/base_export.h" 23 #include "base/base_export.h"
24 #include "base/compiler_specific.h"
24 #include "base/location.h" 25 #include "base/location.h"
25 #include "base/metrics/persistent_memory_allocator.h" 26 #include "base/metrics/persistent_memory_allocator.h"
26 #include "base/threading/platform_thread.h" 27 #include "base/threading/platform_thread.h"
27 #include "base/threading/thread_checker.h" 28 #include "base/threading/thread_checker.h"
28 #include "base/threading/thread_local_storage.h" 29 #include "base/threading/thread_local_storage.h"
29 30
30 namespace base { 31 namespace base {
31 32
32 struct PendingTask; 33 struct PendingTask;
33 34
(...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after
215 // These constants can be used to separate the category and action from 216 // These constants can be used to separate the category and action from
216 // a combined activity type. 217 // a combined activity type.
217 ACT_CATEGORY_MASK = 0xF << 4, 218 ACT_CATEGORY_MASK = 0xF << 4,
218 ACT_ACTION_MASK = 0xF 219 ACT_ACTION_MASK = 0xF
219 }; 220 };
220 221
221 // Internal representation of time. During collection, this is in "ticks" 222 // Internal representation of time. During collection, this is in "ticks"
222 // but when returned in a snapshot, it is "wall time". 223 // but when returned in a snapshot, it is "wall time".
223 int64_t time_internal; 224 int64_t time_internal;
224 225
226 // The address that pushed the activity onto the stack as a raw number.
227 uint64_t calling_address;
228
225 // The address that is the origin of the activity if it not obvious from 229 // The address that is the origin of the activity if it not obvious from
226 // the call stack. This is useful for things like tasks that are posted 230 // the call stack. This is useful for things like tasks that are posted
227 // from a completely different thread though most activities will leave 231 // from a completely different thread though most activities will leave
228 // it null. 232 // it null.
229 uint64_t origin_address; 233 uint64_t origin_address;
230 234
231 // Array of program-counters that make up the top of the call stack. 235 // Array of program-counters that make up the top of the call stack.
232 // Despite the fixed size, this list is always null-terminated. Entries 236 // Despite the fixed size, this list is always null-terminated. Entries
233 // after the terminator have no meaning and may or may not also be null. 237 // after the terminator have no meaning and may or may not also be null.
234 // The list will be completely empty if call-stack collection is not 238 // The list will be completely empty if call-stack collection is not
235 // enabled. 239 // enabled.
236 uint64_t call_stack[kActivityCallStackSize]; 240 uint64_t call_stack[kActivityCallStackSize];
237 241
238 // The (enumerated) type of the activity. This defines what fields of the 242 // The (enumerated) type of the activity. This defines what fields of the
239 // |data| record are valid. 243 // |data| record are valid.
240 uint8_t activity_type; 244 uint8_t activity_type;
241 245
242 // Padding to ensure that the next member begins on a 64-bit boundary 246 // Padding to ensure that the next member begins on a 64-bit boundary
243 // even on 32-bit builds which ensures inter-operability between CPU 247 // even on 32-bit builds which ensures inter-operability between CPU
244 // architectures. New fields can be taken from this space. 248 // architectures. New fields can be taken from this space.
245 uint8_t padding[7]; 249 uint8_t padding[7];
246 250
247 // Information specific to the |activity_type|. 251 // Information specific to the |activity_type|.
248 ActivityData data; 252 ActivityData data;
249 253
250 static void FillFrom(Activity* activity, 254 static void FillFrom(Activity* activity,
255 const void* program_counter,
251 const void* origin, 256 const void* origin,
252 Type type, 257 Type type,
253 const ActivityData& data); 258 const ActivityData& data);
254 }; 259 };
255 260
256 // This structure holds a copy of all the internal data at the moment the 261 // This structure holds a copy of all the internal data at the moment the
257 // "snapshot" operation is done. It is disconnected from the live tracker 262 // "snapshot" operation is done. It is disconnected from the live tracker
258 // so that continued operation of the thread will not cause changes here. 263 // so that continued operation of the thread will not cause changes here.
259 struct BASE_EXPORT ActivitySnapshot { 264 struct BASE_EXPORT ActivitySnapshot {
260 // Explicit constructor/destructor are needed because of complex types 265 // Explicit constructor/destructor are needed because of complex types
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
294 // objects. 299 // objects.
295 class BASE_EXPORT ThreadActivityTracker { 300 class BASE_EXPORT ThreadActivityTracker {
296 public: 301 public:
297 // This is the base class for having the compiler manage an activity on the 302 // This is the base class for having the compiler manage an activity on the
298 // tracker's stack. It does nothing but call methods on the passed |tracker| 303 // tracker's stack. It does nothing but call methods on the passed |tracker|
299 // if it is not null, making it safe (and cheap) to create these objects 304 // if it is not null, making it safe (and cheap) to create these objects
300 // even if activity tracking is not enabled. 305 // even if activity tracking is not enabled.
301 class BASE_EXPORT ScopedActivity { 306 class BASE_EXPORT ScopedActivity {
302 public: 307 public:
303 ScopedActivity(ThreadActivityTracker* tracker, 308 ScopedActivity(ThreadActivityTracker* tracker,
309 const void* program_counter,
304 const void* origin, 310 const void* origin,
305 Activity::Type type, 311 Activity::Type type,
306 const ActivityData& data) 312 const ActivityData& data)
307 : tracker_(tracker) { 313 : tracker_(tracker) {
308 if (tracker_) 314 if (tracker_)
309 tracker_->PushActivity(origin, type, data); 315 tracker_->PushActivity(program_counter, origin, type, data);
310 } 316 }
311 317
312 ~ScopedActivity() { 318 ~ScopedActivity() {
313 if (tracker_) 319 if (tracker_)
314 tracker_->PopActivity(); 320 tracker_->PopActivity();
315 } 321 }
316 322
317 void ChangeTypeAndData(Activity::Type type, const ActivityData& data) { 323 void ChangeTypeAndData(Activity::Type type, const ActivityData& data) {
318 if (tracker_) 324 if (tracker_)
319 tracker_->ChangeActivity(type, data); 325 tracker_->ChangeActivity(type, data);
320 } 326 }
321 327
322 private: 328 private:
323 // The thread tracker to which this object reports. It can be null if 329 // The thread tracker to which this object reports. It can be null if
324 // activity tracking is not (yet) enabled. 330 // activity tracking is not (yet) enabled.
325 ThreadActivityTracker* const tracker_; 331 ThreadActivityTracker* const tracker_;
326 332
327 DISALLOW_COPY_AND_ASSIGN(ScopedActivity); 333 DISALLOW_COPY_AND_ASSIGN(ScopedActivity);
328 }; 334 };
329 335
330 // A ThreadActivityTracker runs on top of memory that is managed externally. 336 // A ThreadActivityTracker runs on top of memory that is managed externally.
331 // It must be large enough for the internal header and a few Activity 337 // It must be large enough for the internal header and a few Activity
332 // blocks. See SizeForStackDepth(). 338 // blocks. See SizeForStackDepth().
333 ThreadActivityTracker(void* base, size_t size); 339 ThreadActivityTracker(void* base, size_t size);
334 virtual ~ThreadActivityTracker(); 340 virtual ~ThreadActivityTracker();
335 341
336 // Indicates that an activity has started from a given |origin| address in 342 // Indicates that an activity has started from a given |origin| address in
337 // the code, though it can be null if the creator's address is not known. 343 // the code, though it can be null if the creator's address is not known.
338 // The |type| and |data| describe the activity. 344 // The |type| and |data| describe the activity. |program_counter| should be
345 // the result of GetProgramCounter() where push is called.
346 void PushActivity(const void* program_counter,
347 const void* origin,
348 Activity::Type type,
349 const ActivityData& data);
350
351 // An inlined version of the above that gets the program counter where it
352 // is called.
353 ALWAYS_INLINE
339 void PushActivity(const void* origin, 354 void PushActivity(const void* origin,
340 Activity::Type type, 355 Activity::Type type,
341 const ActivityData& data); 356 const ActivityData& data) {
357 PushActivity(::tracked_objects::GetProgramCounter(), origin, type, data);
358 }
342 359
343 // Changes the activity |type| and |data| of the top-most entry on the stack. 360 // Changes the activity |type| and |data| of the top-most entry on the stack.
344 // This is useful if the information has changed and it is desireable to 361 // This is useful if the information has changed and it is desireable to
345 // track that change without creating a new stack entry. If the type is 362 // track that change without creating a new stack entry. If the type is
346 // ACT_NULL or the data is kNullActivityData then that value will remain 363 // ACT_NULL or the data is kNullActivityData then that value will remain
347 // unchanged. The type, if changed, must remain in the same category. 364 // unchanged. The type, if changed, must remain in the same category.
348 // Changing both is not atomic so a snapshot operation could occur between 365 // Changing both is not atomic so a snapshot operation could occur between
349 // the update of |type| and |data| or between update of |data| fields. 366 // the update of |type| and |data| or between update of |data| fields.
350 void ChangeActivity(Activity::Type type, const ActivityData& data); 367 void ChangeActivity(Activity::Type type, const ActivityData& data);
351 368
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
391 // for the data to be analyzed by a parallel process or even post-mortem. 408 // for the data to be analyzed by a parallel process or even post-mortem.
392 class BASE_EXPORT GlobalActivityTracker { 409 class BASE_EXPORT GlobalActivityTracker {
393 public: 410 public:
394 // Type identifiers used when storing in persistent memory so they can be 411 // Type identifiers used when storing in persistent memory so they can be
395 // identified during extraction; the first 4 bytes of the SHA1 of the name 412 // identified during extraction; the first 4 bytes of the SHA1 of the name
396 // is used as a unique integer. A "version number" is added to the base 413 // is used as a unique integer. A "version number" is added to the base
397 // so that, if the structure of that object changes, stored older versions 414 // so that, if the structure of that object changes, stored older versions
398 // will be safely ignored. These are public so that an external process 415 // will be safely ignored. These are public so that an external process
399 // can recognize records of this type within an allocator. 416 // can recognize records of this type within an allocator.
400 enum : uint32_t { 417 enum : uint32_t {
401 kTypeIdActivityTracker = 0x5D7381AF + 1, // SHA1(ActivityTracker) v1 418 kTypeIdActivityTracker = 0x5D7381AF + 2, // SHA1(ActivityTracker) v2
402 kTypeIdActivityTrackerFree = ~kTypeIdActivityTracker, 419 kTypeIdActivityTrackerFree = ~kTypeIdActivityTracker,
403 }; 420 };
404 421
405 // This is a thin wrapper around the thread-tracker's ScopedActivity that 422 // This is a thin wrapper around the thread-tracker's ScopedActivity that
406 // accesses the global tracker to provide some of the information, notably 423 // accesses the global tracker to provide some of the information, notably
407 // which thread-tracker to use. It is safe to create even if activity 424 // which thread-tracker to use. It is safe to create even if activity
408 // tracking is not enabled. 425 // tracking is not enabled.
409 class BASE_EXPORT ScopedThreadActivity 426 class BASE_EXPORT ScopedThreadActivity
410 : public ThreadActivityTracker::ScopedActivity { 427 : public ThreadActivityTracker::ScopedActivity {
411 public: 428 public:
412 ScopedThreadActivity(const void* origin, 429 ScopedThreadActivity(const void* program_counter,
430 const void* origin,
413 Activity::Type type, 431 Activity::Type type,
414 const ActivityData& data, 432 const ActivityData& data,
415 bool lock_allowed) 433 bool lock_allowed)
416 : ThreadActivityTracker::ScopedActivity( 434 : ThreadActivityTracker::ScopedActivity(
417 GetOrCreateTracker(lock_allowed), 435 GetOrCreateTracker(lock_allowed),
436 program_counter,
418 origin, 437 origin,
419 type, 438 type,
420 data) {} 439 data) {}
421 440
422 private: 441 private:
423 // Gets (or creates) a tracker for the current thread. If locking is not 442 // Gets (or creates) a tracker for the current thread. If locking is not
424 // allowed (because a lock is being tracked which would cause recursion) 443 // allowed (because a lock is being tracked which would cause recursion)
425 // then the attempt to create one if none found will be skipped. Once 444 // then the attempt to create one if none found will be skipped. Once
426 // the tracker for this thread has been created for other reasons, locks 445 // the tracker for this thread has been created for other reasons, locks
427 // will be tracked. The thread-tracker uses locks. 446 // will be tracked. The thread-tracker uses locks.
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after
577 // |info|. None of these values affect operation; they're all purely 596 // |info|. None of these values affect operation; they're all purely
578 // for association and analysis. To have unique identifiers across a 597 // for association and analysis. To have unique identifiers across a
579 // diverse code-base, create the number by taking the first 8 characters 598 // diverse code-base, create the number by taking the first 8 characters
580 // of the hash of the activity being tracked. 599 // of the hash of the activity being tracked.
581 // 600 //
582 // For example: 601 // For example:
583 // Tracking method: void MayNeverExit(uint32_t foo) {...} 602 // Tracking method: void MayNeverExit(uint32_t foo) {...}
584 // echo -n "MayNeverExit" | sha1sum => e44873ccab21e2b71270da24aa1... 603 // echo -n "MayNeverExit" | sha1sum => e44873ccab21e2b71270da24aa1...
585 // 604 //
586 // void MayNeverExit(int32_t foo) { 605 // void MayNeverExit(int32_t foo) {
587 // base::debug::ScopedActivity track_me(FROM_HERE, 0, 0xE44873CC, foo); 606 // base::debug::ScopedActivity track_me(0, 0xE44873CC, foo);
588 // ... 607 // ...
589 // } 608 // }
590 ScopedActivity(const tracked_objects::Location& location, 609 ALWAYS_INLINE
591 uint8_t action, 610 ScopedActivity(uint8_t action, uint32_t id, int32_t info)
592 uint32_t id, 611 : ScopedActivity(::tracked_objects::GetProgramCounter(),
593 int32_t info); 612 action,
594 613 id,
595 // Because this is inline, the FROM_HERE macro will resolve the current 614 info) {}
596 // program-counter as the location in the calling code. 615 ScopedActivity() : ScopedActivity(0, 0, 0) {}
597 ScopedActivity() : ScopedActivity(FROM_HERE, 0, 0, 0) {}
598 616
599 // Changes the |action| and/or |info| of this activity on the stack. This 617 // Changes the |action| and/or |info| of this activity on the stack. This
600 // is useful for tracking progress through a function, updating the action 618 // is useful for tracking progress through a function, updating the action
601 // to indicate "milestones" in the block (max 16 milestones: 0-15) or the 619 // to indicate "milestones" in the block (max 16 milestones: 0-15) or the
602 // info to reflect other changes. Changing both is not atomic so a snapshot 620 // info to reflect other changes. Changing both is not atomic so a snapshot
603 // operation could occur between the update of |action| and |info|. 621 // operation could occur between the update of |action| and |info|.
604 void ChangeAction(uint8_t action); 622 void ChangeAction(uint8_t action);
605 void ChangeInfo(int32_t info); 623 void ChangeInfo(int32_t info);
606 void ChangeActionAndInfo(uint8_t action, int32_t info); 624 void ChangeActionAndInfo(uint8_t action, int32_t info);
607 625
608 private: 626 private:
627 // Constructs the object using a passed-in program-counter.
628 ScopedActivity(const void* program_counter,
629 uint8_t action,
630 uint32_t id,
631 int32_t info);
632
609 // A copy of the ID code so it doesn't have to be passed by the caller when 633 // A copy of the ID code so it doesn't have to be passed by the caller when
610 // changing the |info| field. 634 // changing the |info| field.
611 uint32_t id_; 635 uint32_t id_;
612 636
613 DISALLOW_COPY_AND_ASSIGN(ScopedActivity); 637 DISALLOW_COPY_AND_ASSIGN(ScopedActivity);
614 }; 638 };
615 639
616 640
617 // These "scoped" classes provide easy tracking of various blocking actions. 641 // These "scoped" classes provide easy tracking of various blocking actions.
618 642
619 class BASE_EXPORT ScopedTaskRunActivity 643 class BASE_EXPORT ScopedTaskRunActivity
620 : public GlobalActivityTracker::ScopedThreadActivity { 644 : public GlobalActivityTracker::ScopedThreadActivity {
621 public: 645 public:
622 explicit ScopedTaskRunActivity(const base::PendingTask& task); 646 ALWAYS_INLINE
647 explicit ScopedTaskRunActivity(const base::PendingTask& task)
648 : ScopedTaskRunActivity(::tracked_objects::GetProgramCounter(),
649 task) {}
650
623 private: 651 private:
652 ScopedTaskRunActivity(const void* program_counter,
653 const base::PendingTask& task);
624 DISALLOW_COPY_AND_ASSIGN(ScopedTaskRunActivity); 654 DISALLOW_COPY_AND_ASSIGN(ScopedTaskRunActivity);
625 }; 655 };
626 656
627 class BASE_EXPORT ScopedLockAcquireActivity 657 class BASE_EXPORT ScopedLockAcquireActivity
628 : public GlobalActivityTracker::ScopedThreadActivity { 658 : public GlobalActivityTracker::ScopedThreadActivity {
629 public: 659 public:
630 explicit ScopedLockAcquireActivity(const base::internal::LockImpl* lock); 660 ALWAYS_INLINE
661 explicit ScopedLockAcquireActivity(const base::internal::LockImpl* lock)
662 : ScopedLockAcquireActivity(::tracked_objects::GetProgramCounter(),
663 lock) {}
664
631 private: 665 private:
666 ScopedLockAcquireActivity(const void* program_counter,
667 const base::internal::LockImpl* lock);
632 DISALLOW_COPY_AND_ASSIGN(ScopedLockAcquireActivity); 668 DISALLOW_COPY_AND_ASSIGN(ScopedLockAcquireActivity);
633 }; 669 };
634 670
635 class BASE_EXPORT ScopedEventWaitActivity 671 class BASE_EXPORT ScopedEventWaitActivity
636 : public GlobalActivityTracker::ScopedThreadActivity { 672 : public GlobalActivityTracker::ScopedThreadActivity {
637 public: 673 public:
638 explicit ScopedEventWaitActivity(const base::WaitableEvent* event); 674 ALWAYS_INLINE
675 explicit ScopedEventWaitActivity(const base::WaitableEvent* event)
676 : ScopedEventWaitActivity(::tracked_objects::GetProgramCounter(),
677 event) {}
678
639 private: 679 private:
680 ScopedEventWaitActivity(const void* program_counter,
681 const base::WaitableEvent* event);
640 DISALLOW_COPY_AND_ASSIGN(ScopedEventWaitActivity); 682 DISALLOW_COPY_AND_ASSIGN(ScopedEventWaitActivity);
641 }; 683 };
642 684
643 class BASE_EXPORT ScopedThreadJoinActivity 685 class BASE_EXPORT ScopedThreadJoinActivity
644 : public GlobalActivityTracker::ScopedThreadActivity { 686 : public GlobalActivityTracker::ScopedThreadActivity {
645 public: 687 public:
646 explicit ScopedThreadJoinActivity(const base::PlatformThreadHandle* thread); 688 ALWAYS_INLINE
689 explicit ScopedThreadJoinActivity(const base::PlatformThreadHandle* thread)
690 : ScopedThreadJoinActivity(::tracked_objects::GetProgramCounter(),
691 thread) {}
692
647 private: 693 private:
694 ScopedThreadJoinActivity(const void* program_counter,
695 const base::PlatformThreadHandle* thread);
648 DISALLOW_COPY_AND_ASSIGN(ScopedThreadJoinActivity); 696 DISALLOW_COPY_AND_ASSIGN(ScopedThreadJoinActivity);
649 }; 697 };
650 698
651 // Some systems don't have base::Process 699 // Some systems don't have base::Process
652 #if !defined(OS_NACL) && !defined(OS_IOS) 700 #if !defined(OS_NACL) && !defined(OS_IOS)
653 class BASE_EXPORT ScopedProcessWaitActivity 701 class BASE_EXPORT ScopedProcessWaitActivity
654 : public GlobalActivityTracker::ScopedThreadActivity { 702 : public GlobalActivityTracker::ScopedThreadActivity {
655 public: 703 public:
656 explicit ScopedProcessWaitActivity(const base::Process* process); 704 ALWAYS_INLINE
705 explicit ScopedProcessWaitActivity(const base::Process* process)
706 : ScopedProcessWaitActivity(::tracked_objects::GetProgramCounter(),
707 process) {}
708
657 private: 709 private:
710 ScopedProcessWaitActivity(const void* program_counter,
711 const base::Process* process);
658 DISALLOW_COPY_AND_ASSIGN(ScopedProcessWaitActivity); 712 DISALLOW_COPY_AND_ASSIGN(ScopedProcessWaitActivity);
659 }; 713 };
660 #endif 714 #endif
661 715
662 } // namespace debug 716 } // namespace debug
663 } // namespace base 717 } // namespace base
664 718
665 #endif // BASE_DEBUG_ACTIVITY_TRACKER_H_ 719 #endif // BASE_DEBUG_ACTIVITY_TRACKER_H_
OLDNEW
« no previous file with comments | « base/debug/activity_analyzer.cc ('k') | base/debug/activity_tracker.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698