| 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 | 8 |
| 9 #include "base/debug/stack_trace.h" | 9 #include "base/debug/stack_trace.h" |
| 10 #include "base/files/file.h" | 10 #include "base/files/file.h" |
| 11 #include "base/files/file_path.h" | 11 #include "base/files/file_path.h" |
| 12 #include "base/files/memory_mapped_file.h" | 12 #include "base/files/memory_mapped_file.h" |
| 13 #include "base/logging.h" | 13 #include "base/logging.h" |
| 14 #include "base/memory/ptr_util.h" | 14 #include "base/memory/ptr_util.h" |
| 15 #include "base/memory/ptr_util.h" | 15 #include "base/memory/ptr_util.h" |
| 16 #include "base/metrics/field_trial.h" | 16 #include "base/metrics/field_trial.h" |
| 17 #include "base/metrics/histogram_macros.h" | 17 #include "base/metrics/histogram_macros.h" |
| 18 #include "base/pending_task.h" | 18 #include "base/pending_task.h" |
| 19 #include "base/pickle.h" |
| 19 #include "base/process/process.h" | 20 #include "base/process/process.h" |
| 20 #include "base/process/process_handle.h" | 21 #include "base/process/process_handle.h" |
| 21 #include "base/stl_util.h" | 22 #include "base/stl_util.h" |
| 22 #include "base/strings/string_util.h" | 23 #include "base/strings/string_util.h" |
| 23 #include "base/threading/platform_thread.h" | 24 #include "base/threading/platform_thread.h" |
| 24 | 25 |
| 25 namespace base { | 26 namespace base { |
| 26 namespace debug { | 27 namespace debug { |
| 27 | 28 |
| 28 namespace { | 29 namespace { |
| (...skipping 857 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 886 } | 887 } |
| 887 | 888 |
| 888 // static | 889 // static |
| 889 size_t ThreadActivityTracker::SizeForStackDepth(int stack_depth) { | 890 size_t ThreadActivityTracker::SizeForStackDepth(int stack_depth) { |
| 890 return static_cast<size_t>(stack_depth) * sizeof(Activity) + sizeof(Header); | 891 return static_cast<size_t>(stack_depth) * sizeof(Activity) + sizeof(Header); |
| 891 } | 892 } |
| 892 | 893 |
| 893 | 894 |
| 894 GlobalActivityTracker* GlobalActivityTracker::g_tracker_ = nullptr; | 895 GlobalActivityTracker* GlobalActivityTracker::g_tracker_ = nullptr; |
| 895 | 896 |
| 897 GlobalActivityTracker::ModuleInfo::ModuleInfo() {} |
| 898 GlobalActivityTracker::ModuleInfo::ModuleInfo(ModuleInfo&& rhs) = default; |
| 899 GlobalActivityTracker::ModuleInfo::ModuleInfo(const ModuleInfo& rhs) = default; |
| 900 GlobalActivityTracker::ModuleInfo::~ModuleInfo() {} |
| 901 |
| 902 GlobalActivityTracker::ModuleInfo& GlobalActivityTracker::ModuleInfo::operator=( |
| 903 ModuleInfo&& rhs) = default; |
| 904 GlobalActivityTracker::ModuleInfo& GlobalActivityTracker::ModuleInfo::operator=( |
| 905 const ModuleInfo& rhs) = default; |
| 906 |
| 907 bool GlobalActivityTracker::ModuleInfoRecord::DecodeTo( |
| 908 GlobalActivityTracker::ModuleInfo* info, |
| 909 size_t record_size) const { |
| 910 std::atomic_thread_fence(std::memory_order_acquire); |
| 911 if (offsetof(ModuleInfoRecord, pickle) + pickle_size > record_size) |
| 912 return false; |
| 913 |
| 914 info->is_loaded = loaded != 0; |
| 915 info->address = static_cast<uintptr_t>(address); |
| 916 info->size = static_cast<size_t>(size); |
| 917 |
| 918 Pickle pickler(pickle, pickle_size); |
| 919 PickleIterator iter(pickler); |
| 920 return iter.ReadString(&info->file) && iter.ReadString(&info->version) && |
| 921 iter.ReadString(&info->identifier) && |
| 922 iter.ReadString(&info->debug_file) && |
| 923 iter.ReadString(&info->debug_identifier); |
| 924 } |
| 925 |
| 926 bool GlobalActivityTracker::ModuleInfoRecord::EncodeFrom( |
| 927 const GlobalActivityTracker::ModuleInfo& info, |
| 928 size_t record_size) { |
| 929 Pickle pickler; |
| 930 bool okay = pickler.WriteString(info.file) && |
| 931 pickler.WriteString(info.version) && |
| 932 pickler.WriteString(info.identifier) && |
| 933 pickler.WriteString(info.debug_file) && |
| 934 pickler.WriteString(info.debug_identifier); |
| 935 if (!okay) { |
| 936 NOTREACHED(); |
| 937 return false; |
| 938 } |
| 939 if (offsetof(ModuleInfoRecord, pickle) + pickler.size() > record_size) { |
| 940 NOTREACHED(); |
| 941 return false; |
| 942 } |
| 943 |
| 944 memcpy(pickle, pickler.data(), pickler.size()); |
| 945 pickle_size = pickler.size(); |
| 946 return UpdateFrom(info); |
| 947 } |
| 948 |
| 949 bool GlobalActivityTracker::ModuleInfoRecord::UpdateFrom( |
| 950 const GlobalActivityTracker::ModuleInfo& info) { |
| 951 address = info.address; |
| 952 size = info.size; |
| 953 loaded = info.is_loaded ? 1 : 0; |
| 954 std::atomic_thread_fence(std::memory_order_release); |
| 955 return true; |
| 956 } |
| 957 |
| 958 // static |
| 959 size_t GlobalActivityTracker::ModuleInfoRecord::EncodedSize( |
| 960 const GlobalActivityTracker::ModuleInfo& info) { |
| 961 PickleSizer sizer; |
| 962 sizer.AddString(info.file); |
| 963 sizer.AddString(info.version); |
| 964 sizer.AddString(info.identifier); |
| 965 sizer.AddString(info.debug_file); |
| 966 sizer.AddString(info.debug_identifier); |
| 967 |
| 968 return offsetof(ModuleInfoRecord, pickle) + sizer.payload_size(); |
| 969 } |
| 970 |
| 896 GlobalActivityTracker::ScopedThreadActivity::ScopedThreadActivity( | 971 GlobalActivityTracker::ScopedThreadActivity::ScopedThreadActivity( |
| 897 const void* program_counter, | 972 const void* program_counter, |
| 898 const void* origin, | 973 const void* origin, |
| 899 Activity::Type type, | 974 Activity::Type type, |
| 900 const ActivityData& data, | 975 const ActivityData& data, |
| 901 bool lock_allowed) | 976 bool lock_allowed) |
| 902 : ThreadActivityTracker::ScopedActivity(GetOrCreateTracker(lock_allowed), | 977 : ThreadActivityTracker::ScopedActivity(GetOrCreateTracker(lock_allowed), |
| 903 program_counter, | 978 program_counter, |
| 904 origin, | 979 origin, |
| 905 type, | 980 type, |
| (...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1058 PersistentMemoryAllocator::Reference ref = | 1133 PersistentMemoryAllocator::Reference ref = |
| 1059 allocator_->Allocate(message.size() + 1, kTypeIdGlobalLogMessage); | 1134 allocator_->Allocate(message.size() + 1, kTypeIdGlobalLogMessage); |
| 1060 char* memory = allocator_->GetAsArray<char>(ref, kTypeIdGlobalLogMessage, | 1135 char* memory = allocator_->GetAsArray<char>(ref, kTypeIdGlobalLogMessage, |
| 1061 message.size() + 1); | 1136 message.size() + 1); |
| 1062 if (memory) { | 1137 if (memory) { |
| 1063 memcpy(memory, message.data(), message.size()); | 1138 memcpy(memory, message.data(), message.size()); |
| 1064 allocator_->MakeIterable(ref); | 1139 allocator_->MakeIterable(ref); |
| 1065 } | 1140 } |
| 1066 } | 1141 } |
| 1067 | 1142 |
| 1143 void GlobalActivityTracker::RecordModuleInfo(const ModuleInfo& info) { |
| 1144 AutoLock lock(modules_lock_); |
| 1145 auto found = modules_.find(info.file); |
| 1146 if (found != modules_.end()) { |
| 1147 ModuleInfoRecord* record = allocator_->GetAsObject<ModuleInfoRecord>( |
| 1148 found->second, kTypeIdModuleInfoRecord); |
| 1149 DCHECK(record); |
| 1150 |
| 1151 // Get should never fail but need to be tolerant in production. |
| 1152 if (record) { |
| 1153 // Update the basic state of module information that has been already |
| 1154 // recorded. It is assumed that the string information (identifier, |
| 1155 // version, etc.) remain unchanged which means that there's no need |
| 1156 // to create a new record to accommodate a possibly longer length. |
| 1157 record->UpdateFrom(info); |
| 1158 return; |
| 1159 } |
| 1160 } |
| 1161 |
| 1162 size_t required_size = ModuleInfoRecord::EncodedSize(info); |
| 1163 PersistentMemoryAllocator::Reference ref = |
| 1164 allocator_->Allocate(required_size, kTypeIdModuleInfoRecord); |
| 1165 ModuleInfoRecord* record = |
| 1166 allocator_->GetAsObject<ModuleInfoRecord>(ref, kTypeIdModuleInfoRecord); |
| 1167 if (!record) |
| 1168 return; |
| 1169 |
| 1170 bool success = record->EncodeFrom(info, allocator_->GetAllocSize(ref)); |
| 1171 DCHECK(success); |
| 1172 allocator_->MakeIterable(ref); |
| 1173 modules_.insert(std::make_pair(info.file, ref)); |
| 1174 } |
| 1175 |
| 1068 GlobalActivityTracker::GlobalActivityTracker( | 1176 GlobalActivityTracker::GlobalActivityTracker( |
| 1069 std::unique_ptr<PersistentMemoryAllocator> allocator, | 1177 std::unique_ptr<PersistentMemoryAllocator> allocator, |
| 1070 int stack_depth) | 1178 int stack_depth) |
| 1071 : allocator_(std::move(allocator)), | 1179 : allocator_(std::move(allocator)), |
| 1072 stack_memory_size_(ThreadActivityTracker::SizeForStackDepth(stack_depth)), | 1180 stack_memory_size_(ThreadActivityTracker::SizeForStackDepth(stack_depth)), |
| 1073 this_thread_tracker_(&OnTLSDestroy), | 1181 this_thread_tracker_(&OnTLSDestroy), |
| 1074 thread_tracker_count_(0), | 1182 thread_tracker_count_(0), |
| 1075 thread_tracker_allocator_(allocator_.get(), | 1183 thread_tracker_allocator_(allocator_.get(), |
| 1076 kTypeIdActivityTracker, | 1184 kTypeIdActivityTracker, |
| 1077 kTypeIdActivityTrackerFree, | 1185 kTypeIdActivityTrackerFree, |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1091 PersistentMemoryAllocator::kSizeAny), | 1199 PersistentMemoryAllocator::kSizeAny), |
| 1092 kGlobalDataSize) { | 1200 kGlobalDataSize) { |
| 1093 // Ensure the passed memory is valid and empty (iterator finds nothing). | 1201 // Ensure the passed memory is valid and empty (iterator finds nothing). |
| 1094 uint32_t type; | 1202 uint32_t type; |
| 1095 DCHECK(!PersistentMemoryAllocator::Iterator(allocator_.get()).GetNext(&type)); | 1203 DCHECK(!PersistentMemoryAllocator::Iterator(allocator_.get()).GetNext(&type)); |
| 1096 | 1204 |
| 1097 // Ensure that there is no other global object and then make this one such. | 1205 // Ensure that there is no other global object and then make this one such. |
| 1098 DCHECK(!g_tracker_); | 1206 DCHECK(!g_tracker_); |
| 1099 g_tracker_ = this; | 1207 g_tracker_ = this; |
| 1100 | 1208 |
| 1101 // The global user-data record must be iterable in order to be found by an | 1209 // The global records must be iterable in order to be found by an analyzer. |
| 1102 // analyzer. | |
| 1103 allocator_->MakeIterable(allocator_->GetAsReference( | 1210 allocator_->MakeIterable(allocator_->GetAsReference( |
| 1104 user_data_.GetBaseAddress(), kTypeIdGlobalDataRecord)); | 1211 user_data_.GetBaseAddress(), kTypeIdGlobalDataRecord)); |
| 1105 } | 1212 } |
| 1106 | 1213 |
| 1107 GlobalActivityTracker::~GlobalActivityTracker() { | 1214 GlobalActivityTracker::~GlobalActivityTracker() { |
| 1108 DCHECK_EQ(g_tracker_, this); | 1215 DCHECK_EQ(g_tracker_, this); |
| 1109 DCHECK_EQ(0, thread_tracker_count_.load(std::memory_order_relaxed)); | 1216 DCHECK_EQ(0, thread_tracker_count_.load(std::memory_order_relaxed)); |
| 1110 g_tracker_ = nullptr; | 1217 g_tracker_ = nullptr; |
| 1111 } | 1218 } |
| 1112 | 1219 |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1209 : GlobalActivityTracker::ScopedThreadActivity( | 1316 : GlobalActivityTracker::ScopedThreadActivity( |
| 1210 program_counter, | 1317 program_counter, |
| 1211 nullptr, | 1318 nullptr, |
| 1212 Activity::ACT_PROCESS_WAIT, | 1319 Activity::ACT_PROCESS_WAIT, |
| 1213 ActivityData::ForProcess(process->Pid()), | 1320 ActivityData::ForProcess(process->Pid()), |
| 1214 /*lock_allowed=*/true) {} | 1321 /*lock_allowed=*/true) {} |
| 1215 #endif | 1322 #endif |
| 1216 | 1323 |
| 1217 } // namespace debug | 1324 } // namespace debug |
| 1218 } // namespace base | 1325 } // namespace base |
| OLD | NEW |