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 { |
29 | 30 |
30 // A number that identifies the memory as having been initialized. It's | 31 // A number that identifies the memory as having been initialized. It's |
31 // arbitrary but happens to be the first 4 bytes of SHA1(ThreadActivityTracker). | 32 // arbitrary but happens to be the first 4 bytes of SHA1(ThreadActivityTracker). |
32 // A version number is added on so that major structure changes won't try to | 33 // A version number is added on so that major structure changes won't try to |
33 // read an older version (since the cookie won't match). | 34 // read an older version (since the cookie won't match). |
34 const uint32_t kHeaderCookie = 0xC0029B24UL + 2; // v2 | 35 const uint32_t kHeaderCookie = 0xC0029B24UL + 2; // v2 |
35 | 36 |
36 // The minimum depth a stack should support. | 37 // The minimum depth a stack should support. |
37 const int kMinStackDepth = 2; | 38 const int kMinStackDepth = 2; |
38 | 39 |
39 // The amount of memory set aside for holding arbitrary user data (key/value | 40 // The amount of memory set aside for holding arbitrary user data (key/value |
40 // pairs) globally or associated with ActivityData entries. | 41 // pairs) globally or associated with ActivityData entries. |
41 const size_t kUserDataSize = 1024; // bytes | 42 const size_t kUserDataSize = 1024; // bytes |
42 const size_t kGlobalDataSize = 4096; // bytes | 43 const size_t kGlobalDataSize = 4096; // bytes |
44 const size_t kGlobalModulesSize = 4096; // bytes | |
43 const size_t kMaxUserDataNameLength = | 45 const size_t kMaxUserDataNameLength = |
44 static_cast<size_t>(std::numeric_limits<uint8_t>::max()); | 46 static_cast<size_t>(std::numeric_limits<uint8_t>::max()); |
45 | 47 |
46 union ThreadRef { | 48 union ThreadRef { |
47 int64_t as_id; | 49 int64_t as_id; |
48 #if defined(OS_WIN) | 50 #if defined(OS_WIN) |
49 // On Windows, the handle itself is often a pseudo-handle with a common | 51 // On Windows, the handle itself is often a pseudo-handle with a common |
50 // value meaning "this thread" and so the thread-id is used. The former | 52 // value meaning "this thread" and so the thread-id is used. The former |
51 // can be converted to a thread-id with a system call. | 53 // can be converted to a thread-id with a system call. |
52 PlatformThreadId as_tid; | 54 PlatformThreadId as_tid; |
53 #elif defined(OS_POSIX) | 55 #elif defined(OS_POSIX) |
54 // On Posix, the handle is always a unique identifier so no conversion | 56 // On Posix, the handle is always a unique identifier so no conversion |
55 // needs to be done. However, it's value is officially opaque so there | 57 // needs to be done. However, it's value is officially opaque so there |
56 // is no one correct way to convert it to a numerical identifier. | 58 // is no one correct way to convert it to a numerical identifier. |
57 PlatformThreadHandle::Handle as_handle; | 59 PlatformThreadHandle::Handle as_handle; |
58 #endif | 60 #endif |
59 }; | 61 }; |
60 | 62 |
63 // State of a module as stared in persistent memory. | |
manzagop (departed)
2016/12/14 20:08:53
typo: stared -> stored
bcwhite
2016/12/14 21:59:05
Done.
| |
64 struct ModuleInfoStore { | |
65 // Expected size for 32/64-bit check. | |
66 static constexpr size_t kExpectedInstanceSize = 24; | |
manzagop (departed)
2016/12/14 20:08:53
nit: I like having units in variable names (kExpec
manzagop (departed)
2016/12/14 20:08:53
Unused?
bcwhite
2016/12/14 21:59:05
The constant is required (and used) by the Persist
| |
67 | |
68 uint64_t address; // The base address of the module. | |
69 uint64_t size; // The size of the module in bytes. | |
70 uint16_t pickle_size; // The size of the following pickle. | |
71 uint8_t loaded; // Flag indicating if module is loaded or not. | |
72 char pickle[5]; // Other strings; may allocate larger. | |
73 | |
74 // Decodes/encodes storage structure from more generic info structure. | |
75 bool DecodeTo(GlobalActivityTracker::ModuleInfo* info); | |
76 bool EncodeFrom(const GlobalActivityTracker::ModuleInfo& info, size_t size); | |
manzagop (departed)
2016/12/14 20:08:53
Why do you need the size? Ah it's the size budget.
bcwhite
2016/12/14 21:59:05
Done.
| |
77 | |
78 // Updates the core information without changing the encoded strings. This is | |
79 // useful when a known module changes state (i.e. new load or unload). | |
80 bool UpdateFrom(const GlobalActivityTracker::ModuleInfo& info); | |
81 | |
82 // Deterimes the required memory size for the encoded storage. | |
manzagop (departed)
2016/12/14 20:08:53
typo: Deterimes
bcwhite
2016/12/14 21:59:05
Done.
| |
83 static size_t EncodedSize(const GlobalActivityTracker::ModuleInfo& info); | |
84 }; | |
85 | |
86 static constexpr size_t kModuleInfoStoreHeaderSize = | |
87 sizeof(ModuleInfoStore) - sizeof(((ModuleInfoStore*)0)->pickle); | |
manzagop (departed)
2016/12/14 20:08:53
Size of on the null pointer smells funny to me. Wo
bcwhite
2016/12/14 21:59:05
Done.
| |
88 | |
89 bool ModuleInfoStore::DecodeTo(GlobalActivityTracker::ModuleInfo* info) { | |
90 std::atomic_thread_fence(std::memory_order_acquire); | |
91 info->is_loaded = loaded != 0; | |
92 info->address = static_cast<uintptr_t>(address); | |
93 info->size = static_cast<size_t>(size); | |
94 | |
95 Pickle pickler(pickle, pickle_size); | |
96 PickleIterator iter(pickler); | |
97 return iter.ReadString(&info->file) && iter.ReadString(&info->version) && | |
98 iter.ReadString(&info->identifier) && | |
99 iter.ReadString(&info->debug_file) && | |
100 iter.ReadString(&info->debug_identifier); | |
101 } | |
102 | |
103 bool ModuleInfoStore::EncodeFrom(const GlobalActivityTracker::ModuleInfo& info, | |
104 size_t size) { | |
105 Pickle pickler; | |
106 bool okay = pickler.WriteString(info.file) && | |
107 pickler.WriteString(info.version) && | |
108 pickler.WriteString(info.identifier) && | |
109 pickler.WriteString(info.debug_file) && | |
110 pickler.WriteString(info.debug_identifier); | |
111 if (!okay) { | |
112 NOTREACHED(); | |
113 return false; | |
114 } | |
115 if (pickler.size() + kModuleInfoStoreHeaderSize > size) { | |
116 NOTREACHED(); | |
117 return false; | |
118 } | |
119 | |
120 memcpy(pickle, pickler.data(), pickler.size()); | |
121 return UpdateFrom(info); | |
122 } | |
123 | |
124 bool ModuleInfoStore::UpdateFrom( | |
125 const GlobalActivityTracker::ModuleInfo& info) { | |
126 address = info.address; | |
127 size = info.size; | |
128 loaded = info.is_loaded ? 1 : 0; | |
129 std::atomic_thread_fence(std::memory_order_release); | |
130 return true; | |
131 } | |
132 | |
133 // static | |
134 size_t ModuleInfoStore::EncodedSize( | |
135 const GlobalActivityTracker::ModuleInfo& info) { | |
136 PickleSizer sizer; | |
137 sizer.AddString(info.file); | |
138 sizer.AddString(info.version); | |
139 sizer.AddString(info.identifier); | |
140 sizer.AddString(info.debug_file); | |
141 sizer.AddString(info.debug_identifier); | |
142 | |
143 return kModuleInfoStoreHeaderSize + sizer.payload_size(); | |
144 } | |
145 | |
61 // Determines the previous aligned index. | 146 // Determines the previous aligned index. |
62 size_t RoundDownToAlignment(size_t index, size_t alignment) { | 147 size_t RoundDownToAlignment(size_t index, size_t alignment) { |
63 return index & (0 - alignment); | 148 return index & (0 - alignment); |
64 } | 149 } |
65 | 150 |
66 // Determines the next aligned index. | 151 // Determines the next aligned index. |
67 size_t RoundUpToAlignment(size_t index, size_t alignment) { | 152 size_t RoundUpToAlignment(size_t index, size_t alignment) { |
68 return (index + (alignment - 1)) & (0 - alignment); | 153 return (index + (alignment - 1)) & (0 - alignment); |
69 } | 154 } |
70 | 155 |
(...skipping 987 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1058 PersistentMemoryAllocator::Reference ref = | 1143 PersistentMemoryAllocator::Reference ref = |
1059 allocator_->Allocate(message.size() + 1, kTypeIdGlobalLogMessage); | 1144 allocator_->Allocate(message.size() + 1, kTypeIdGlobalLogMessage); |
1060 char* memory = allocator_->GetAsArray<char>(ref, kTypeIdGlobalLogMessage, | 1145 char* memory = allocator_->GetAsArray<char>(ref, kTypeIdGlobalLogMessage, |
1061 message.size() + 1); | 1146 message.size() + 1); |
1062 if (memory) { | 1147 if (memory) { |
1063 memcpy(memory, message.data(), message.size()); | 1148 memcpy(memory, message.data(), message.size()); |
1064 allocator_->MakeIterable(ref); | 1149 allocator_->MakeIterable(ref); |
1065 } | 1150 } |
1066 } | 1151 } |
1067 | 1152 |
1153 void GlobalActivityTracker::RecordModuleInfo(const ModuleInfo& info) { | |
1154 AutoLock lock(modules_lock_); | |
1155 auto found = modules_.find(info.file); | |
1156 if (found != modules_.end()) { | |
1157 ModuleInfoStore* store = allocator_->GetAsObject<ModuleInfoStore>( | |
1158 found->second, kTypeIdModulesRecord); | |
1159 DCHECK(store); | |
1160 | |
1161 // Get should never fail but need to be tolerant in production. | |
1162 if (store) { | |
1163 // Update the basic state of module information that has been already | |
1164 // recorded. It is assumed that the string information (identifier, | |
1165 // version, etc.) remain unchanged which means that there's no need | |
1166 // to create a new record to accomodate a possibly longer length. | |
manzagop (departed)
2016/12/14 20:08:53
typo: accommodate
bcwhite
2016/12/14 21:59:05
Done.
| |
1167 store->UpdateFrom(info); | |
1168 return; | |
manzagop (departed)
2016/12/14 20:08:53
return outside the if(store)?
bcwhite
2016/12/14 21:59:05
If it fails to load it, a new record will be creat
manzagop (departed)
2016/12/16 16:09:31
But then the map insertion will fail as the key al
bcwhite
2016/12/16 18:35:15
Good point. Always return.
| |
1169 } | |
1170 } | |
1171 | |
1172 size_t required_size = ModuleInfoStore::EncodedSize(info); | |
1173 PersistentMemoryAllocator::Reference ref = | |
1174 allocator_->Allocate(required_size, kTypeIdModulesRecord); | |
1175 ModuleInfoStore* store = | |
1176 allocator_->GetAsObject<ModuleInfoStore>(ref, kTypeIdModulesRecord); | |
1177 if (!store) | |
1178 return; | |
1179 | |
1180 bool success = store->EncodeFrom(info, allocator_->GetAllocSize(ref)); | |
1181 DCHECK(success); | |
1182 modules_.insert(std::make_pair(info.file, ref)); | |
1183 } | |
1184 | |
1068 GlobalActivityTracker::GlobalActivityTracker( | 1185 GlobalActivityTracker::GlobalActivityTracker( |
1069 std::unique_ptr<PersistentMemoryAllocator> allocator, | 1186 std::unique_ptr<PersistentMemoryAllocator> allocator, |
1070 int stack_depth) | 1187 int stack_depth) |
1071 : allocator_(std::move(allocator)), | 1188 : allocator_(std::move(allocator)), |
1072 stack_memory_size_(ThreadActivityTracker::SizeForStackDepth(stack_depth)), | 1189 stack_memory_size_(ThreadActivityTracker::SizeForStackDepth(stack_depth)), |
1073 this_thread_tracker_(&OnTLSDestroy), | 1190 this_thread_tracker_(&OnTLSDestroy), |
1074 thread_tracker_count_(0), | 1191 thread_tracker_count_(0), |
1075 thread_tracker_allocator_(allocator_.get(), | 1192 thread_tracker_allocator_(allocator_.get(), |
1076 kTypeIdActivityTracker, | 1193 kTypeIdActivityTracker, |
1077 kTypeIdActivityTrackerFree, | 1194 kTypeIdActivityTrackerFree, |
(...skipping 13 matching lines...) Expand all Loading... | |
1091 PersistentMemoryAllocator::kSizeAny), | 1208 PersistentMemoryAllocator::kSizeAny), |
1092 kGlobalDataSize) { | 1209 kGlobalDataSize) { |
1093 // Ensure the passed memory is valid and empty (iterator finds nothing). | 1210 // Ensure the passed memory is valid and empty (iterator finds nothing). |
1094 uint32_t type; | 1211 uint32_t type; |
1095 DCHECK(!PersistentMemoryAllocator::Iterator(allocator_.get()).GetNext(&type)); | 1212 DCHECK(!PersistentMemoryAllocator::Iterator(allocator_.get()).GetNext(&type)); |
1096 | 1213 |
1097 // Ensure that there is no other global object and then make this one such. | 1214 // Ensure that there is no other global object and then make this one such. |
1098 DCHECK(!g_tracker_); | 1215 DCHECK(!g_tracker_); |
1099 g_tracker_ = this; | 1216 g_tracker_ = this; |
1100 | 1217 |
1101 // The global user-data record must be iterable in order to be found by an | 1218 // The global records must be iterable in order to be found by an analyzer. |
1102 // analyzer. | |
1103 allocator_->MakeIterable(allocator_->GetAsReference( | 1219 allocator_->MakeIterable(allocator_->GetAsReference( |
1104 user_data_.GetBaseAddress(), kTypeIdGlobalDataRecord)); | 1220 user_data_.GetBaseAddress(), kTypeIdGlobalDataRecord)); |
1105 } | 1221 } |
1106 | 1222 |
1107 GlobalActivityTracker::~GlobalActivityTracker() { | 1223 GlobalActivityTracker::~GlobalActivityTracker() { |
1108 DCHECK_EQ(g_tracker_, this); | 1224 DCHECK_EQ(g_tracker_, this); |
1109 DCHECK_EQ(0, thread_tracker_count_.load(std::memory_order_relaxed)); | 1225 DCHECK_EQ(0, thread_tracker_count_.load(std::memory_order_relaxed)); |
1110 g_tracker_ = nullptr; | 1226 g_tracker_ = nullptr; |
1111 } | 1227 } |
1112 | 1228 |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1209 : GlobalActivityTracker::ScopedThreadActivity( | 1325 : GlobalActivityTracker::ScopedThreadActivity( |
1210 program_counter, | 1326 program_counter, |
1211 nullptr, | 1327 nullptr, |
1212 Activity::ACT_PROCESS_WAIT, | 1328 Activity::ACT_PROCESS_WAIT, |
1213 ActivityData::ForProcess(process->Pid()), | 1329 ActivityData::ForProcess(process->Pid()), |
1214 /*lock_allowed=*/true) {} | 1330 /*lock_allowed=*/true) {} |
1215 #endif | 1331 #endif |
1216 | 1332 |
1217 } // namespace debug | 1333 } // namespace debug |
1218 } // namespace base | 1334 } // namespace base |
OLD | NEW |