OLD | NEW |
---|---|
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 |
(...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
310 // thus clang requires explicit out-of-line constructors and destructors even | 310 // thus clang requires explicit out-of-line constructors and destructors even |
311 // when they do nothing. | 311 // when they do nothing. |
312 ActivityUserData::ValueInfo::ValueInfo() {} | 312 ActivityUserData::ValueInfo::ValueInfo() {} |
313 ActivityUserData::ValueInfo::ValueInfo(ValueInfo&&) = default; | 313 ActivityUserData::ValueInfo::ValueInfo(ValueInfo&&) = default; |
314 ActivityUserData::ValueInfo::~ValueInfo() {} | 314 ActivityUserData::ValueInfo::~ValueInfo() {} |
315 ActivityUserData::MemoryHeader::MemoryHeader() {} | 315 ActivityUserData::MemoryHeader::MemoryHeader() {} |
316 ActivityUserData::MemoryHeader::~MemoryHeader() {} | 316 ActivityUserData::MemoryHeader::~MemoryHeader() {} |
317 ActivityUserData::FieldHeader::FieldHeader() {} | 317 ActivityUserData::FieldHeader::FieldHeader() {} |
318 ActivityUserData::FieldHeader::~FieldHeader() {} | 318 ActivityUserData::FieldHeader::~FieldHeader() {} |
319 | 319 |
320 ActivityUserData::ActivityUserData() : ActivityUserData(nullptr, 0) {} | |
321 | |
320 ActivityUserData::ActivityUserData(void* memory, size_t size) | 322 ActivityUserData::ActivityUserData(void* memory, size_t size) |
321 : memory_(reinterpret_cast<char*>(memory)), | 323 : memory_(reinterpret_cast<char*>(memory)), |
322 available_(RoundDownToAlignment(size, kMemoryAlignment)), | 324 available_(RoundDownToAlignment(size, kMemoryAlignment)), |
323 header_(reinterpret_cast<MemoryHeader*>(memory)) { | 325 header_(reinterpret_cast<MemoryHeader*>(memory)) { |
324 // It's possible that no user data is being stored. | 326 // It's possible that no user data is being stored. |
325 if (!memory_) | 327 if (!memory_) |
326 return; | 328 return; |
327 | 329 |
328 static_assert(0 == sizeof(MemoryHeader) % kMemoryAlignment, "invalid header"); | 330 static_assert(0 == sizeof(MemoryHeader) % kMemoryAlignment, "invalid header"); |
329 DCHECK_LT(sizeof(MemoryHeader), available_); | 331 DCHECK_LT(sizeof(MemoryHeader), available_); |
(...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
553 // This information is kept for every thread that is tracked. It is filled | 555 // This information is kept for every thread that is tracked. It is filled |
554 // the very first time the thread is seen. All fields must be of exact sizes | 556 // the very first time the thread is seen. All fields must be of exact sizes |
555 // so there is no issue moving between 32 and 64-bit builds. | 557 // so there is no issue moving between 32 and 64-bit builds. |
556 struct ThreadActivityTracker::Header { | 558 struct ThreadActivityTracker::Header { |
557 // Defined in .h for analyzer access. Increment this if structure changes! | 559 // Defined in .h for analyzer access. Increment this if structure changes! |
558 static constexpr uint32_t kPersistentTypeId = | 560 static constexpr uint32_t kPersistentTypeId = |
559 GlobalActivityTracker::kTypeIdActivityTracker; | 561 GlobalActivityTracker::kTypeIdActivityTracker; |
560 | 562 |
561 // Expected size for 32/64-bit check. | 563 // Expected size for 32/64-bit check. |
562 static constexpr size_t kExpectedInstanceSize = | 564 static constexpr size_t kExpectedInstanceSize = |
563 OwningProcess::kExpectedInstanceSize + 72; | 565 OwningProcess::kExpectedInstanceSize + Activity::kExpectedInstanceSize + |
566 72; | |
564 | 567 |
565 // This information uniquely identifies a process. | 568 // This information uniquely identifies a process. |
566 OwningProcess owner; | 569 OwningProcess owner; |
567 | 570 |
568 // The thread-id (thread_ref.as_id) to which this data belongs. This number | 571 // The thread-id (thread_ref.as_id) to which this data belongs. This number |
569 // is not guaranteed to mean anything but combined with the process-id from | 572 // is not guaranteed to mean anything but combined with the process-id from |
570 // OwningProcess is unique among all active trackers. | 573 // OwningProcess is unique among all active trackers. |
571 ThreadRef thread_ref; | 574 ThreadRef thread_ref; |
572 | 575 |
573 // The start-time and start-ticks when the data was created. Each activity | 576 // The start-time and start-ticks when the data was created. Each activity |
574 // record has a |time_internal| value that can be converted to a "wall time" | 577 // record has a |time_internal| value that can be converted to a "wall time" |
575 // with these two values. | 578 // with these two values. |
576 int64_t start_time; | 579 int64_t start_time; |
577 int64_t start_ticks; | 580 int64_t start_ticks; |
578 | 581 |
579 // The number of Activity slots (spaces that can hold an Activity) that | 582 // The number of Activity slots (spaces that can hold an Activity) that |
580 // immediately follow this structure in memory. | 583 // immediately follow this structure in memory. |
581 uint32_t stack_slots; | 584 uint32_t stack_slots; |
582 | 585 |
583 // Some padding to keep everything 64-bit aligned. | 586 // Some padding to keep everything 64-bit aligned. |
584 uint32_t padding; | 587 uint32_t padding; |
585 | 588 |
586 // The current depth of the stack. This may be greater than the number of | 589 // The current depth of the stack. This may be greater than the number of |
587 // slots. If the depth exceeds the number of slots, the newest entries | 590 // slots. If the depth exceeds the number of slots, the newest entries |
588 // won't be recorded. | 591 // won't be recorded. |
589 std::atomic<uint32_t> current_depth; | 592 std::atomic<uint32_t> current_depth; |
590 | 593 |
591 // A memory location used to indicate if changes have been made to the stack | 594 // A memory location used to indicate if changes have been made to the data |
592 // that would invalidate an in-progress read of its contents. The active | 595 // that would invalidate an in-progress read of its contents. The active |
593 // tracker will zero the value whenever something gets popped from the | 596 // tracker will zero the value whenever something gets popped from the |
594 // stack. A monitoring tracker can write a non-zero value here, copy the | 597 // stack. A monitoring tracker can write a non-zero value here, copy the |
595 // stack contents, and read the value to know, if it is still non-zero, that | 598 // stack contents, and read the value to know, if it is still non-zero, that |
596 // the contents didn't change while being copied. This can handle concurrent | 599 // the contents didn't change while being copied. This can handle concurrent |
597 // snapshot operations only if each snapshot writes a different bit (which | 600 // snapshot operations only if each snapshot writes a different bit (which |
598 // is not the current implementation so no parallel snapshots allowed). | 601 // is not the current implementation so no parallel snapshots allowed). |
599 std::atomic<uint32_t> stack_unchanged; | 602 std::atomic<uint32_t> data_unchanged; |
603 | |
604 // The last "exception" activity. This can't be stored on the stack because | |
605 // that could get popped as things unwind. | |
606 Activity last_exception; | |
600 | 607 |
601 // The name of the thread (up to a maximum length). Dynamic-length names | 608 // The name of the thread (up to a maximum length). Dynamic-length names |
602 // are not practical since the memory has to come from the same persistent | 609 // are not practical since the memory has to come from the same persistent |
603 // allocator that holds this structure and to which this object has no | 610 // allocator that holds this structure and to which this object has no |
604 // reference. | 611 // reference. |
605 char thread_name[32]; | 612 char thread_name[32]; |
606 }; | 613 }; |
607 | 614 |
608 ThreadActivityTracker::Snapshot::Snapshot() {} | 615 ThreadActivityTracker::Snapshot::Snapshot() {} |
609 ThreadActivityTracker::Snapshot::~Snapshot() {} | 616 ThreadActivityTracker::Snapshot::~Snapshot() {} |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
667 // Provided memory should either be completely initialized or all zeros. | 674 // Provided memory should either be completely initialized or all zeros. |
668 if (header_->owner.data_id.load(std::memory_order_relaxed) == 0) { | 675 if (header_->owner.data_id.load(std::memory_order_relaxed) == 0) { |
669 // This is a new file. Double-check other fields and then initialize. | 676 // This is a new file. Double-check other fields and then initialize. |
670 DCHECK_EQ(0, header_->owner.process_id); | 677 DCHECK_EQ(0, header_->owner.process_id); |
671 DCHECK_EQ(0, header_->owner.create_stamp); | 678 DCHECK_EQ(0, header_->owner.create_stamp); |
672 DCHECK_EQ(0, header_->thread_ref.as_id); | 679 DCHECK_EQ(0, header_->thread_ref.as_id); |
673 DCHECK_EQ(0, header_->start_time); | 680 DCHECK_EQ(0, header_->start_time); |
674 DCHECK_EQ(0, header_->start_ticks); | 681 DCHECK_EQ(0, header_->start_ticks); |
675 DCHECK_EQ(0U, header_->stack_slots); | 682 DCHECK_EQ(0U, header_->stack_slots); |
676 DCHECK_EQ(0U, header_->current_depth.load(std::memory_order_relaxed)); | 683 DCHECK_EQ(0U, header_->current_depth.load(std::memory_order_relaxed)); |
677 DCHECK_EQ(0U, header_->stack_unchanged.load(std::memory_order_relaxed)); | 684 DCHECK_EQ(0U, header_->data_unchanged.load(std::memory_order_relaxed)); |
678 DCHECK_EQ(0, stack_[0].time_internal); | 685 DCHECK_EQ(0, stack_[0].time_internal); |
679 DCHECK_EQ(0U, stack_[0].origin_address); | 686 DCHECK_EQ(0U, stack_[0].origin_address); |
680 DCHECK_EQ(0U, stack_[0].call_stack[0]); | 687 DCHECK_EQ(0U, stack_[0].call_stack[0]); |
681 DCHECK_EQ(0U, stack_[0].data.task.sequence_id); | 688 DCHECK_EQ(0U, stack_[0].data.task.sequence_id); |
682 | 689 |
683 #if defined(OS_WIN) | 690 #if defined(OS_WIN) |
684 header_->thread_ref.as_tid = PlatformThread::CurrentId(); | 691 header_->thread_ref.as_tid = PlatformThread::CurrentId(); |
685 #elif defined(OS_POSIX) | 692 #elif defined(OS_POSIX) |
686 header_->thread_ref.as_handle = | 693 header_->thread_ref.as_handle = |
687 PlatformThread::CurrentHandle().platform_handle(); | 694 PlatformThread::CurrentHandle().platform_handle(); |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
781 // Validate that everything is running correctly. | 788 // Validate that everything is running correctly. |
782 DCHECK_EQ(id, depth); | 789 DCHECK_EQ(id, depth); |
783 | 790 |
784 // A thread-checker creates a lock to check the thread-id which means | 791 // A thread-checker creates a lock to check the thread-id which means |
785 // re-entry into this code if lock acquisitions are being tracked. | 792 // re-entry into this code if lock acquisitions are being tracked. |
786 DCHECK(stack_[depth].activity_type == Activity::ACT_LOCK_ACQUIRE || | 793 DCHECK(stack_[depth].activity_type == Activity::ACT_LOCK_ACQUIRE || |
787 thread_checker_.CalledOnValidThread()); | 794 thread_checker_.CalledOnValidThread()); |
788 | 795 |
789 // The stack has shrunk meaning that some other thread trying to copy the | 796 // The stack has shrunk meaning that some other thread trying to copy the |
790 // contents for reporting purposes could get bad data. That thread would | 797 // contents for reporting purposes could get bad data. That thread would |
791 // have written a non-zero value into |stack_unchanged|; clearing it here | 798 // have written a non-zero value into |data_unchanged|; clearing it here |
792 // will let that thread detect that something did change. This needs to | 799 // will let that thread detect that something did change. This needs to |
793 // happen after the atomic |depth| operation above so a "release" store | 800 // happen after the atomic |depth| operation above so a "release" store |
794 // is required. | 801 // is required. |
795 header_->stack_unchanged.store(0, std::memory_order_release); | 802 header_->data_unchanged.store(0, std::memory_order_release); |
796 } | 803 } |
797 | 804 |
798 std::unique_ptr<ActivityUserData> ThreadActivityTracker::GetUserData( | 805 std::unique_ptr<ActivityUserData> ThreadActivityTracker::GetUserData( |
799 ActivityId id, | 806 ActivityId id, |
800 ActivityTrackerMemoryAllocator* allocator) { | 807 ActivityTrackerMemoryAllocator* allocator) { |
801 // User-data is only stored for activities actually held in the stack. | 808 // Don't allow user data for lock acquisition as recursion may occur. |
802 if (id < stack_slots_) { | 809 if (stack_[id].activity_type == Activity::ACT_LOCK_ACQUIRE) { |
803 // Don't allow user data for lock acquisition as recursion may occur. | 810 NOTREACHED(); |
804 if (stack_[id].activity_type == Activity::ACT_LOCK_ACQUIRE) { | 811 return MakeUnique<ActivityUserData>(); |
805 NOTREACHED(); | |
806 return MakeUnique<ActivityUserData>(nullptr, 0); | |
807 } | |
808 | |
809 // Get (or reuse) a block of memory and create a real UserData object | |
810 // on it. | |
811 PersistentMemoryAllocator::Reference ref = allocator->GetObjectReference(); | |
812 void* memory = | |
813 allocator->GetAsArray<char>(ref, PersistentMemoryAllocator::kSizeAny); | |
814 if (memory) { | |
815 std::unique_ptr<ActivityUserData> user_data = | |
816 MakeUnique<ActivityUserData>(memory, kUserDataSize); | |
817 stack_[id].user_data_ref = ref; | |
818 stack_[id].user_data_id = user_data->id(); | |
819 return user_data; | |
820 } | |
821 } | 812 } |
822 | 813 |
823 // Return a dummy object that will still accept (but ignore) Set() calls. | 814 // User-data is only stored for activities actually held in the stack. |
824 return MakeUnique<ActivityUserData>(nullptr, 0); | 815 if (id >= stack_slots_) |
816 return MakeUnique<ActivityUserData>(); | |
817 | |
818 // Create and return a real UserData object. | |
819 return CreateUserDataForActivity(&stack_[id], allocator); | |
825 } | 820 } |
826 | 821 |
827 bool ThreadActivityTracker::HasUserData(ActivityId id) { | 822 bool ThreadActivityTracker::HasUserData(ActivityId id) { |
828 // User-data is only stored for activities actually held in the stack. | 823 // User-data is only stored for activities actually held in the stack. |
829 return (id < stack_slots_ && stack_[id].user_data_ref); | 824 return (id < stack_slots_ && stack_[id].user_data_ref); |
830 } | 825 } |
831 | 826 |
832 void ThreadActivityTracker::ReleaseUserData( | 827 void ThreadActivityTracker::ReleaseUserData( |
833 ActivityId id, | 828 ActivityId id, |
834 ActivityTrackerMemoryAllocator* allocator) { | 829 ActivityTrackerMemoryAllocator* allocator) { |
835 // User-data is only stored for activities actually held in the stack. | 830 // User-data is only stored for activities actually held in the stack. |
836 if (id < stack_slots_ && stack_[id].user_data_ref) { | 831 if (id < stack_slots_ && stack_[id].user_data_ref) { |
837 allocator->ReleaseObjectReference(stack_[id].user_data_ref); | 832 allocator->ReleaseObjectReference(stack_[id].user_data_ref); |
838 stack_[id].user_data_ref = 0; | 833 stack_[id].user_data_ref = 0; |
839 } | 834 } |
840 } | 835 } |
841 | 836 |
837 void ThreadActivityTracker::ExceptionActivity(const void* program_counter, | |
838 const void* origin, | |
839 Activity::Type type, | |
840 const ActivityData& data) { | |
841 // A thread-checker creates a lock to check the thread-id which means | |
842 // re-entry into this code if lock acquisitions are being tracked. | |
843 DCHECK(thread_checker_.CalledOnValidThread()); | |
844 | |
845 // Fill the reusable exception activity. | |
846 Activity::FillFrom(&header_->last_exception, program_counter, origin, type, | |
847 data); | |
848 | |
849 // The data has changed meaning that some other thread trying to copy the | |
850 // contents for reporting purposes could get bad data. | |
851 header_->data_unchanged.store(0, std::memory_order_relaxed); | |
852 } | |
853 | |
842 bool ThreadActivityTracker::IsValid() const { | 854 bool ThreadActivityTracker::IsValid() const { |
843 if (header_->owner.data_id.load(std::memory_order_acquire) == 0 || | 855 if (header_->owner.data_id.load(std::memory_order_acquire) == 0 || |
844 header_->owner.process_id == 0 || header_->thread_ref.as_id == 0 || | 856 header_->owner.process_id == 0 || header_->thread_ref.as_id == 0 || |
845 header_->start_time == 0 || header_->start_ticks == 0 || | 857 header_->start_time == 0 || header_->start_ticks == 0 || |
846 header_->stack_slots != stack_slots_ || | 858 header_->stack_slots != stack_slots_ || |
847 header_->thread_name[sizeof(header_->thread_name) - 1] != '\0') { | 859 header_->thread_name[sizeof(header_->thread_name) - 1] != '\0') { |
848 return false; | 860 return false; |
849 } | 861 } |
850 | 862 |
851 return valid_; | 863 return valid_; |
(...skipping 22 matching lines...) Expand all Loading... | |
874 | 886 |
875 for (int attempt = 0; attempt < kMaxAttempts; ++attempt) { | 887 for (int attempt = 0; attempt < kMaxAttempts; ++attempt) { |
876 // Remember the data IDs to ensure nothing is replaced during the snapshot | 888 // Remember the data IDs to ensure nothing is replaced during the snapshot |
877 // operation. Use "acquire" so that all the non-atomic fields of the | 889 // operation. Use "acquire" so that all the non-atomic fields of the |
878 // structure are valid (at least at the current moment in time). | 890 // structure are valid (at least at the current moment in time). |
879 const uint32_t starting_id = | 891 const uint32_t starting_id = |
880 header_->owner.data_id.load(std::memory_order_acquire); | 892 header_->owner.data_id.load(std::memory_order_acquire); |
881 const int64_t starting_process_id = header_->owner.process_id; | 893 const int64_t starting_process_id = header_->owner.process_id; |
882 const int64_t starting_thread_id = header_->thread_ref.as_id; | 894 const int64_t starting_thread_id = header_->thread_ref.as_id; |
883 | 895 |
884 // Write a non-zero value to |stack_unchanged| so it's possible to detect | 896 // Write a non-zero value to |data_unchanged| so it's possible to detect |
885 // at the end that nothing has changed since copying the data began. A | 897 // at the end that nothing has changed since copying the data began. A |
886 // "cst" operation is required to ensure it occurs before everything else. | 898 // "cst" operation is required to ensure it occurs before everything else. |
887 // Using "cst" memory ordering is relatively expensive but this is only | 899 // Using "cst" memory ordering is relatively expensive but this is only |
888 // done during analysis so doesn't directly affect the worker threads. | 900 // done during analysis so doesn't directly affect the worker threads. |
889 header_->stack_unchanged.store(1, std::memory_order_seq_cst); | 901 header_->data_unchanged.store(1, std::memory_order_seq_cst); |
890 | 902 |
891 // Fetching the current depth also "acquires" the contents of the stack. | 903 // Fetching the current depth also "acquires" the contents of the stack. |
892 depth = header_->current_depth.load(std::memory_order_acquire); | 904 depth = header_->current_depth.load(std::memory_order_acquire); |
893 uint32_t count = std::min(depth, stack_slots_); | 905 uint32_t count = std::min(depth, stack_slots_); |
894 output_snapshot->activity_stack.resize(count); | 906 output_snapshot->activity_stack.resize(count); |
895 if (count > 0) { | 907 if (count > 0) { |
896 // Copy the existing contents. Memcpy is used for speed. | 908 // Copy the existing contents. Memcpy is used for speed. |
897 memcpy(&output_snapshot->activity_stack[0], stack_, | 909 memcpy(&output_snapshot->activity_stack[0], stack_, |
898 count * sizeof(Activity)); | 910 count * sizeof(Activity)); |
899 } | 911 } |
900 | 912 |
913 // Capture the last exception. | |
914 memcpy(&output_snapshot->last_exception, &header_->last_exception, | |
915 sizeof(Activity)); | |
916 | |
917 // TODO(bcwhite): Snapshot other things here. | |
918 | |
901 // Retry if something changed during the copy. A "cst" operation ensures | 919 // Retry if something changed during the copy. A "cst" operation ensures |
902 // it must happen after all the above operations. | 920 // it must happen after all the above operations. |
903 if (!header_->stack_unchanged.load(std::memory_order_seq_cst)) | 921 if (!header_->data_unchanged.load(std::memory_order_seq_cst)) |
904 continue; | 922 continue; |
905 | 923 |
906 // Stack copied. Record it's full depth. | 924 // Stack copied. Record it's full depth. |
907 output_snapshot->activity_stack_depth = depth; | 925 output_snapshot->activity_stack_depth = depth; |
908 | 926 |
909 // TODO(bcwhite): Snapshot other things here. | |
910 | |
911 // Get the general thread information. | 927 // Get the general thread information. |
912 output_snapshot->thread_name = | 928 output_snapshot->thread_name = |
913 std::string(header_->thread_name, sizeof(header_->thread_name) - 1); | 929 std::string(header_->thread_name, sizeof(header_->thread_name) - 1); |
914 output_snapshot->thread_id = header_->thread_ref.as_id; | 930 output_snapshot->thread_id = header_->thread_ref.as_id; |
915 output_snapshot->process_id = header_->owner.process_id; | 931 output_snapshot->process_id = header_->owner.process_id; |
916 | 932 |
917 // All characters of the thread-name buffer were copied so as to not break | 933 // All characters of the thread-name buffer were copied so as to not break |
918 // if the trailing NUL were missing. Now limit the length if the actual | 934 // if the trailing NUL were missing. Now limit the length if the actual |
919 // name is shorter. | 935 // name is shorter. |
920 output_snapshot->thread_name.resize( | 936 output_snapshot->thread_name.resize( |
(...skipping 15 matching lines...) Expand all Loading... | |
936 | 952 |
937 // Change all the timestamps in the activities from "ticks" to "wall" time. | 953 // Change all the timestamps in the activities from "ticks" to "wall" time. |
938 const Time start_time = Time::FromInternalValue(header_->start_time); | 954 const Time start_time = Time::FromInternalValue(header_->start_time); |
939 const int64_t start_ticks = header_->start_ticks; | 955 const int64_t start_ticks = header_->start_ticks; |
940 for (Activity& activity : output_snapshot->activity_stack) { | 956 for (Activity& activity : output_snapshot->activity_stack) { |
941 activity.time_internal = | 957 activity.time_internal = |
942 (start_time + | 958 (start_time + |
943 TimeDelta::FromInternalValue(activity.time_internal - start_ticks)) | 959 TimeDelta::FromInternalValue(activity.time_internal - start_ticks)) |
944 .ToInternalValue(); | 960 .ToInternalValue(); |
945 } | 961 } |
962 output_snapshot->last_exception.time_internal = | |
963 (start_time + | |
964 TimeDelta::FromInternalValue( | |
manzagop (departed)
2017/03/20 14:29:55
Ticks to time might be worth a function.
bcwhite
2017/03/21 12:25:06
Done.
| |
965 output_snapshot->last_exception.time_internal - start_ticks)) | |
966 .ToInternalValue(); | |
946 | 967 |
947 // Success! | 968 // Success! |
948 return true; | 969 return true; |
949 } | 970 } |
950 | 971 |
951 // Too many attempts. | 972 // Too many attempts. |
952 return false; | 973 return false; |
953 } | 974 } |
954 | 975 |
955 const void* ThreadActivityTracker::GetBaseAddress() { | 976 const void* ThreadActivityTracker::GetBaseAddress() { |
(...skipping 11 matching lines...) Expand all Loading... | |
967 int64_t* out_stamp) { | 988 int64_t* out_stamp) { |
968 const Header* header = reinterpret_cast<const Header*>(memory); | 989 const Header* header = reinterpret_cast<const Header*>(memory); |
969 return OwningProcess::GetOwningProcessId(&header->owner, out_id, out_stamp); | 990 return OwningProcess::GetOwningProcessId(&header->owner, out_id, out_stamp); |
970 } | 991 } |
971 | 992 |
972 // static | 993 // static |
973 size_t ThreadActivityTracker::SizeForStackDepth(int stack_depth) { | 994 size_t ThreadActivityTracker::SizeForStackDepth(int stack_depth) { |
974 return static_cast<size_t>(stack_depth) * sizeof(Activity) + sizeof(Header); | 995 return static_cast<size_t>(stack_depth) * sizeof(Activity) + sizeof(Header); |
975 } | 996 } |
976 | 997 |
998 std::unique_ptr<ActivityUserData> | |
999 ThreadActivityTracker::CreateUserDataForActivity( | |
1000 Activity* activity, | |
1001 ActivityTrackerMemoryAllocator* allocator) { | |
1002 DCHECK_EQ(0U, activity->user_data_ref); | |
1003 | |
1004 PersistentMemoryAllocator::Reference ref = allocator->GetObjectReference(); | |
1005 void* memory = allocator->GetAsArray<char>(ref, kUserDataSize); | |
1006 if (memory) { | |
1007 std::unique_ptr<ActivityUserData> user_data = | |
1008 MakeUnique<ActivityUserData>(memory, kUserDataSize); | |
1009 activity->user_data_ref = ref; | |
1010 activity->user_data_id = user_data->id(); | |
1011 return user_data; | |
1012 } | |
1013 | |
1014 // Return a dummy object that will still accept (but ignore) Set() calls. | |
1015 return MakeUnique<ActivityUserData>(); | |
1016 } | |
1017 | |
977 // The instantiation of the GlobalActivityTracker object. | 1018 // The instantiation of the GlobalActivityTracker object. |
978 // The object held here will obviously not be destructed at process exit | 1019 // The object held here will obviously not be destructed at process exit |
979 // but that's best since PersistentMemoryAllocator objects (that underlie | 1020 // but that's best since PersistentMemoryAllocator objects (that underlie |
980 // GlobalActivityTracker objects) are explicitly forbidden from doing anything | 1021 // GlobalActivityTracker objects) are explicitly forbidden from doing anything |
981 // essential at exit anyway due to the fact that they depend on data managed | 1022 // essential at exit anyway due to the fact that they depend on data managed |
982 // elsewhere and which could be destructed first. An AtomicWord is used instead | 1023 // elsewhere and which could be destructed first. An AtomicWord is used instead |
983 // of std::atomic because the latter can create global ctors and dtors. | 1024 // of std::atomic because the latter can create global ctors and dtors. |
984 subtle::AtomicWord GlobalActivityTracker::g_tracker_ = 0; | 1025 subtle::AtomicWord GlobalActivityTracker::g_tracker_ = 0; |
985 | 1026 |
986 GlobalActivityTracker::ModuleInfo::ModuleInfo() {} | 1027 GlobalActivityTracker::ModuleInfo::ModuleInfo() {} |
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1120 } | 1161 } |
1121 | 1162 |
1122 ActivityUserData& GlobalActivityTracker::ScopedThreadActivity::user_data() { | 1163 ActivityUserData& GlobalActivityTracker::ScopedThreadActivity::user_data() { |
1123 if (!user_data_) { | 1164 if (!user_data_) { |
1124 if (tracker_) { | 1165 if (tracker_) { |
1125 GlobalActivityTracker* global = GlobalActivityTracker::Get(); | 1166 GlobalActivityTracker* global = GlobalActivityTracker::Get(); |
1126 AutoLock lock(global->user_data_allocator_lock_); | 1167 AutoLock lock(global->user_data_allocator_lock_); |
1127 user_data_ = | 1168 user_data_ = |
1128 tracker_->GetUserData(activity_id_, &global->user_data_allocator_); | 1169 tracker_->GetUserData(activity_id_, &global->user_data_allocator_); |
1129 } else { | 1170 } else { |
1130 user_data_ = MakeUnique<ActivityUserData>(nullptr, 0); | 1171 user_data_ = MakeUnique<ActivityUserData>(); |
1131 } | 1172 } |
1132 } | 1173 } |
1133 return *user_data_; | 1174 return *user_data_; |
1134 } | 1175 } |
1135 | 1176 |
1136 GlobalActivityTracker::ThreadSafeUserData::ThreadSafeUserData(void* memory, | 1177 GlobalActivityTracker::ThreadSafeUserData::ThreadSafeUserData(void* memory, |
1137 size_t size) | 1178 size_t size) |
1138 : ActivityUserData(memory, size) {} | 1179 : ActivityUserData(memory, size) {} |
1139 | 1180 |
1140 GlobalActivityTracker::ThreadSafeUserData::~ThreadSafeUserData() {} | 1181 GlobalActivityTracker::ThreadSafeUserData::~ThreadSafeUserData() {} |
(...skipping 411 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1552 | 1593 |
1553 // Remove the destructed tracker from the set of known ones. | 1594 // Remove the destructed tracker from the set of known ones. |
1554 DCHECK_LE(1, thread_tracker_count_.load(std::memory_order_relaxed)); | 1595 DCHECK_LE(1, thread_tracker_count_.load(std::memory_order_relaxed)); |
1555 thread_tracker_count_.fetch_sub(1, std::memory_order_relaxed); | 1596 thread_tracker_count_.fetch_sub(1, std::memory_order_relaxed); |
1556 | 1597 |
1557 // Release this memory for re-use at a later time. | 1598 // Release this memory for re-use at a later time. |
1558 base::AutoLock autolock(thread_tracker_allocator_lock_); | 1599 base::AutoLock autolock(thread_tracker_allocator_lock_); |
1559 thread_tracker_allocator_.ReleaseObjectReference(mem_reference); | 1600 thread_tracker_allocator_.ReleaseObjectReference(mem_reference); |
1560 } | 1601 } |
1561 | 1602 |
1603 void GlobalActivityTracker::RecordExceptionImpl(const void* pc, | |
1604 const void* origin) { | |
1605 // Get an existing tracker for this thread. It's not possible to create | |
1606 // one at this point because such would involve memory allocations and | |
1607 // other potentially complex operations that can cause failures if done | |
1608 // within an exception handler. In most cases various operations will | |
1609 // have already created the tracker so this shouldn't generally be a | |
1610 // problem. | |
1611 ThreadActivityTracker* tracker = GetTrackerForCurrentThread(); | |
1612 if (!tracker) | |
1613 return; | |
1614 | |
1615 tracker->ExceptionActivity(pc, origin, Activity::ACT_EXCEPTION, | |
1616 ActivityData::ForGeneric(0, 0)); | |
1617 } | |
1618 | |
1562 // static | 1619 // static |
1563 void GlobalActivityTracker::OnTLSDestroy(void* value) { | 1620 void GlobalActivityTracker::OnTLSDestroy(void* value) { |
1564 delete reinterpret_cast<ManagedActivityTracker*>(value); | 1621 delete reinterpret_cast<ManagedActivityTracker*>(value); |
1565 } | 1622 } |
1566 | 1623 |
1567 ScopedActivity::ScopedActivity(const void* program_counter, | 1624 ScopedActivity::ScopedActivity(const void* program_counter, |
1568 uint8_t action, | 1625 uint8_t action, |
1569 uint32_t id, | 1626 uint32_t id, |
1570 int32_t info) | 1627 int32_t info) |
1571 : GlobalActivityTracker::ScopedThreadActivity( | 1628 : GlobalActivityTracker::ScopedThreadActivity( |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1642 : GlobalActivityTracker::ScopedThreadActivity( | 1699 : GlobalActivityTracker::ScopedThreadActivity( |
1643 program_counter, | 1700 program_counter, |
1644 nullptr, | 1701 nullptr, |
1645 Activity::ACT_PROCESS_WAIT, | 1702 Activity::ACT_PROCESS_WAIT, |
1646 ActivityData::ForProcess(process->Pid()), | 1703 ActivityData::ForProcess(process->Pid()), |
1647 /*lock_allowed=*/true) {} | 1704 /*lock_allowed=*/true) {} |
1648 #endif | 1705 #endif |
1649 | 1706 |
1650 } // namespace debug | 1707 } // namespace debug |
1651 } // namespace base | 1708 } // namespace base |
OLD | NEW |