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

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

Issue 2702413006: Enable storing last-dispatched exception per-thread. (Closed)
Patch Set: some cleanup Created 3 years, 10 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
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 #include "base/debug/activity_tracker.h" 5 #include "base/debug/activity_tracker.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <limits> 8 #include <limits>
9 #include <utility> 9 #include <utility>
10 10
11 #include "base/atomic_sequence_num.h" 11 #include "base/atomic_sequence_num.h"
12 #include "base/debug/stack_trace.h" 12 #include "base/debug/stack_trace.h"
13 #include "base/files/file.h" 13 #include "base/files/file.h"
14 #include "base/files/file_path.h" 14 #include "base/files/file_path.h"
15 #include "base/files/memory_mapped_file.h" 15 #include "base/files/memory_mapped_file.h"
16 #include "base/lazy_instance.h"
16 #include "base/logging.h" 17 #include "base/logging.h"
17 #include "base/memory/ptr_util.h" 18 #include "base/memory/ptr_util.h"
18 #include "base/metrics/field_trial.h" 19 #include "base/metrics/field_trial.h"
19 #include "base/metrics/histogram_macros.h" 20 #include "base/metrics/histogram_macros.h"
20 #include "base/pending_task.h" 21 #include "base/pending_task.h"
21 #include "base/pickle.h" 22 #include "base/pickle.h"
22 #include "base/process/process.h" 23 #include "base/process/process.h"
23 #include "base/process/process_handle.h" 24 #include "base/process/process_handle.h"
24 #include "base/stl_util.h" 25 #include "base/stl_util.h"
25 #include "base/strings/string_util.h" 26 #include "base/strings/string_util.h"
(...skipping 19 matching lines...) Expand all
45 // A constant used to indicate that module information is changing. 46 // A constant used to indicate that module information is changing.
46 const uint32_t kModuleInformationChanging = 0x80000000; 47 const uint32_t kModuleInformationChanging = 0x80000000;
47 48
48 // The key used to record process information. 49 // The key used to record process information.
49 const char kProcessPhaseDataKey[] = "process-phase"; 50 const char kProcessPhaseDataKey[] = "process-phase";
50 51
51 // An atomically incrementing number, used to check for recreations of objects 52 // An atomically incrementing number, used to check for recreations of objects
52 // in the same memory space. 53 // in the same memory space.
53 StaticAtomicSequenceNumber g_next_id; 54 StaticAtomicSequenceNumber g_next_id;
54 55
56 // An reusable user-data sink that just discards all data saved to it.
57 LazyInstance<ActivityUserData>::Leaky g_data_sink;
58
55 union ThreadRef { 59 union ThreadRef {
56 int64_t as_id; 60 int64_t as_id;
57 #if defined(OS_WIN) 61 #if defined(OS_WIN)
58 // On Windows, the handle itself is often a pseudo-handle with a common 62 // On Windows, the handle itself is often a pseudo-handle with a common
59 // value meaning "this thread" and so the thread-id is used. The former 63 // value meaning "this thread" and so the thread-id is used. The former
60 // can be converted to a thread-id with a system call. 64 // can be converted to a thread-id with a system call.
61 PlatformThreadId as_tid; 65 PlatformThreadId as_tid;
62 #elif defined(OS_POSIX) 66 #elif defined(OS_POSIX)
63 // On Posix, the handle is always a unique identifier so no conversion 67 // On Posix, the handle is always a unique identifier so no conversion
64 // needs to be done. However, it's value is officially opaque so there 68 // needs to be done. However, it's value is officially opaque so there
(...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after
309 // thus clang requires explicit out-of-line constructors and destructors even 313 // thus clang requires explicit out-of-line constructors and destructors even
310 // when they do nothing. 314 // when they do nothing.
311 ActivityUserData::ValueInfo::ValueInfo() {} 315 ActivityUserData::ValueInfo::ValueInfo() {}
312 ActivityUserData::ValueInfo::ValueInfo(ValueInfo&&) = default; 316 ActivityUserData::ValueInfo::ValueInfo(ValueInfo&&) = default;
313 ActivityUserData::ValueInfo::~ValueInfo() {} 317 ActivityUserData::ValueInfo::~ValueInfo() {}
314 ActivityUserData::MemoryHeader::MemoryHeader() {} 318 ActivityUserData::MemoryHeader::MemoryHeader() {}
315 ActivityUserData::MemoryHeader::~MemoryHeader() {} 319 ActivityUserData::MemoryHeader::~MemoryHeader() {}
316 ActivityUserData::FieldHeader::FieldHeader() {} 320 ActivityUserData::FieldHeader::FieldHeader() {}
317 ActivityUserData::FieldHeader::~FieldHeader() {} 321 ActivityUserData::FieldHeader::~FieldHeader() {}
318 322
323 ActivityUserData::ActivityUserData() : ActivityUserData(nullptr, 0) {}
324
319 ActivityUserData::ActivityUserData(void* memory, size_t size) 325 ActivityUserData::ActivityUserData(void* memory, size_t size)
320 : memory_(reinterpret_cast<char*>(memory)), 326 : memory_(reinterpret_cast<char*>(memory)),
321 available_(RoundDownToAlignment(size, kMemoryAlignment)), 327 available_(RoundDownToAlignment(size, kMemoryAlignment)),
322 header_(reinterpret_cast<MemoryHeader*>(memory)) { 328 header_(reinterpret_cast<MemoryHeader*>(memory)) {
323 // It's possible that no user data is being stored. 329 // It's possible that no user data is being stored.
324 if (!memory_) 330 if (!memory_)
325 return; 331 return;
326 332
327 static_assert(0 == sizeof(MemoryHeader) % kMemoryAlignment, "invalid header"); 333 static_assert(0 == sizeof(MemoryHeader) % kMemoryAlignment, "invalid header");
328 DCHECK_LT(sizeof(MemoryHeader), available_); 334 DCHECK_LT(sizeof(MemoryHeader), available_);
(...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after
550 // This information is kept for every thread that is tracked. It is filled 556 // This information is kept for every thread that is tracked. It is filled
551 // the very first time the thread is seen. All fields must be of exact sizes 557 // the very first time the thread is seen. All fields must be of exact sizes
552 // so there is no issue moving between 32 and 64-bit builds. 558 // so there is no issue moving between 32 and 64-bit builds.
553 struct ThreadActivityTracker::Header { 559 struct ThreadActivityTracker::Header {
554 // Defined in .h for analyzer access. Increment this if structure changes! 560 // Defined in .h for analyzer access. Increment this if structure changes!
555 static constexpr uint32_t kPersistentTypeId = 561 static constexpr uint32_t kPersistentTypeId =
556 GlobalActivityTracker::kTypeIdActivityTracker; 562 GlobalActivityTracker::kTypeIdActivityTracker;
557 563
558 // Expected size for 32/64-bit check. 564 // Expected size for 32/64-bit check.
559 static constexpr size_t kExpectedInstanceSize = 565 static constexpr size_t kExpectedInstanceSize =
560 OwningProcess::kExpectedInstanceSize + 72; 566 OwningProcess::kExpectedInstanceSize + Activity::kExpectedInstanceSize +
567 72;
561 568
562 // This information uniquely identifies a process. 569 // This information uniquely identifies a process.
563 OwningProcess owner; 570 OwningProcess owner;
564 571
565 // The thread-id (thread_ref.as_id) to which this data belongs. This number 572 // The thread-id (thread_ref.as_id) to which this data belongs. This number
566 // is not guaranteed to mean anything but combined with the process-id from 573 // is not guaranteed to mean anything but combined with the process-id from
567 // OwningProcess is unique among all active trackers. 574 // OwningProcess is unique among all active trackers.
568 ThreadRef thread_ref; 575 ThreadRef thread_ref;
569 576
570 // The start-time and start-ticks when the data was created. Each activity 577 // The start-time and start-ticks when the data was created. Each activity
571 // record has a |time_internal| value that can be converted to a "wall time" 578 // record has a |time_internal| value that can be converted to a "wall time"
572 // with these two values. 579 // with these two values.
573 int64_t start_time; 580 int64_t start_time;
574 int64_t start_ticks; 581 int64_t start_ticks;
575 582
576 // The number of Activity slots (spaces that can hold an Activity) that 583 // The number of Activity slots (spaces that can hold an Activity) that
577 // immediately follow this structure in memory. 584 // immediately follow this structure in memory.
578 uint32_t stack_slots; 585 uint32_t stack_slots;
579 586
580 // Some padding to keep everything 64-bit aligned. 587 // Some padding to keep everything 64-bit aligned.
581 uint32_t padding; 588 uint32_t padding;
582 589
583 // The current depth of the stack. This may be greater than the number of 590 // The current depth of the stack. This may be greater than the number of
584 // slots. If the depth exceeds the number of slots, the newest entries 591 // slots. If the depth exceeds the number of slots, the newest entries
585 // won't be recorded. 592 // won't be recorded.
586 std::atomic<uint32_t> current_depth; 593 std::atomic<uint32_t> current_depth;
587 594
588 // A memory location used to indicate if changes have been made to the stack 595 // A memory location used to indicate if changes have been made to the stack
manzagop (departed) 2017/02/24 19:06:14 update comment
bcwhite 2017/02/24 19:10:58 Done.
589 // that would invalidate an in-progress read of its contents. The active 596 // that would invalidate an in-progress read of its contents. The active
590 // tracker will zero the value whenever something gets popped from the 597 // tracker will zero the value whenever something gets popped from the
591 // stack. A monitoring tracker can write a non-zero value here, copy the 598 // stack. A monitoring tracker can write a non-zero value here, copy the
592 // stack contents, and read the value to know, if it is still non-zero, that 599 // stack contents, and read the value to know, if it is still non-zero, that
593 // the contents didn't change while being copied. This can handle concurrent 600 // the contents didn't change while being copied. This can handle concurrent
594 // snapshot operations only if each snapshot writes a different bit (which 601 // snapshot operations only if each snapshot writes a different bit (which
595 // is not the current implementation so no parallel snapshots allowed). 602 // is not the current implementation so no parallel snapshots allowed).
596 std::atomic<uint32_t> stack_unchanged; 603 std::atomic<uint32_t> data_unchanged;
604
605 // The last "exception" activity. This can't be stored on the stack because
606 // that could get popped as things unwind.
607 Activity last_exception;
597 608
598 // The name of the thread (up to a maximum length). Dynamic-length names 609 // The name of the thread (up to a maximum length). Dynamic-length names
599 // are not practical since the memory has to come from the same persistent 610 // are not practical since the memory has to come from the same persistent
600 // allocator that holds this structure and to which this object has no 611 // allocator that holds this structure and to which this object has no
601 // reference. 612 // reference.
602 char thread_name[32]; 613 char thread_name[32];
603 }; 614 };
604 615
605 ThreadActivityTracker::Snapshot::Snapshot() {} 616 ThreadActivityTracker::Snapshot::Snapshot() {}
606 ThreadActivityTracker::Snapshot::~Snapshot() {} 617 ThreadActivityTracker::Snapshot::~Snapshot() {}
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
664 // Provided memory should either be completely initialized or all zeros. 675 // Provided memory should either be completely initialized or all zeros.
665 if (header_->owner.data_id.load(std::memory_order_relaxed) == 0) { 676 if (header_->owner.data_id.load(std::memory_order_relaxed) == 0) {
666 // This is a new file. Double-check other fields and then initialize. 677 // This is a new file. Double-check other fields and then initialize.
667 DCHECK_EQ(0, header_->owner.process_id); 678 DCHECK_EQ(0, header_->owner.process_id);
668 DCHECK_EQ(0, header_->owner.create_stamp); 679 DCHECK_EQ(0, header_->owner.create_stamp);
669 DCHECK_EQ(0, header_->thread_ref.as_id); 680 DCHECK_EQ(0, header_->thread_ref.as_id);
670 DCHECK_EQ(0, header_->start_time); 681 DCHECK_EQ(0, header_->start_time);
671 DCHECK_EQ(0, header_->start_ticks); 682 DCHECK_EQ(0, header_->start_ticks);
672 DCHECK_EQ(0U, header_->stack_slots); 683 DCHECK_EQ(0U, header_->stack_slots);
673 DCHECK_EQ(0U, header_->current_depth.load(std::memory_order_relaxed)); 684 DCHECK_EQ(0U, header_->current_depth.load(std::memory_order_relaxed));
674 DCHECK_EQ(0U, header_->stack_unchanged.load(std::memory_order_relaxed)); 685 DCHECK_EQ(0U, header_->data_unchanged.load(std::memory_order_relaxed));
675 DCHECK_EQ(0, stack_[0].time_internal); 686 DCHECK_EQ(0, stack_[0].time_internal);
676 DCHECK_EQ(0U, stack_[0].origin_address); 687 DCHECK_EQ(0U, stack_[0].origin_address);
677 DCHECK_EQ(0U, stack_[0].call_stack[0]); 688 DCHECK_EQ(0U, stack_[0].call_stack[0]);
678 DCHECK_EQ(0U, stack_[0].data.task.sequence_id); 689 DCHECK_EQ(0U, stack_[0].data.task.sequence_id);
679 690
680 #if defined(OS_WIN) 691 #if defined(OS_WIN)
681 header_->thread_ref.as_tid = PlatformThread::CurrentId(); 692 header_->thread_ref.as_tid = PlatformThread::CurrentId();
682 #elif defined(OS_POSIX) 693 #elif defined(OS_POSIX)
683 header_->thread_ref.as_handle = 694 header_->thread_ref.as_handle =
684 PlatformThread::CurrentHandle().platform_handle(); 695 PlatformThread::CurrentHandle().platform_handle();
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
778 // Validate that everything is running correctly. 789 // Validate that everything is running correctly.
779 DCHECK_EQ(id, depth); 790 DCHECK_EQ(id, depth);
780 791
781 // A thread-checker creates a lock to check the thread-id which means 792 // A thread-checker creates a lock to check the thread-id which means
782 // re-entry into this code if lock acquisitions are being tracked. 793 // re-entry into this code if lock acquisitions are being tracked.
783 DCHECK(stack_[depth].activity_type == Activity::ACT_LOCK_ACQUIRE || 794 DCHECK(stack_[depth].activity_type == Activity::ACT_LOCK_ACQUIRE ||
784 thread_checker_.CalledOnValidThread()); 795 thread_checker_.CalledOnValidThread());
785 796
786 // The stack has shrunk meaning that some other thread trying to copy the 797 // The stack has shrunk meaning that some other thread trying to copy the
787 // contents for reporting purposes could get bad data. That thread would 798 // contents for reporting purposes could get bad data. That thread would
788 // have written a non-zero value into |stack_unchanged|; clearing it here 799 // have written a non-zero value into |data_unchanged|; clearing it here
789 // will let that thread detect that something did change. This needs to 800 // will let that thread detect that something did change. This needs to
790 // happen after the atomic |depth| operation above so a "release" store 801 // happen after the atomic |depth| operation above so a "release" store
791 // is required. 802 // is required.
792 header_->stack_unchanged.store(0, std::memory_order_release); 803 header_->data_unchanged.store(0, std::memory_order_release);
793 } 804 }
794 805
795 std::unique_ptr<ActivityUserData> ThreadActivityTracker::GetUserData( 806 std::unique_ptr<ActivityUserData> ThreadActivityTracker::GetUserData(
796 ActivityId id, 807 ActivityId id,
797 ActivityTrackerMemoryAllocator* allocator) { 808 ActivityTrackerMemoryAllocator* allocator) {
798 // User-data is only stored for activities actually held in the stack. 809 // Don't allow user data for lock acquisition as recursion may occur.
799 if (id < stack_slots_) { 810 if (stack_[id].activity_type == Activity::ACT_LOCK_ACQUIRE) {
800 // Don't allow user data for lock acquisition as recursion may occur. 811 NOTREACHED();
801 if (stack_[id].activity_type == Activity::ACT_LOCK_ACQUIRE) { 812 return MakeUnique<ActivityUserData>();
802 NOTREACHED();
803 return MakeUnique<ActivityUserData>(nullptr, 0);
804 }
805
806 // Get (or reuse) a block of memory and create a real UserData object
807 // on it.
808 PersistentMemoryAllocator::Reference ref = allocator->GetObjectReference();
809 void* memory =
810 allocator->GetAsArray<char>(ref, PersistentMemoryAllocator::kSizeAny);
811 if (memory) {
812 std::unique_ptr<ActivityUserData> user_data =
813 MakeUnique<ActivityUserData>(memory, kUserDataSize);
814 stack_[id].user_data_ref = ref;
815 stack_[id].user_data_id = user_data->id();
816 return user_data;
817 }
818 } 813 }
819 814
820 // Return a dummy object that will still accept (but ignore) Set() calls. 815 // User-data is only stored for activities actually held in the stack.
821 return MakeUnique<ActivityUserData>(nullptr, 0); 816 if (id >= stack_slots_)
817 return MakeUnique<ActivityUserData>();
818
819 // Create and return a real UserData object.
820 return CreateUserDataForActivity(&stack_[id], allocator);
822 } 821 }
823 822
824 bool ThreadActivityTracker::HasUserData(ActivityId id) { 823 bool ThreadActivityTracker::HasUserData(ActivityId id) {
825 // User-data is only stored for activities actually held in the stack. 824 // User-data is only stored for activities actually held in the stack.
826 return (id < stack_slots_ && stack_[id].user_data_ref); 825 return (id < stack_slots_ && stack_[id].user_data_ref);
827 } 826 }
828 827
829 void ThreadActivityTracker::ReleaseUserData( 828 void ThreadActivityTracker::ReleaseUserData(
830 ActivityId id, 829 ActivityId id,
831 ActivityTrackerMemoryAllocator* allocator) { 830 ActivityTrackerMemoryAllocator* allocator) {
832 // User-data is only stored for activities actually held in the stack. 831 // User-data is only stored for activities actually held in the stack.
833 if (id < stack_slots_ && stack_[id].user_data_ref) { 832 if (id < stack_slots_ && stack_[id].user_data_ref) {
834 allocator->ReleaseObjectReference(stack_[id].user_data_ref); 833 allocator->ReleaseObjectReference(stack_[id].user_data_ref);
835 stack_[id].user_data_ref = 0; 834 stack_[id].user_data_ref = 0;
836 } 835 }
836 // Release user-data for an exception.
837 if (header_->last_exception.user_data_ref) {
838 exception_data.reset();
839 allocator->ReleaseObjectReference(header_->last_exception.user_data_ref);
840 header_->last_exception.user_data_ref = 0;
841 }
842 }
843
844 ActivityUserData& ThreadActivityTracker::ExceptionActivity(
845 const void* program_counter,
846 const void* origin,
Sigurður Ásgeirsson 2017/02/24 18:37:41 is this the exception address? If so, maybe name i
bcwhite 2017/02/24 19:10:58 Yes, it's for holding the address where the except
847 Activity::Type type,
848 const ActivityData& data,
849 ActivityTrackerMemoryAllocator* allocator) {
Sigurður Ásgeirsson 2017/02/24 18:37:41 Note that here you will be executing in the contex
bcwhite 2017/02/24 19:10:58 There are two points that need hardening: 1) Crea
manzagop (departed) 2017/02/27 16:05:15 IIRC the locks are to enable memory reuse. Another
bcwhite 2017/03/14 12:53:25 Correct on all counts. Better to avoid the leaks
850 // A thread-checker creates a lock to check the thread-id which means
851 // re-entry into this code if lock acquisitions are being tracked.
852 DCHECK(thread_checker_.CalledOnValidThread());
853
854 // If there was a previous exception, release its user-data.
855 if (header_->last_exception.user_data_ref) {
856 allocator->ReleaseObjectReference(header_->last_exception.user_data_ref);
857 header_->last_exception.user_data_ref = 0;
858 }
859
860 // Fill the reusable exception activity.
861 Activity::FillFrom(&header_->last_exception, program_counter, origin, type,
862 data);
863
864 // Create a new user-data object for holding additional information.
865 exception_data =
866 CreateUserDataForActivity(&header_->last_exception, allocator);
867
868 // The data has changed meaning that some other thread trying to copy the
869 // contents for reporting purposes could get bad data.
870 header_->data_unchanged.store(0, std::memory_order_relaxed);
871
872 return *exception_data;
837 } 873 }
838 874
839 bool ThreadActivityTracker::IsValid() const { 875 bool ThreadActivityTracker::IsValid() const {
840 if (header_->owner.data_id.load(std::memory_order_acquire) == 0 || 876 if (header_->owner.data_id.load(std::memory_order_acquire) == 0 ||
841 header_->owner.process_id == 0 || header_->thread_ref.as_id == 0 || 877 header_->owner.process_id == 0 || header_->thread_ref.as_id == 0 ||
842 header_->start_time == 0 || header_->start_ticks == 0 || 878 header_->start_time == 0 || header_->start_ticks == 0 ||
843 header_->stack_slots != stack_slots_ || 879 header_->stack_slots != stack_slots_ ||
844 header_->thread_name[sizeof(header_->thread_name) - 1] != '\0') { 880 header_->thread_name[sizeof(header_->thread_name) - 1] != '\0') {
845 return false; 881 return false;
846 } 882 }
(...skipping 24 matching lines...) Expand all
871 907
872 for (int attempt = 0; attempt < kMaxAttempts; ++attempt) { 908 for (int attempt = 0; attempt < kMaxAttempts; ++attempt) {
873 // Remember the data IDs to ensure nothing is replaced during the snapshot 909 // Remember the data IDs to ensure nothing is replaced during the snapshot
874 // operation. Use "acquire" so that all the non-atomic fields of the 910 // operation. Use "acquire" so that all the non-atomic fields of the
875 // structure are valid (at least at the current moment in time). 911 // structure are valid (at least at the current moment in time).
876 const uint32_t starting_id = 912 const uint32_t starting_id =
877 header_->owner.data_id.load(std::memory_order_acquire); 913 header_->owner.data_id.load(std::memory_order_acquire);
878 const int64_t starting_process_id = header_->owner.process_id; 914 const int64_t starting_process_id = header_->owner.process_id;
879 const int64_t starting_thread_id = header_->thread_ref.as_id; 915 const int64_t starting_thread_id = header_->thread_ref.as_id;
880 916
881 // Write a non-zero value to |stack_unchanged| so it's possible to detect 917 // Write a non-zero value to |data_unchanged| so it's possible to detect
882 // at the end that nothing has changed since copying the data began. A 918 // at the end that nothing has changed since copying the data began. A
883 // "cst" operation is required to ensure it occurs before everything else. 919 // "cst" operation is required to ensure it occurs before everything else.
884 // Using "cst" memory ordering is relatively expensive but this is only 920 // Using "cst" memory ordering is relatively expensive but this is only
885 // done during analysis so doesn't directly affect the worker threads. 921 // done during analysis so doesn't directly affect the worker threads.
886 header_->stack_unchanged.store(1, std::memory_order_seq_cst); 922 header_->data_unchanged.store(1, std::memory_order_seq_cst);
887 923
888 // Fetching the current depth also "acquires" the contents of the stack. 924 // Fetching the current depth also "acquires" the contents of the stack.
889 depth = header_->current_depth.load(std::memory_order_acquire); 925 depth = header_->current_depth.load(std::memory_order_acquire);
890 uint32_t count = std::min(depth, stack_slots_); 926 uint32_t count = std::min(depth, stack_slots_);
891 output_snapshot->activity_stack.resize(count); 927 output_snapshot->activity_stack.resize(count);
892 if (count > 0) { 928 if (count > 0) {
893 // Copy the existing contents. Memcpy is used for speed. 929 // Copy the existing contents. Memcpy is used for speed.
894 memcpy(&output_snapshot->activity_stack[0], stack_, 930 memcpy(&output_snapshot->activity_stack[0], stack_,
895 count * sizeof(Activity)); 931 count * sizeof(Activity));
896 } 932 }
897 933
934 // Capture the last exception.
935 memcpy(&output_snapshot->last_exception, &header_->last_exception,
936 sizeof(Activity));
937
938 // TODO(bcwhite): Snapshot other things here.
939
898 // Retry if something changed during the copy. A "cst" operation ensures 940 // Retry if something changed during the copy. A "cst" operation ensures
899 // it must happen after all the above operations. 941 // it must happen after all the above operations.
900 if (!header_->stack_unchanged.load(std::memory_order_seq_cst)) 942 if (!header_->data_unchanged.load(std::memory_order_seq_cst))
901 continue; 943 continue;
902 944
903 // Stack copied. Record it's full depth. 945 // Stack copied. Record it's full depth.
904 output_snapshot->activity_stack_depth = depth; 946 output_snapshot->activity_stack_depth = depth;
905 947
906 // TODO(bcwhite): Snapshot other things here.
907
908 // Get the general thread information. 948 // Get the general thread information.
909 output_snapshot->thread_name = 949 output_snapshot->thread_name =
910 std::string(header_->thread_name, sizeof(header_->thread_name) - 1); 950 std::string(header_->thread_name, sizeof(header_->thread_name) - 1);
911 output_snapshot->thread_id = header_->thread_ref.as_id; 951 output_snapshot->thread_id = header_->thread_ref.as_id;
912 output_snapshot->process_id = header_->owner.process_id; 952 output_snapshot->process_id = header_->owner.process_id;
913 953
914 // All characters of the thread-name buffer were copied so as to not break 954 // All characters of the thread-name buffer were copied so as to not break
915 // if the trailing NUL were missing. Now limit the length if the actual 955 // if the trailing NUL were missing. Now limit the length if the actual
916 // name is shorter. 956 // name is shorter.
917 output_snapshot->thread_name.resize( 957 output_snapshot->thread_name.resize(
(...skipping 15 matching lines...) Expand all
933 973
934 // Change all the timestamps in the activities from "ticks" to "wall" time. 974 // Change all the timestamps in the activities from "ticks" to "wall" time.
935 const Time start_time = Time::FromInternalValue(header_->start_time); 975 const Time start_time = Time::FromInternalValue(header_->start_time);
936 const int64_t start_ticks = header_->start_ticks; 976 const int64_t start_ticks = header_->start_ticks;
937 for (Activity& activity : output_snapshot->activity_stack) { 977 for (Activity& activity : output_snapshot->activity_stack) {
938 activity.time_internal = 978 activity.time_internal =
939 (start_time + 979 (start_time +
940 TimeDelta::FromInternalValue(activity.time_internal - start_ticks)) 980 TimeDelta::FromInternalValue(activity.time_internal - start_ticks))
941 .ToInternalValue(); 981 .ToInternalValue();
942 } 982 }
983 output_snapshot->last_exception.time_internal =
984 (start_time +
985 TimeDelta::FromInternalValue(
986 output_snapshot->last_exception.time_internal - start_ticks))
987 .ToInternalValue();
943 988
944 // Success! 989 // Success!
945 return true; 990 return true;
946 } 991 }
947 992
948 // Too many attempts. 993 // Too many attempts.
949 return false; 994 return false;
950 } 995 }
951 996
952 const void* ThreadActivityTracker::GetBaseAddress() { 997 const void* ThreadActivityTracker::GetBaseAddress() {
(...skipping 11 matching lines...) Expand all
964 int64_t* out_stamp) { 1009 int64_t* out_stamp) {
965 const Header* header = reinterpret_cast<const Header*>(memory); 1010 const Header* header = reinterpret_cast<const Header*>(memory);
966 return OwningProcess::GetOwningProcessId(&header->owner, out_id, out_stamp); 1011 return OwningProcess::GetOwningProcessId(&header->owner, out_id, out_stamp);
967 } 1012 }
968 1013
969 // static 1014 // static
970 size_t ThreadActivityTracker::SizeForStackDepth(int stack_depth) { 1015 size_t ThreadActivityTracker::SizeForStackDepth(int stack_depth) {
971 return static_cast<size_t>(stack_depth) * sizeof(Activity) + sizeof(Header); 1016 return static_cast<size_t>(stack_depth) * sizeof(Activity) + sizeof(Header);
972 } 1017 }
973 1018
1019 std::unique_ptr<ActivityUserData>
1020 ThreadActivityTracker::CreateUserDataForActivity(
1021 Activity* activity,
1022 ActivityTrackerMemoryAllocator* allocator) {
1023 DCHECK_EQ(0U, activity->user_data_ref);
1024
1025 PersistentMemoryAllocator::Reference ref = allocator->GetObjectReference();
1026 void* memory = allocator->GetAsArray<char>(ref, kUserDataSize);
1027 if (memory) {
1028 std::unique_ptr<ActivityUserData> user_data =
1029 MakeUnique<ActivityUserData>(memory, kUserDataSize);
1030 activity->user_data_ref = ref;
1031 activity->user_data_id = user_data->id();
1032 return user_data;
1033 }
1034
1035 // Return a dummy object that will still accept (but ignore) Set() calls.
1036 return MakeUnique<ActivityUserData>();
1037 }
1038
974 // The instantiation of the GlobalActivityTracker object. 1039 // The instantiation of the GlobalActivityTracker object.
975 // The object held here will obviously not be destructed at process exit 1040 // The object held here will obviously not be destructed at process exit
976 // but that's best since PersistentMemoryAllocator objects (that underlie 1041 // but that's best since PersistentMemoryAllocator objects (that underlie
977 // GlobalActivityTracker objects) are explicitly forbidden from doing anything 1042 // GlobalActivityTracker objects) are explicitly forbidden from doing anything
978 // essential at exit anyway due to the fact that they depend on data managed 1043 // essential at exit anyway due to the fact that they depend on data managed
979 // elsewhere and which could be destructed first. An AtomicWord is used instead 1044 // elsewhere and which could be destructed first. An AtomicWord is used instead
980 // of std::atomic because the latter can create global ctors and dtors. 1045 // of std::atomic because the latter can create global ctors and dtors.
981 subtle::AtomicWord GlobalActivityTracker::g_tracker_ = 0; 1046 subtle::AtomicWord GlobalActivityTracker::g_tracker_ = 0;
982 1047
983 GlobalActivityTracker::ModuleInfo::ModuleInfo() {} 1048 GlobalActivityTracker::ModuleInfo::ModuleInfo() {}
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after
1117 } 1182 }
1118 1183
1119 ActivityUserData& GlobalActivityTracker::ScopedThreadActivity::user_data() { 1184 ActivityUserData& GlobalActivityTracker::ScopedThreadActivity::user_data() {
1120 if (!user_data_) { 1185 if (!user_data_) {
1121 if (tracker_) { 1186 if (tracker_) {
1122 GlobalActivityTracker* global = GlobalActivityTracker::Get(); 1187 GlobalActivityTracker* global = GlobalActivityTracker::Get();
1123 AutoLock lock(global->user_data_allocator_lock_); 1188 AutoLock lock(global->user_data_allocator_lock_);
1124 user_data_ = 1189 user_data_ =
1125 tracker_->GetUserData(activity_id_, &global->user_data_allocator_); 1190 tracker_->GetUserData(activity_id_, &global->user_data_allocator_);
1126 } else { 1191 } else {
1127 user_data_ = MakeUnique<ActivityUserData>(nullptr, 0); 1192 user_data_ = MakeUnique<ActivityUserData>();
1128 } 1193 }
1129 } 1194 }
1130 return *user_data_; 1195 return *user_data_;
1131 } 1196 }
1132 1197
1133 GlobalActivityTracker::ThreadSafeUserData::ThreadSafeUserData(void* memory, 1198 GlobalActivityTracker::ThreadSafeUserData::ThreadSafeUserData(void* memory,
1134 size_t size) 1199 size_t size)
1135 : ActivityUserData(memory, size) {} 1200 : ActivityUserData(memory, size) {}
1136 1201
1137 GlobalActivityTracker::ThreadSafeUserData::~ThreadSafeUserData() {} 1202 GlobalActivityTracker::ThreadSafeUserData::~ThreadSafeUserData() {}
(...skipping 411 matching lines...) Expand 10 before | Expand all | Expand 10 after
1549 1614
1550 // Remove the destructed tracker from the set of known ones. 1615 // Remove the destructed tracker from the set of known ones.
1551 DCHECK_LE(1, thread_tracker_count_.load(std::memory_order_relaxed)); 1616 DCHECK_LE(1, thread_tracker_count_.load(std::memory_order_relaxed));
1552 thread_tracker_count_.fetch_sub(1, std::memory_order_relaxed); 1617 thread_tracker_count_.fetch_sub(1, std::memory_order_relaxed);
1553 1618
1554 // Release this memory for re-use at a later time. 1619 // Release this memory for re-use at a later time.
1555 base::AutoLock autolock(thread_tracker_allocator_lock_); 1620 base::AutoLock autolock(thread_tracker_allocator_lock_);
1556 thread_tracker_allocator_.ReleaseObjectReference(mem_reference); 1621 thread_tracker_allocator_.ReleaseObjectReference(mem_reference);
1557 } 1622 }
1558 1623
1624 ActivityUserData& GlobalActivityTracker::RecordExceptionImpl(
1625 const void* pc,
1626 const void* origin) {
1627 ThreadActivityTracker* tracker = GetOrCreateTrackerForCurrentThread();
1628 if (!tracker)
1629 return g_data_sink.Get();
1630
1631 AutoLock lock(user_data_allocator_lock_);
1632 return tracker->ExceptionActivity(pc, origin, Activity::ACT_EXCEPTION,
1633 ActivityData::ForGeneric(0, 0),
1634 &user_data_allocator_);
1635 }
1636
1559 // static 1637 // static
1560 void GlobalActivityTracker::OnTLSDestroy(void* value) { 1638 void GlobalActivityTracker::OnTLSDestroy(void* value) {
1561 delete reinterpret_cast<ManagedActivityTracker*>(value); 1639 delete reinterpret_cast<ManagedActivityTracker*>(value);
1562 } 1640 }
1563 1641
1564 ScopedActivity::ScopedActivity(const void* program_counter, 1642 ScopedActivity::ScopedActivity(const void* program_counter,
1565 uint8_t action, 1643 uint8_t action,
1566 uint32_t id, 1644 uint32_t id,
1567 int32_t info) 1645 int32_t info)
1568 : GlobalActivityTracker::ScopedThreadActivity( 1646 : GlobalActivityTracker::ScopedThreadActivity(
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
1639 : GlobalActivityTracker::ScopedThreadActivity( 1717 : GlobalActivityTracker::ScopedThreadActivity(
1640 program_counter, 1718 program_counter,
1641 nullptr, 1719 nullptr,
1642 Activity::ACT_PROCESS_WAIT, 1720 Activity::ACT_PROCESS_WAIT,
1643 ActivityData::ForProcess(process->Pid()), 1721 ActivityData::ForProcess(process->Pid()),
1644 /*lock_allowed=*/true) {} 1722 /*lock_allowed=*/true) {}
1645 #endif 1723 #endif
1646 1724
1647 } // namespace debug 1725 } // namespace debug
1648 } // namespace base 1726 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698