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

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

Issue 2702413006: Enable storing last-dispatched exception per-thread. (Closed)
Patch Set: fixed test (larger memory buffer) 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') | 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
(...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.
109 } lock; 113 } lock;
110 struct { 114 struct {
111 uint64_t event_address; // The memory address of the event object. 115 uint64_t event_address; // The memory address of the event object.
112 } event; 116 } event;
113 struct { 117 struct {
114 int64_t thread_id; // A unique identifier for a thread within a process. 118 int64_t thread_id; // A unique identifier for a thread within a process.
115 } thread; 119 } thread;
116 struct { 120 struct {
117 int64_t process_id; // A unique identifier for a process. 121 int64_t process_id; // A unique identifier for a process.
118 } process; 122 } process;
123 struct {
124 uint32_t code; // An "exception code" number.
125 } exception;
119 126
120 // These methods create an ActivityData object from the appropriate 127 // These methods create an ActivityData object from the appropriate
121 // parameters. Objects of this type should always be created this way to 128 // parameters. Objects of this type should always be created this way to
122 // ensure that no fields remain unpopulated should the set of recorded 129 // ensure that no fields remain unpopulated should the set of recorded
123 // fields change. They're defined inline where practical because they 130 // fields change. They're defined inline where practical because they
124 // reduce to loading a small local structure with a few values, roughly 131 // reduce to loading a small local structure with a few values, roughly
125 // the same as loading all those values into parameters. 132 // the same as loading all those values into parameters.
126 133
127 static ActivityData ForGeneric(uint32_t id, int32_t info) { 134 static ActivityData ForGeneric(uint32_t id, int32_t info) {
128 ActivityData data; 135 ActivityData data;
(...skipping 25 matching lines...) Expand all
154 ActivityData data; 161 ActivityData data;
155 data.thread.thread_id = id; 162 data.thread.thread_id = id;
156 return data; 163 return data;
157 } 164 }
158 165
159 static ActivityData ForProcess(const int64_t id) { 166 static ActivityData ForProcess(const int64_t id) {
160 ActivityData data; 167 ActivityData data;
161 data.process.process_id = id; 168 data.process.process_id = id;
162 return data; 169 return data;
163 } 170 }
171
172 static ActivityData ForException(const uint32_t code) {
173 ActivityData data;
174 data.exception.code = code;
175 return data;
176 }
164 }; 177 };
165 178
166 // A "null" activity-data that can be passed to indicate "do not change". 179 // A "null" activity-data that can be passed to indicate "do not change".
167 extern const ActivityData kNullActivityData; 180 extern const ActivityData kNullActivityData;
168 181
169 182
170 // A helper class that is used for managing memory allocations within a 183 // A helper class that is used for managing memory allocations within a
171 // persistent memory allocator. Instances of this class are NOT thread-safe. 184 // persistent memory allocator. Instances of this class are NOT thread-safe.
172 // Use from a single thread or protect access with a lock. 185 // Use from a single thread or protect access with a lock.
173 class BASE_EXPORT ActivityTrackerMemoryAllocator { 186 class BASE_EXPORT ActivityTrackerMemoryAllocator {
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
265 // Thread activities involve the life management of threads. 278 // Thread activities involve the life management of threads.
266 ACT_THREAD = 4 << 4, 279 ACT_THREAD = 4 << 4,
267 ACT_THREAD_START = ACT_THREAD, 280 ACT_THREAD_START = ACT_THREAD,
268 ACT_THREAD_JOIN, 281 ACT_THREAD_JOIN,
269 282
270 // Process activities involve the life management of processes. 283 // Process activities involve the life management of processes.
271 ACT_PROCESS = 5 << 4, 284 ACT_PROCESS = 5 << 4,
272 ACT_PROCESS_START = ACT_PROCESS, 285 ACT_PROCESS_START = ACT_PROCESS,
273 ACT_PROCESS_WAIT, 286 ACT_PROCESS_WAIT,
274 287
288 // Exception activities indicate the occurence of something unexpected.
289 ACT_EXCEPTION = 14 << 4,
290
275 // Generic activities are user defined and can be anything. 291 // Generic activities are user defined and can be anything.
276 ACT_GENERIC = 15 << 4, 292 ACT_GENERIC = 15 << 4,
277 293
278 // These constants can be used to separate the category and action from 294 // These constants can be used to separate the category and action from
279 // a combined activity type. 295 // a combined activity type.
280 ACT_CATEGORY_MASK = 0xF << 4, 296 ACT_CATEGORY_MASK = 0xF << 4,
281 ACT_ACTION_MASK = 0xF 297 ACT_ACTION_MASK = 0xF
282 }; 298 };
283 299
284 // Internal representation of time. During collection, this is in "ticks" 300 // Internal representation of time. During collection, this is in "ticks"
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
378 friend class ActivityUserData; 394 friend class ActivityUserData;
379 395
380 ValueType type_; 396 ValueType type_;
381 uint64_t short_value_; // Used to hold copy of numbers, etc. 397 uint64_t short_value_; // Used to hold copy of numbers, etc.
382 std::string long_value_; // Used to hold copy of raw/string data. 398 std::string long_value_; // Used to hold copy of raw/string data.
383 StringPiece ref_value_; // Used to hold reference to external data. 399 StringPiece ref_value_; // Used to hold reference to external data.
384 }; 400 };
385 401
386 using Snapshot = std::map<std::string, TypedValue>; 402 using Snapshot = std::map<std::string, TypedValue>;
387 403
404 // Initialize the object either as a "sink" that just accepts and discards
405 // data or an active one that writes to a given (zeroed) memory block.
406 ActivityUserData();
388 ActivityUserData(void* memory, size_t size); 407 ActivityUserData(void* memory, size_t size);
389 virtual ~ActivityUserData(); 408 virtual ~ActivityUserData();
390 409
391 // Gets the unique ID number for this user data. If this changes then the 410 // Gets the unique ID number for this user data. If this changes then the
392 // contents have been overwritten by another thread. The return value is 411 // contents have been overwritten by another thread. The return value is
393 // always non-zero unless it's actually just a data "sink". 412 // always non-zero unless it's actually just a data "sink".
394 uint32_t id() const { 413 uint32_t id() const {
395 return header_ ? header_->owner.data_id.load(std::memory_order_relaxed) : 0; 414 return header_ ? header_->owner.data_id.load(std::memory_order_relaxed) : 0;
396 } 415 }
397 416
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after
572 int64_t process_id = 0; 591 int64_t process_id = 0;
573 int64_t thread_id = 0; 592 int64_t thread_id = 0;
574 593
575 // The current stack of activities that are underway for this thread. It 594 // The current stack of activities that are underway for this thread. It
576 // is limited in its maximum size with later entries being left off. 595 // is limited in its maximum size with later entries being left off.
577 std::vector<Activity> activity_stack; 596 std::vector<Activity> activity_stack;
578 597
579 // The current total depth of the activity stack, including those later 598 // The current total depth of the activity stack, including those later
580 // entries not recorded in the |activity_stack| vector. 599 // entries not recorded in the |activity_stack| vector.
581 uint32_t activity_stack_depth = 0; 600 uint32_t activity_stack_depth = 0;
601
602 // The last recorded "exception" activity.
603 Activity last_exception;
582 }; 604 };
583 605
584 // This is the base class for having the compiler manage an activity on the 606 // This is the base class for having the compiler manage an activity on the
585 // tracker's stack. It does nothing but call methods on the passed |tracker| 607 // tracker's stack. It does nothing but call methods on the passed |tracker|
586 // if it is not null, making it safe (and cheap) to create these objects 608 // if it is not null, making it safe (and cheap) to create these objects
587 // even if activity tracking is not enabled. 609 // even if activity tracking is not enabled.
588 class BASE_EXPORT ScopedActivity { 610 class BASE_EXPORT ScopedActivity {
589 public: 611 public:
590 ScopedActivity(ThreadActivityTracker* tracker, 612 ScopedActivity(ThreadActivityTracker* tracker,
591 const void* program_counter, 613 const void* program_counter,
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
655 ActivityTrackerMemoryAllocator* allocator); 677 ActivityTrackerMemoryAllocator* allocator);
656 678
657 // Returns if there is true use-data associated with a given ActivityId since 679 // Returns if there is true use-data associated with a given ActivityId since
658 // it's possible than any returned object is just a sink. 680 // it's possible than any returned object is just a sink.
659 bool HasUserData(ActivityId id); 681 bool HasUserData(ActivityId id);
660 682
661 // Release the user-data information for an activity. 683 // Release the user-data information for an activity.
662 void ReleaseUserData(ActivityId id, 684 void ReleaseUserData(ActivityId id,
663 ActivityTrackerMemoryAllocator* allocator); 685 ActivityTrackerMemoryAllocator* allocator);
664 686
687 // Save an exception. |origin| is the location of the exception.
688 void RecordExceptionActivity(const void* program_counter,
689 const void* origin,
690 Activity::Type type,
691 const ActivityData& data);
692
665 // Returns whether the current data is valid or not. It is not valid if 693 // Returns whether the current data is valid or not. It is not valid if
666 // corruption has been detected in the header or other data structures. 694 // corruption has been detected in the header or other data structures.
667 bool IsValid() const; 695 bool IsValid() const;
668 696
669 // Gets a copy of the tracker contents for analysis. Returns false if a 697 // Gets a copy of the tracker contents for analysis. Returns false if a
670 // snapshot was not possible, perhaps because the data is not valid; the 698 // snapshot was not possible, perhaps because the data is not valid; the
671 // contents of |output_snapshot| are undefined in that case. The current 699 // contents of |output_snapshot| are undefined in that case. The current
672 // implementation does not support concurrent snapshot operations. 700 // implementation does not support concurrent snapshot operations.
673 bool CreateSnapshot(Snapshot* output_snapshot) const; 701 bool CreateSnapshot(Snapshot* output_snapshot) const;
674 702
(...skipping 10 matching lines...) Expand all
685 ProcessId* out_id, 713 ProcessId* out_id,
686 int64_t* out_stamp); 714 int64_t* out_stamp);
687 715
688 // Calculates the memory size required for a given stack depth, including 716 // Calculates the memory size required for a given stack depth, including
689 // the internal header structure for the stack. 717 // the internal header structure for the stack.
690 static size_t SizeForStackDepth(int stack_depth); 718 static size_t SizeForStackDepth(int stack_depth);
691 719
692 private: 720 private:
693 friend class ActivityTrackerTest; 721 friend class ActivityTrackerTest;
694 722
723 std::unique_ptr<ActivityUserData> CreateUserDataForActivity(
724 Activity* activity,
725 ActivityTrackerMemoryAllocator* allocator);
726
695 Header* const header_; // Pointer to the Header structure. 727 Header* const header_; // Pointer to the Header structure.
696 Activity* const stack_; // The stack of activities. 728 Activity* const stack_; // The stack of activities.
697 const uint32_t stack_slots_; // The total number of stack slots. 729 const uint32_t stack_slots_; // The total number of stack slots.
698 730
699 bool valid_ = false; // Tracks whether the data is valid or not. 731 bool valid_ = false; // Tracks whether the data is valid or not.
700 732
701 base::ThreadChecker thread_checker_; 733 base::ThreadChecker thread_checker_;
702 734
703 DISALLOW_COPY_AND_ASSIGN(ThreadActivityTracker); 735 DISALLOW_COPY_AND_ASSIGN(ThreadActivityTracker);
704 }; 736 };
(...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after
913 const FilePath::StringType& args) { 945 const FilePath::StringType& args) {
914 GlobalActivityTracker* tracker = Get(); 946 GlobalActivityTracker* tracker = Get();
915 if (tracker) 947 if (tracker)
916 tracker->RecordProcessLaunch(process_id, exe, args); 948 tracker->RecordProcessLaunch(process_id, exe, args);
917 } 949 }
918 static void RecordProcessExitIfEnabled(ProcessId process_id, int exit_code) { 950 static void RecordProcessExitIfEnabled(ProcessId process_id, int exit_code) {
919 GlobalActivityTracker* tracker = Get(); 951 GlobalActivityTracker* tracker = Get();
920 if (tracker) 952 if (tracker)
921 tracker->RecordProcessExit(process_id, exit_code); 953 tracker->RecordProcessExit(process_id, exit_code);
922 } 954 }
955
923 // Sets the "phase" of the current process, useful for knowing what it was 956 // Sets the "phase" of the current process, useful for knowing what it was
924 // doing when it last reported. 957 // doing when it last reported.
925 void SetProcessPhase(ProcessPhase phase); 958 void SetProcessPhase(ProcessPhase phase);
926 static void SetProcessPhaseIfEnabled(ProcessPhase phase) { 959 static void SetProcessPhaseIfEnabled(ProcessPhase phase) {
927 GlobalActivityTracker* tracker = Get(); 960 GlobalActivityTracker* tracker = Get();
928 if (tracker) 961 if (tracker)
929 tracker->SetProcessPhase(phase); 962 tracker->SetProcessPhase(phase);
930 } 963 }
931 964
932 // Records a log message. The current implementation does NOT recycle these 965 // Records a log message. The current implementation does NOT recycle these
(...skipping 18 matching lines...) Expand all
951 // this, construction of a GlobalActivityTracker will cause all existing 984 // this, construction of a GlobalActivityTracker will cause all existing
952 // active field trials to be fetched and recorded. 985 // active field trials to be fetched and recorded.
953 void RecordFieldTrial(const std::string& trial_name, StringPiece group_name); 986 void RecordFieldTrial(const std::string& trial_name, StringPiece group_name);
954 static void RecordFieldTrialIfEnabled(const std::string& trial_name, 987 static void RecordFieldTrialIfEnabled(const std::string& trial_name,
955 StringPiece group_name) { 988 StringPiece group_name) {
956 GlobalActivityTracker* tracker = Get(); 989 GlobalActivityTracker* tracker = Get();
957 if (tracker) 990 if (tracker)
958 tracker->RecordFieldTrial(trial_name, group_name); 991 tracker->RecordFieldTrial(trial_name, group_name);
959 } 992 }
960 993
994 // Record exception information for the current thread.
995 ALWAYS_INLINE
996 void RecordException(const void* origin, uint32_t code) {
997 return RecordExceptionImpl(::tracked_objects::GetProgramCounter(), origin,
998 code);
999 }
1000
961 // Accesses the process data record for storing arbitrary key/value pairs. 1001 // Accesses the process data record for storing arbitrary key/value pairs.
962 // Updates to this are thread-safe. 1002 // Updates to this are thread-safe.
963 ActivityUserData& process_data() { return process_data_; } 1003 ActivityUserData& process_data() { return process_data_; }
964 1004
965 // Accesses the global data record for storing arbitrary key/value pairs. 1005 // Accesses the global data record for storing arbitrary key/value pairs.
966 // Updates to this are thread-safe. 1006 // Updates to this are thread-safe.
967 ActivityUserData& global_data() { return global_data_; } 1007 ActivityUserData& global_data() { return global_data_; }
968 1008
969 private: 1009 private:
970 friend class GlobalActivityAnalyzer; 1010 friend class GlobalActivityAnalyzer;
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
1068 // Creates a global tracker using a given persistent-memory |allocator| and 1108 // Creates a global tracker using a given persistent-memory |allocator| and
1069 // providing the given |stack_depth| to each thread tracker it manages. The 1109 // providing the given |stack_depth| to each thread tracker it manages. The
1070 // created object is activated so tracking has already started upon return. 1110 // created object is activated so tracking has already started upon return.
1071 GlobalActivityTracker(std::unique_ptr<PersistentMemoryAllocator> allocator, 1111 GlobalActivityTracker(std::unique_ptr<PersistentMemoryAllocator> allocator,
1072 int stack_depth); 1112 int stack_depth);
1073 1113
1074 // Returns the memory used by an activity-tracker managed by this class. 1114 // Returns the memory used by an activity-tracker managed by this class.
1075 // It is called during the destruction of a ManagedActivityTracker object. 1115 // It is called during the destruction of a ManagedActivityTracker object.
1076 void ReturnTrackerMemory(ManagedActivityTracker* tracker); 1116 void ReturnTrackerMemory(ManagedActivityTracker* tracker);
1077 1117
1118 // Records exception information.
1119 void RecordExceptionImpl(const void* pc, const void* origin, uint32_t code);
1120
1078 // Releases the activity-tracker associcated with thread. It is called 1121 // Releases the activity-tracker associcated with thread. It is called
1079 // automatically when a thread is joined and thus there is nothing more to 1122 // automatically when a thread is joined and thus there is nothing more to
1080 // be tracked. |value| is a pointer to a ManagedActivityTracker. 1123 // be tracked. |value| is a pointer to a ManagedActivityTracker.
1081 static void OnTLSDestroy(void* value); 1124 static void OnTLSDestroy(void* value);
1082 1125
1083 // Does process-exit work. This can be run on any thread. 1126 // Does process-exit work. This can be run on any thread.
1084 void CleanupAfterProcess(ProcessId process_id, 1127 void CleanupAfterProcess(ProcessId process_id,
1085 int64_t exit_stamp, 1128 int64_t exit_stamp,
1086 int exit_code, 1129 int exit_code,
1087 std::string&& command_line); 1130 std::string&& command_line);
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after
1261 ScopedProcessWaitActivity(const void* program_counter, 1304 ScopedProcessWaitActivity(const void* program_counter,
1262 const base::Process* process); 1305 const base::Process* process);
1263 DISALLOW_COPY_AND_ASSIGN(ScopedProcessWaitActivity); 1306 DISALLOW_COPY_AND_ASSIGN(ScopedProcessWaitActivity);
1264 }; 1307 };
1265 #endif 1308 #endif
1266 1309
1267 } // namespace debug 1310 } // namespace debug
1268 } // namespace base 1311 } // namespace base
1269 1312
1270 #endif // BASE_DEBUG_ACTIVITY_TRACKER_H_ 1313 #endif // BASE_DEBUG_ACTIVITY_TRACKER_H_
OLDNEW
« no previous file with comments | « no previous file | base/debug/activity_tracker.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698