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

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

Issue 2702413006: Enable storing last-dispatched exception per-thread. (Closed)
Patch Set: harden exception recording 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);
manzagop (departed) 2017/02/27 16:05:16 Mention memory points to zeroed out memory.
bcwhite 2017/03/14 12:53:26 Done.
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
403 // Resets everything back to nothing stored.
404 void Reset();
405
390 // Writes a |value| (as part of a key/value pair) that will be included with 406 // Writes a |value| (as part of a key/value pair) that will be included with
391 // the activity in any reports. The same |name| can be written multiple times 407 // the activity in any reports. The same |name| can be written multiple times
392 // with each successive call overwriting the previously stored |value|. For 408 // with each successive call overwriting the previously stored |value|. For
393 // raw and string values, the maximum size of successive writes is limited by 409 // raw and string values, the maximum size of successive writes is limited by
394 // the first call. The length of "name" is limited to 255 characters. 410 // the first call. The length of "name" is limited to 255 characters.
395 // 411 //
396 // This information is stored on a "best effort" basis. It may be dropped if 412 // This information is stored on a "best effort" basis. It may be dropped if
397 // the memory buffer is full or the associated activity is beyond the maximum 413 // the memory buffer is full or the associated activity is beyond the maximum
398 // recording depth. 414 // recording depth.
399 void Set(StringPiece name, const void* memory, size_t size) { 415 void Set(StringPiece name, const void* memory, size_t size) {
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
498 void* memory; // Where the "value" is held. 514 void* memory; // Where the "value" is held.
499 std::atomic<uint16_t>* size_ptr; // Address of the actual size of value. 515 std::atomic<uint16_t>* size_ptr; // Address of the actual size of value.
500 size_t extent; // The total storage of the value, 516 size_t extent; // The total storage of the value,
501 }; // typically rounded up for alignment. 517 }; // typically rounded up for alignment.
502 518
503 void SetReference(StringPiece name, 519 void SetReference(StringPiece name,
504 ValueType type, 520 ValueType type,
505 const void* memory, 521 const void* memory,
506 size_t size); 522 size_t size);
507 523
524 // Performs initialization on empty memory.
525 void Initialize();
526
508 // Loads any data already in the memory segment. This allows for accessing 527 // Loads any data already in the memory segment. This allows for accessing
509 // records created previously. 528 // records created previously.
510 void ImportExistingData() const; 529 void ImportExistingData() const;
511 530
512 // A map of all the values within the memory block, keyed by name for quick 531 // A map of all the values within the memory block, keyed by name for quick
513 // updates of the values. This is "mutable" because it changes on "const" 532 // updates of the values. This is "mutable" because it changes on "const"
514 // objects even when the actual data values can't change. 533 // objects even when the actual data values can't change.
515 mutable std::map<StringPiece, ValueInfo> values_; 534 mutable std::map<StringPiece, ValueInfo> values_;
516 535
517 // Information about the memory block in which new data can be stored. These 536 // Information about the memory block in which new data can be stored. These
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
564 int64_t process_id = 0; 583 int64_t process_id = 0;
565 int64_t thread_id = 0; 584 int64_t thread_id = 0;
566 585
567 // The current stack of activities that are underway for this thread. It 586 // 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. 587 // is limited in its maximum size with later entries being left off.
569 std::vector<Activity> activity_stack; 588 std::vector<Activity> activity_stack;
570 589
571 // The current total depth of the activity stack, including those later 590 // The current total depth of the activity stack, including those later
572 // entries not recorded in the |activity_stack| vector. 591 // entries not recorded in the |activity_stack| vector.
573 uint32_t activity_stack_depth = 0; 592 uint32_t activity_stack_depth = 0;
593
594 // The last recorded "exception" activity.
595 Activity last_exception;
574 }; 596 };
575 597
576 // This is the base class for having the compiler manage an activity on the 598 // 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| 599 // 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 600 // if it is not null, making it safe (and cheap) to create these objects
579 // even if activity tracking is not enabled. 601 // even if activity tracking is not enabled.
580 class BASE_EXPORT ScopedActivity { 602 class BASE_EXPORT ScopedActivity {
581 public: 603 public:
582 ScopedActivity(ThreadActivityTracker* tracker, 604 ScopedActivity(ThreadActivityTracker* tracker,
583 const void* program_counter, 605 const void* program_counter,
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
647 ActivityTrackerMemoryAllocator* allocator); 669 ActivityTrackerMemoryAllocator* allocator);
648 670
649 // Returns if there is true use-data associated with a given ActivityId since 671 // 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. 672 // it's possible than any returned object is just a sink.
651 bool HasUserData(ActivityId id); 673 bool HasUserData(ActivityId id);
652 674
653 // Release the user-data information for an activity. 675 // Release the user-data information for an activity.
654 void ReleaseUserData(ActivityId id, 676 void ReleaseUserData(ActivityId id,
655 ActivityTrackerMemoryAllocator* allocator); 677 ActivityTrackerMemoryAllocator* allocator);
656 678
679 // Save an exception and return space for additional information.
680 ActivityUserData& ExceptionActivity(const void* program_counter,
681 const void* origin,
682 Activity::Type type,
683 const ActivityData& data);
684
657 // Returns whether the current data is valid or not. It is not valid if 685 // 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. 686 // corruption has been detected in the header or other data structures.
659 bool IsValid() const; 687 bool IsValid() const;
660 688
661 // Gets a copy of the tracker contents for analysis. Returns false if a 689 // 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 690 // snapshot was not possible, perhaps because the data is not valid; the
663 // contents of |output_snapshot| are undefined in that case. The current 691 // contents of |output_snapshot| are undefined in that case. The current
664 // implementation does not support concurrent snapshot operations. 692 // implementation does not support concurrent snapshot operations.
665 bool CreateSnapshot(Snapshot* output_snapshot) const; 693 bool CreateSnapshot(Snapshot* output_snapshot) const;
666 694
(...skipping 10 matching lines...) Expand all
677 ProcessId* out_id, 705 ProcessId* out_id,
678 int64_t* out_stamp); 706 int64_t* out_stamp);
679 707
680 // Calculates the memory size required for a given stack depth, including 708 // Calculates the memory size required for a given stack depth, including
681 // the internal header structure for the stack. 709 // the internal header structure for the stack.
682 static size_t SizeForStackDepth(int stack_depth); 710 static size_t SizeForStackDepth(int stack_depth);
683 711
684 private: 712 private:
685 friend class ActivityTrackerTest; 713 friend class ActivityTrackerTest;
686 714
715 std::unique_ptr<ActivityUserData> CreateUserDataForActivity(
716 Activity* activity,
717 ActivityTrackerMemoryAllocator* allocator);
718
687 Header* const header_; // Pointer to the Header structure. 719 Header* const header_; // Pointer to the Header structure.
688 Activity* const stack_; // The stack of activities. 720 Activity* const stack_; // The stack of activities.
689 const uint32_t stack_slots_; // The total number of stack slots. 721 const uint32_t stack_slots_; // The total number of stack slots.
690 722
691 bool valid_ = false; // Tracks whether the data is valid or not. 723 bool valid_ = false; // Tracks whether the data is valid or not.
692 724
725 // A user-data object for information associated with the last exception.
726 std::unique_ptr<ActivityUserData> exception_data;
727
693 base::ThreadChecker thread_checker_; 728 base::ThreadChecker thread_checker_;
694 729
695 DISALLOW_COPY_AND_ASSIGN(ThreadActivityTracker); 730 DISALLOW_COPY_AND_ASSIGN(ThreadActivityTracker);
696 }; 731 };
697 732
698 733
699 // The global tracker manages all the individual thread trackers. Memory for 734 // The global tracker manages all the individual thread trackers. Memory for
700 // the thread trackers is taken from a PersistentMemoryAllocator which allows 735 // 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. 736 // for the data to be analyzed by a parallel process or even post-mortem.
702 class BASE_EXPORT GlobalActivityTracker { 737 class BASE_EXPORT GlobalActivityTracker {
(...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after
900 const FilePath::StringType& args) { 935 const FilePath::StringType& args) {
901 GlobalActivityTracker* tracker = Get(); 936 GlobalActivityTracker* tracker = Get();
902 if (tracker) 937 if (tracker)
903 tracker->RecordProcessLaunch(process_id, exe, args); 938 tracker->RecordProcessLaunch(process_id, exe, args);
904 } 939 }
905 static void RecordProcessExitIfEnabled(ProcessId process_id, int exit_code) { 940 static void RecordProcessExitIfEnabled(ProcessId process_id, int exit_code) {
906 GlobalActivityTracker* tracker = Get(); 941 GlobalActivityTracker* tracker = Get();
907 if (tracker) 942 if (tracker)
908 tracker->RecordProcessExit(process_id, exit_code); 943 tracker->RecordProcessExit(process_id, exit_code);
909 } 944 }
945
910 // Sets the "phase" of the current process, useful for knowing what it was 946 // Sets the "phase" of the current process, useful for knowing what it was
911 // doing when it last reported. 947 // doing when it last reported.
912 void SetProcessPhase(ProcessPhase phase); 948 void SetProcessPhase(ProcessPhase phase);
913 static void SetProcessPhaseIfEnabled(ProcessPhase phase) { 949 static void SetProcessPhaseIfEnabled(ProcessPhase phase) {
914 GlobalActivityTracker* tracker = Get(); 950 GlobalActivityTracker* tracker = Get();
915 if (tracker) 951 if (tracker)
916 tracker->SetProcessPhase(phase); 952 tracker->SetProcessPhase(phase);
917 } 953 }
918 954
919 // Records a log message. The current implementation does NOT recycle these 955 // Records a log message. The current implementation does NOT recycle these
920 // only store critical messages such as FATAL ones. 956 // only store critical messages such as FATAL ones.
921 void RecordLogMessage(StringPiece message); 957 void RecordLogMessage(StringPiece message);
922 958
923 // Records a module load/unload event. This is safe to call multiple times 959 // Records a module load/unload event. This is safe to call multiple times
924 // even with the same information. 960 // even with the same information.
925 void RecordModuleInfo(const ModuleInfo& info); 961 void RecordModuleInfo(const ModuleInfo& info);
926 962
927 // Record field trial information. This call is thread-safe. In addition to 963 // Record field trial information. This call is thread-safe. In addition to
928 // this, construction of a GlobalActivityTracker will cause all existing 964 // this, construction of a GlobalActivityTracker will cause all existing
929 // active field trials to be fetched and recorded. 965 // active field trials to be fetched and recorded.
930 void RecordFieldTrial(const std::string& trial_name, StringPiece group_name); 966 void RecordFieldTrial(const std::string& trial_name, StringPiece group_name);
931 967
968 // Record exception information for the current thread and return space where
969 // additional information may be recorded.
970 // TODO(bcwhite): More parameters (space for 4 + 64 bits).
971 ALWAYS_INLINE
972 ActivityUserData& RecordException(const void* origin) {
973 return RecordExceptionImpl(::tracked_objects::GetProgramCounter(), origin);
974 }
975
932 // Accesses the process data record for storing arbitrary key/value pairs. 976 // Accesses the process data record for storing arbitrary key/value pairs.
933 // Updates to this are thread-safe. 977 // Updates to this are thread-safe.
934 ActivityUserData& process_data() { return process_data_; } 978 ActivityUserData& process_data() { return process_data_; }
935 979
936 // Accesses the global data record for storing arbitrary key/value pairs. 980 // Accesses the global data record for storing arbitrary key/value pairs.
937 // Updates to this are thread-safe. 981 // Updates to this are thread-safe.
938 ActivityUserData& global_data() { return global_data_; } 982 ActivityUserData& global_data() { return global_data_; }
939 983
940 private: 984 private:
941 friend class GlobalActivityAnalyzer; 985 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 1083 // Creates a global tracker using a given persistent-memory |allocator| and
1040 // providing the given |stack_depth| to each thread tracker it manages. The 1084 // providing the given |stack_depth| to each thread tracker it manages. The
1041 // created object is activated so tracking has already started upon return. 1085 // created object is activated so tracking has already started upon return.
1042 GlobalActivityTracker(std::unique_ptr<PersistentMemoryAllocator> allocator, 1086 GlobalActivityTracker(std::unique_ptr<PersistentMemoryAllocator> allocator,
1043 int stack_depth); 1087 int stack_depth);
1044 1088
1045 // Returns the memory used by an activity-tracker managed by this class. 1089 // Returns the memory used by an activity-tracker managed by this class.
1046 // It is called during the destruction of a ManagedActivityTracker object. 1090 // It is called during the destruction of a ManagedActivityTracker object.
1047 void ReturnTrackerMemory(ManagedActivityTracker* tracker); 1091 void ReturnTrackerMemory(ManagedActivityTracker* tracker);
1048 1092
1093 // Records exception information.
1094 ActivityUserData& RecordExceptionImpl(const void* pc, const void* origin);
1095
1096 // Reserves an ActivityUserData object for storing exception information.
1097 void ReserveExceptionData();
1098
1049 // Releases the activity-tracker associcated with thread. It is called 1099 // Releases the activity-tracker associcated with thread. It is called
1050 // automatically when a thread is joined and thus there is nothing more to 1100 // automatically when a thread is joined and thus there is nothing more to
1051 // be tracked. |value| is a pointer to a ManagedActivityTracker. 1101 // be tracked. |value| is a pointer to a ManagedActivityTracker.
1052 static void OnTLSDestroy(void* value); 1102 static void OnTLSDestroy(void* value);
1053 1103
1054 // Does process-exit work. This can be run on any thread. 1104 // Does process-exit work. This can be run on any thread.
1055 void CleanupAfterProcess(ProcessId process_id, 1105 void CleanupAfterProcess(ProcessId process_id,
1056 int64_t exit_stamp, 1106 int64_t exit_stamp,
1057 int exit_code, 1107 int exit_code,
1058 std::string&& command_line); 1108 std::string&& command_line);
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after
1232 ScopedProcessWaitActivity(const void* program_counter, 1282 ScopedProcessWaitActivity(const void* program_counter,
1233 const base::Process* process); 1283 const base::Process* process);
1234 DISALLOW_COPY_AND_ASSIGN(ScopedProcessWaitActivity); 1284 DISALLOW_COPY_AND_ASSIGN(ScopedProcessWaitActivity);
1235 }; 1285 };
1236 #endif 1286 #endif
1237 1287
1238 } // namespace debug 1288 } // namespace debug
1239 } // namespace base 1289 } // namespace base
1240 1290
1241 #endif // BASE_DEBUG_ACTIVITY_TRACKER_H_ 1291 #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