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

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

Issue 2702413006: Enable storing last-dispatched exception per-thread. (Closed)
Patch Set: some cleanup Created 3 years, 9 months 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 | « no previous file | base/debug/activity_tracker.cc » ('j') | base/debug/activity_tracker.cc » ('J')
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
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
89 uint32_t padding; 89 uint32_t padding;
90 int64_t process_id; 90 int64_t process_id;
91 int64_t create_stamp; 91 int64_t create_stamp;
92 }; 92 };
93 93
94 // The data associated with an activity is dependent upon the activity type. 94 // The data associated with an activity is dependent upon the activity type.
95 // This union defines all of the various fields. All fields must be explicitly 95 // This union defines all of the various fields. All fields must be explicitly
96 // sized types to ensure no interoperability problems between 32-bit and 96 // sized types to ensure no interoperability problems between 32-bit and
97 // 64-bit systems. 97 // 64-bit systems.
98 union ActivityData { 98 union ActivityData {
99 // Expected size for 32/64-bit check.
100 // TODO(bcwhite): VC2015 doesn't allow statics in unions. Fix when it does.
101 // static constexpr size_t kExpectedInstanceSize = 8;
102
99 // Generic activities don't have any defined structure. 103 // Generic activities don't have any defined structure.
100 struct { 104 struct {
101 uint32_t id; // An arbitrary identifier used for association. 105 uint32_t id; // An arbitrary identifier used for association.
102 int32_t info; // An arbitrary value used for information purposes. 106 int32_t info; // An arbitrary value used for information purposes.
103 } generic; 107 } generic;
104 struct { 108 struct {
105 uint64_t sequence_id; // The sequence identifier of the posted task. 109 uint64_t sequence_id; // The sequence identifier of the posted task.
106 } task; 110 } task;
107 struct { 111 struct {
108 uint64_t lock_address; // The memory address of the lock object. 112 uint64_t lock_address; // The memory address of the lock object.
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
226 230
227 DISALLOW_COPY_AND_ASSIGN(ActivityTrackerMemoryAllocator); 231 DISALLOW_COPY_AND_ASSIGN(ActivityTrackerMemoryAllocator);
228 }; 232 };
229 233
230 234
231 // This structure is the full contents recorded for every activity pushed 235 // This structure is the full contents recorded for every activity pushed
232 // onto the stack. The |activity_type| indicates what is actually stored in 236 // onto the stack. The |activity_type| indicates what is actually stored in
233 // the |data| field. All fields must be explicitly sized types to ensure no 237 // the |data| field. All fields must be explicitly sized types to ensure no
234 // interoperability problems between 32-bit and 64-bit systems. 238 // interoperability problems between 32-bit and 64-bit systems.
235 struct Activity { 239 struct Activity {
240 // Expected size for 32/64-bit check.
241 static constexpr size_t kExpectedInstanceSize =
242 40 + 8 * kActivityCallStackSize +
243 /*ActivityData::kExpectedInstanceSize=*/8;
244
236 // The type of an activity on the stack. Activities are broken into 245 // The type of an activity on the stack. Activities are broken into
237 // categories with the category ID taking the top 4 bits and the lower 246 // categories with the category ID taking the top 4 bits and the lower
238 // bits representing an action within that category. This combination 247 // bits representing an action within that category. This combination
239 // makes it easy to "switch" based on the type during analysis. 248 // makes it easy to "switch" based on the type during analysis.
240 enum Type : uint8_t { 249 enum Type : uint8_t {
241 // This "null" constant is used to indicate "do not change" in calls. 250 // This "null" constant is used to indicate "do not change" in calls.
242 ACT_NULL = 0, 251 ACT_NULL = 0,
243 252
244 // Task activities involve callbacks posted to a thread or thread-pool 253 // Task activities involve callbacks posted to a thread or thread-pool
245 // using the PostTask() method or any of its friends. 254 // using the PostTask() method or any of its friends.
(...skipping 13 matching lines...) Expand all
259 // Thread activities involve the life management of threads. 268 // Thread activities involve the life management of threads.
260 ACT_THREAD = 4 << 4, 269 ACT_THREAD = 4 << 4,
261 ACT_THREAD_START = ACT_THREAD, 270 ACT_THREAD_START = ACT_THREAD,
262 ACT_THREAD_JOIN, 271 ACT_THREAD_JOIN,
263 272
264 // Process activities involve the life management of processes. 273 // Process activities involve the life management of processes.
265 ACT_PROCESS = 5 << 4, 274 ACT_PROCESS = 5 << 4,
266 ACT_PROCESS_START = ACT_PROCESS, 275 ACT_PROCESS_START = ACT_PROCESS,
267 ACT_PROCESS_WAIT, 276 ACT_PROCESS_WAIT,
268 277
278 // Exception activities indicate the occurence of something unexpected.
279 ACT_EXCEPTION = 14 << 4,
280
269 // Generic activities are user defined and can be anything. 281 // Generic activities are user defined and can be anything.
270 ACT_GENERIC = 15 << 4, 282 ACT_GENERIC = 15 << 4,
271 283
272 // These constants can be used to separate the category and action from 284 // These constants can be used to separate the category and action from
273 // a combined activity type. 285 // a combined activity type.
274 ACT_CATEGORY_MASK = 0xF << 4, 286 ACT_CATEGORY_MASK = 0xF << 4,
275 ACT_ACTION_MASK = 0xF 287 ACT_ACTION_MASK = 0xF
276 }; 288 };
277 289
278 // Internal representation of time. During collection, this is in "ticks" 290 // Internal representation of time. During collection, this is in "ticks"
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
370 friend class ActivityUserData; 382 friend class ActivityUserData;
371 383
372 ValueType type_; 384 ValueType type_;
373 uint64_t short_value_; // Used to hold copy of numbers, etc. 385 uint64_t short_value_; // Used to hold copy of numbers, etc.
374 std::string long_value_; // Used to hold copy of raw/string data. 386 std::string long_value_; // Used to hold copy of raw/string data.
375 StringPiece ref_value_; // Used to hold reference to external data. 387 StringPiece ref_value_; // Used to hold reference to external data.
376 }; 388 };
377 389
378 using Snapshot = std::map<std::string, TypedValue>; 390 using Snapshot = std::map<std::string, TypedValue>;
379 391
392 ActivityUserData();
380 ActivityUserData(void* memory, size_t size); 393 ActivityUserData(void* memory, size_t size);
381 virtual ~ActivityUserData(); 394 virtual ~ActivityUserData();
382 395
383 // Gets the unique ID number for this user data. If this changes then the 396 // Gets the unique ID number for this user data. If this changes then the
384 // contents have been overwritten by another thread. The return value is 397 // contents have been overwritten by another thread. The return value is
385 // always non-zero unless it's actually just a data "sink". 398 // always non-zero unless it's actually just a data "sink".
386 uint32_t id() const { 399 uint32_t id() const {
387 return header_ ? header_->owner.data_id.load(std::memory_order_relaxed) : 0; 400 return header_ ? header_->owner.data_id.load(std::memory_order_relaxed) : 0;
388 } 401 }
389 402
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after
564 int64_t process_id = 0; 577 int64_t process_id = 0;
565 int64_t thread_id = 0; 578 int64_t thread_id = 0;
566 579
567 // The current stack of activities that are underway for this thread. It 580 // The current stack of activities that are underway for this thread. It
568 // is limited in its maximum size with later entries being left off. 581 // is limited in its maximum size with later entries being left off.
569 std::vector<Activity> activity_stack; 582 std::vector<Activity> activity_stack;
570 583
571 // The current total depth of the activity stack, including those later 584 // The current total depth of the activity stack, including those later
572 // entries not recorded in the |activity_stack| vector. 585 // entries not recorded in the |activity_stack| vector.
573 uint32_t activity_stack_depth = 0; 586 uint32_t activity_stack_depth = 0;
587
588 // The last recorded "exception" activity.
589 Activity last_exception;
574 }; 590 };
575 591
576 // This is the base class for having the compiler manage an activity on the 592 // This is the base class for having the compiler manage an activity on the
577 // tracker's stack. It does nothing but call methods on the passed |tracker| 593 // tracker's stack. It does nothing but call methods on the passed |tracker|
578 // if it is not null, making it safe (and cheap) to create these objects 594 // if it is not null, making it safe (and cheap) to create these objects
579 // even if activity tracking is not enabled. 595 // even if activity tracking is not enabled.
580 class BASE_EXPORT ScopedActivity { 596 class BASE_EXPORT ScopedActivity {
581 public: 597 public:
582 ScopedActivity(ThreadActivityTracker* tracker, 598 ScopedActivity(ThreadActivityTracker* tracker,
583 const void* program_counter, 599 const void* program_counter,
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
647 ActivityTrackerMemoryAllocator* allocator); 663 ActivityTrackerMemoryAllocator* allocator);
648 664
649 // Returns if there is true use-data associated with a given ActivityId since 665 // Returns if there is true use-data associated with a given ActivityId since
650 // it's possible than any returned object is just a sink. 666 // it's possible than any returned object is just a sink.
651 bool HasUserData(ActivityId id); 667 bool HasUserData(ActivityId id);
652 668
653 // Release the user-data information for an activity. 669 // Release the user-data information for an activity.
654 void ReleaseUserData(ActivityId id, 670 void ReleaseUserData(ActivityId id,
655 ActivityTrackerMemoryAllocator* allocator); 671 ActivityTrackerMemoryAllocator* allocator);
656 672
673 // Save an exception and return space for additional information.
674 ActivityUserData& ExceptionActivity(
675 const void* program_counter,
676 const void* origin,
677 Activity::Type type,
678 const ActivityData& data,
679 ActivityTrackerMemoryAllocator* allocator);
680
657 // Returns whether the current data is valid or not. It is not valid if 681 // Returns whether the current data is valid or not. It is not valid if
658 // corruption has been detected in the header or other data structures. 682 // corruption has been detected in the header or other data structures.
659 bool IsValid() const; 683 bool IsValid() const;
660 684
661 // Gets a copy of the tracker contents for analysis. Returns false if a 685 // Gets a copy of the tracker contents for analysis. Returns false if a
662 // snapshot was not possible, perhaps because the data is not valid; the 686 // snapshot was not possible, perhaps because the data is not valid; the
663 // contents of |output_snapshot| are undefined in that case. The current 687 // contents of |output_snapshot| are undefined in that case. The current
664 // implementation does not support concurrent snapshot operations. 688 // implementation does not support concurrent snapshot operations.
665 bool CreateSnapshot(Snapshot* output_snapshot) const; 689 bool CreateSnapshot(Snapshot* output_snapshot) const;
666 690
(...skipping 10 matching lines...) Expand all
677 ProcessId* out_id, 701 ProcessId* out_id,
678 int64_t* out_stamp); 702 int64_t* out_stamp);
679 703
680 // Calculates the memory size required for a given stack depth, including 704 // Calculates the memory size required for a given stack depth, including
681 // the internal header structure for the stack. 705 // the internal header structure for the stack.
682 static size_t SizeForStackDepth(int stack_depth); 706 static size_t SizeForStackDepth(int stack_depth);
683 707
684 private: 708 private:
685 friend class ActivityTrackerTest; 709 friend class ActivityTrackerTest;
686 710
711 std::unique_ptr<ActivityUserData> CreateUserDataForActivity(
712 Activity* activity,
713 ActivityTrackerMemoryAllocator* allocator);
714
687 Header* const header_; // Pointer to the Header structure. 715 Header* const header_; // Pointer to the Header structure.
688 Activity* const stack_; // The stack of activities. 716 Activity* const stack_; // The stack of activities.
689 const uint32_t stack_slots_; // The total number of stack slots. 717 const uint32_t stack_slots_; // The total number of stack slots.
690 718
691 bool valid_ = false; // Tracks whether the data is valid or not. 719 bool valid_ = false; // Tracks whether the data is valid or not.
692 720
721 // A user-data object for information associated with the last exception.
722 std::unique_ptr<ActivityUserData> exception_data;
723
693 base::ThreadChecker thread_checker_; 724 base::ThreadChecker thread_checker_;
694 725
695 DISALLOW_COPY_AND_ASSIGN(ThreadActivityTracker); 726 DISALLOW_COPY_AND_ASSIGN(ThreadActivityTracker);
696 }; 727 };
697 728
698 729
699 // The global tracker manages all the individual thread trackers. Memory for 730 // The global tracker manages all the individual thread trackers. Memory for
700 // the thread trackers is taken from a PersistentMemoryAllocator which allows 731 // the thread trackers is taken from a PersistentMemoryAllocator which allows
701 // for the data to be analyzed by a parallel process or even post-mortem. 732 // for the data to be analyzed by a parallel process or even post-mortem.
702 class BASE_EXPORT GlobalActivityTracker { 733 class BASE_EXPORT GlobalActivityTracker {
(...skipping 19 matching lines...) Expand all
722 // An enumeration of common process life stages. All entries are given an 753 // An enumeration of common process life stages. All entries are given an
723 // explicit number so they are known and remain constant; this allows for 754 // explicit number so they are known and remain constant; this allows for
724 // cross-version analysis either locally or on a server. 755 // cross-version analysis either locally or on a server.
725 enum ProcessPhase : int { 756 enum ProcessPhase : int {
726 // The phases are generic and may have meaning to the tracker. 757 // The phases are generic and may have meaning to the tracker.
727 PROCESS_PHASE_UNKNOWN = 0, 758 PROCESS_PHASE_UNKNOWN = 0,
728 PROCESS_LAUNCHED = 1, 759 PROCESS_LAUNCHED = 1,
729 PROCESS_LAUNCH_FAILED = 2, 760 PROCESS_LAUNCH_FAILED = 2,
730 PROCESS_EXITED_CLEANLY = 10, 761 PROCESS_EXITED_CLEANLY = 10,
731 PROCESS_EXITED_WITH_CODE = 11, 762 PROCESS_EXITED_WITH_CODE = 11,
763 PROCESS_UNHANDLED_EXCEPTION = 50,
manzagop (departed) 2017/02/24 19:06:14 Perhaps this should be kept separate (e.g. a hit-e
bcwhite 2017/02/24 19:10:58 Actually, I need to remove it because it writes to
732 764
733 // Add here whatever is useful for analysis. 765 // Add here whatever is useful for analysis.
734 PROCESS_SHUTDOWN_STARTED = 100, 766 PROCESS_SHUTDOWN_STARTED = 100,
735 PROCESS_MAIN_LOOP_STARTED = 101, 767 PROCESS_MAIN_LOOP_STARTED = 101,
736 }; 768 };
737 769
738 // A callback made when a process exits to allow immediate analysis of its 770 // A callback made when a process exits to allow immediate analysis of its
739 // data. Note that the system may reuse the |process_id| so when fetching 771 // data. Note that the system may reuse the |process_id| so when fetching
740 // records its important to ensure that what is returned was created before 772 // records its important to ensure that what is returned was created before
741 // the |exit_stamp|. Movement of |process_data| information is allowed. 773 // the |exit_stamp|. Movement of |process_data| information is allowed.
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after
900 const FilePath::StringType& args) { 932 const FilePath::StringType& args) {
901 GlobalActivityTracker* tracker = Get(); 933 GlobalActivityTracker* tracker = Get();
902 if (tracker) 934 if (tracker)
903 tracker->RecordProcessLaunch(process_id, exe, args); 935 tracker->RecordProcessLaunch(process_id, exe, args);
904 } 936 }
905 static void RecordProcessExitIfEnabled(ProcessId process_id, int exit_code) { 937 static void RecordProcessExitIfEnabled(ProcessId process_id, int exit_code) {
906 GlobalActivityTracker* tracker = Get(); 938 GlobalActivityTracker* tracker = Get();
907 if (tracker) 939 if (tracker)
908 tracker->RecordProcessExit(process_id, exit_code); 940 tracker->RecordProcessExit(process_id, exit_code);
909 } 941 }
942
910 // Sets the "phase" of the current process, useful for knowing what it was 943 // Sets the "phase" of the current process, useful for knowing what it was
911 // doing when it last reported. 944 // doing when it last reported.
912 void SetProcessPhase(ProcessPhase phase); 945 void SetProcessPhase(ProcessPhase phase);
913 static void SetProcessPhaseIfEnabled(ProcessPhase phase) { 946 static void SetProcessPhaseIfEnabled(ProcessPhase phase) {
914 GlobalActivityTracker* tracker = Get(); 947 GlobalActivityTracker* tracker = Get();
915 if (tracker) 948 if (tracker)
916 tracker->SetProcessPhase(phase); 949 tracker->SetProcessPhase(phase);
917 } 950 }
918 951
919 // Records a log message. The current implementation does NOT recycle these 952 // Records a log message. The current implementation does NOT recycle these
920 // only store critical messages such as FATAL ones. 953 // only store critical messages such as FATAL ones.
921 void RecordLogMessage(StringPiece message); 954 void RecordLogMessage(StringPiece message);
922 955
923 // Records a module load/unload event. This is safe to call multiple times 956 // Records a module load/unload event. This is safe to call multiple times
924 // even with the same information. 957 // even with the same information.
925 void RecordModuleInfo(const ModuleInfo& info); 958 void RecordModuleInfo(const ModuleInfo& info);
926 959
927 // Record field trial information. This call is thread-safe. In addition to 960 // Record field trial information. This call is thread-safe. In addition to
928 // this, construction of a GlobalActivityTracker will cause all existing 961 // this, construction of a GlobalActivityTracker will cause all existing
929 // active field trials to be fetched and recorded. 962 // active field trials to be fetched and recorded.
930 void RecordFieldTrial(const std::string& trial_name, StringPiece group_name); 963 void RecordFieldTrial(const std::string& trial_name, StringPiece group_name);
931 964
965 // Record exception information for the current thread and return space where
966 // additional information may be recorded.
967 // TODO(bcwhite): More parameters (space for 4 + 64 bits).
968 ALWAYS_INLINE
969 ActivityUserData& RecordException(const void* origin) {
970 return RecordExceptionImpl(::tracked_objects::GetProgramCounter(), origin);
Sigurður Ásgeirsson 2017/02/24 18:37:41 no - this the program counter will have to come fr
bcwhite 2017/02/24 19:10:58 Every activity holds the PC of where it was create
971 }
972
932 // Accesses the process data record for storing arbitrary key/value pairs. 973 // Accesses the process data record for storing arbitrary key/value pairs.
933 // Updates to this are thread-safe. 974 // Updates to this are thread-safe.
934 ActivityUserData& process_data() { return process_data_; } 975 ActivityUserData& process_data() { return process_data_; }
935 976
936 // Accesses the global data record for storing arbitrary key/value pairs. 977 // Accesses the global data record for storing arbitrary key/value pairs.
937 // Updates to this are thread-safe. 978 // Updates to this are thread-safe.
938 ActivityUserData& global_data() { return global_data_; } 979 ActivityUserData& global_data() { return global_data_; }
939 980
940 private: 981 private:
941 friend class GlobalActivityAnalyzer; 982 friend class GlobalActivityAnalyzer;
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
1039 // Creates a global tracker using a given persistent-memory |allocator| and 1080 // Creates a global tracker using a given persistent-memory |allocator| and
1040 // providing the given |stack_depth| to each thread tracker it manages. The 1081 // providing the given |stack_depth| to each thread tracker it manages. The
1041 // created object is activated so tracking has already started upon return. 1082 // created object is activated so tracking has already started upon return.
1042 GlobalActivityTracker(std::unique_ptr<PersistentMemoryAllocator> allocator, 1083 GlobalActivityTracker(std::unique_ptr<PersistentMemoryAllocator> allocator,
1043 int stack_depth); 1084 int stack_depth);
1044 1085
1045 // Returns the memory used by an activity-tracker managed by this class. 1086 // Returns the memory used by an activity-tracker managed by this class.
1046 // It is called during the destruction of a ManagedActivityTracker object. 1087 // It is called during the destruction of a ManagedActivityTracker object.
1047 void ReturnTrackerMemory(ManagedActivityTracker* tracker); 1088 void ReturnTrackerMemory(ManagedActivityTracker* tracker);
1048 1089
1090 // Records exception information.
1091 ActivityUserData& RecordExceptionImpl(const void* pc, const void* origin);
1092
1049 // Releases the activity-tracker associcated with thread. It is called 1093 // Releases the activity-tracker associcated with thread. It is called
1050 // automatically when a thread is joined and thus there is nothing more to 1094 // automatically when a thread is joined and thus there is nothing more to
1051 // be tracked. |value| is a pointer to a ManagedActivityTracker. 1095 // be tracked. |value| is a pointer to a ManagedActivityTracker.
1052 static void OnTLSDestroy(void* value); 1096 static void OnTLSDestroy(void* value);
1053 1097
1054 // Does process-exit work. This can be run on any thread. 1098 // Does process-exit work. This can be run on any thread.
1055 void CleanupAfterProcess(ProcessId process_id, 1099 void CleanupAfterProcess(ProcessId process_id,
1056 int64_t exit_stamp, 1100 int64_t exit_stamp,
1057 int exit_code, 1101 int exit_code,
1058 std::string&& command_line); 1102 std::string&& command_line);
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after
1232 ScopedProcessWaitActivity(const void* program_counter, 1276 ScopedProcessWaitActivity(const void* program_counter,
1233 const base::Process* process); 1277 const base::Process* process);
1234 DISALLOW_COPY_AND_ASSIGN(ScopedProcessWaitActivity); 1278 DISALLOW_COPY_AND_ASSIGN(ScopedProcessWaitActivity);
1235 }; 1279 };
1236 #endif 1280 #endif
1237 1281
1238 } // namespace debug 1282 } // namespace debug
1239 } // namespace base 1283 } // namespace base
1240 1284
1241 #endif // BASE_DEBUG_ACTIVITY_TRACKER_H_ 1285 #endif // BASE_DEBUG_ACTIVITY_TRACKER_H_
OLDNEW
« no previous file with comments | « no previous file | base/debug/activity_tracker.cc » ('j') | base/debug/activity_tracker.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698