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

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

Issue 2666653002: Record field-trial information in stability file for crash analysis. (Closed)
Patch Set: addressed review comments by asvitkine 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/debug/stack_trace.h" 11 #include "base/debug/stack_trace.h"
12 #include "base/files/file.h" 12 #include "base/files/file.h"
13 #include "base/files/file_path.h" 13 #include "base/files/file_path.h"
14 #include "base/files/memory_mapped_file.h" 14 #include "base/files/memory_mapped_file.h"
15 #include "base/lazy_instance.h"
15 #include "base/logging.h" 16 #include "base/logging.h"
16 #include "base/memory/ptr_util.h" 17 #include "base/memory/ptr_util.h"
17 #include "base/metrics/field_trial.h" 18 #include "base/metrics/field_trial.h"
18 #include "base/metrics/histogram_macros.h" 19 #include "base/metrics/histogram_macros.h"
19 #include "base/pending_task.h" 20 #include "base/pending_task.h"
20 #include "base/pickle.h" 21 #include "base/pickle.h"
21 #include "base/process/process.h" 22 #include "base/process/process.h"
22 #include "base/process/process_handle.h" 23 #include "base/process/process_handle.h"
23 #include "base/stl_util.h" 24 #include "base/stl_util.h"
24 #include "base/strings/string_util.h" 25 #include "base/strings/string_util.h"
25 #include "base/threading/platform_thread.h" 26 #include "base/threading/platform_thread.h"
26 27
27 namespace base { 28 namespace base {
28 namespace debug { 29 namespace debug {
29 30
30 namespace { 31 namespace {
31 32
32 // A number that identifies the memory as having been initialized. It's 33 // A number that identifies the memory as having been initialized. It's
33 // arbitrary but happens to be the first 4 bytes of SHA1(ThreadActivityTracker). 34 // arbitrary but happens to be the first 4 bytes of SHA1(ThreadActivityTracker).
34 // A version number is added on so that major structure changes won't try to 35 // A version number is added on so that major structure changes won't try to
35 // read an older version (since the cookie won't match). 36 // read an older version (since the cookie won't match).
36 const uint32_t kHeaderCookie = 0xC0029B24UL + 2; // v2 37 const uint32_t kHeaderCookie = 0xC0029B24UL + 2; // v2
37 38
38 // The minimum depth a stack should support. 39 // The minimum depth a stack should support.
39 const int kMinStackDepth = 2; 40 const int kMinStackDepth = 2;
40 41
41 // The amount of memory set aside for holding arbitrary user data (key/value 42 // The amount of memory set aside for holding arbitrary user data (key/value
42 // pairs) globally or associated with ActivityData entries. 43 // pairs) globally or associated with ActivityData entries.
43 const size_t kUserDataSize = 1024; // bytes 44 const size_t kUserDataSize = 1 << 10; // 1 KiB
44 const size_t kGlobalDataSize = 4096; // bytes 45 const size_t kGlobalDataSize = 16 << 10; // 16 KiB
45 const size_t kMaxUserDataNameLength = 46 const size_t kMaxUserDataNameLength =
46 static_cast<size_t>(std::numeric_limits<uint8_t>::max()); 47 static_cast<size_t>(std::numeric_limits<uint8_t>::max());
47 48
48 // A constant used to indicate that module information is changing. 49 // A constant used to indicate that module information is changing.
49 const uint32_t kModuleInformationChanging = 0x80000000; 50 const uint32_t kModuleInformationChanging = 0x80000000;
50 51
51 union ThreadRef { 52 union ThreadRef {
52 int64_t as_id; 53 int64_t as_id;
53 #if defined(OS_WIN) 54 #if defined(OS_WIN)
54 // On Windows, the handle itself is often a pseudo-handle with a common 55 // On Windows, the handle itself is often a pseudo-handle with a common
55 // value meaning "this thread" and so the thread-id is used. The former 56 // value meaning "this thread" and so the thread-id is used. The former
56 // can be converted to a thread-id with a system call. 57 // can be converted to a thread-id with a system call.
57 PlatformThreadId as_tid; 58 PlatformThreadId as_tid;
58 #elif defined(OS_POSIX) 59 #elif defined(OS_POSIX)
59 // On Posix, the handle is always a unique identifier so no conversion 60 // On Posix, the handle is always a unique identifier so no conversion
60 // needs to be done. However, it's value is officially opaque so there 61 // needs to be done. However, it's value is officially opaque so there
61 // is no one correct way to convert it to a numerical identifier. 62 // is no one correct way to convert it to a numerical identifier.
62 PlatformThreadHandle::Handle as_handle; 63 PlatformThreadHandle::Handle as_handle;
63 #endif 64 #endif
64 }; 65 };
65 66
67 // A class to collect field-trial information and dump it to a global
68 // tracker. If no GlobalActivityTracker exists, the information is held
69 // locally for dumping later.
70 class FieldTrialRecorder {
71 public:
72 FieldTrialRecorder() : enabled_(true) {}
73 ~FieldTrialRecorder() {}
74
75 void Disable() {
76 enabled_.store(false, std::memory_order_relaxed);
77 AutoLock lock(trial_group_lock_);
78 trial_group_map_.clear();
79 }
80
81 void DumpCollectedActivity() {
82 DCHECK(GlobalActivityTracker::Get());
83
84 // OnFieldTrialGroupFinalized will insert into trial_group_map_ if the
85 // global tracker goes away. Be safe and move its contents to a local
86 // variable first.
87 std::map<std::string, std::string> collected;
88 {
89 AutoLock lock(trial_group_lock_);
90 collected.swap(trial_group_map_);
91 }
92
93 // Store collected information to the global tracker.
94 for (const auto& kv : collected)
95 Record(kv.first, kv.second);
96 }
97
98 void Record(const std::string& trial_name, const std::string& group_name) {
99 if (!enabled_.load(std::memory_order_relaxed))
100 return;
101
102 const std::string key = std::string("FieldTrial.") + trial_name;
103
104 GlobalActivityTracker* tracker = GlobalActivityTracker::Get();
105 if (tracker) {
106 // global_data is thread-safe.
107 tracker->global_data().SetString(key, group_name);
108 } else {
109 AutoLock lock(trial_group_lock_);
110 trial_group_map_.insert(std::make_pair(key, group_name));
111 }
112 }
113
114 private:
115 std::atomic<bool> enabled_;
116 std::map<std::string, std::string> trial_group_map_;
117 Lock trial_group_lock_;
118
119 DISALLOW_COPY_AND_ASSIGN(FieldTrialRecorder);
120 };
121
122 LazyInstance<FieldTrialRecorder>::Leaky g_field_trial_recorder =
123 LAZY_INSTANCE_INITIALIZER;
124
66 // Determines the previous aligned index. 125 // Determines the previous aligned index.
67 size_t RoundDownToAlignment(size_t index, size_t alignment) { 126 size_t RoundDownToAlignment(size_t index, size_t alignment) {
68 return index & (0 - alignment); 127 return index & (0 - alignment);
69 } 128 }
70 129
71 // Determines the next aligned index. 130 // Determines the next aligned index.
72 size_t RoundUpToAlignment(size_t index, size_t alignment) { 131 size_t RoundUpToAlignment(size_t index, size_t alignment) {
73 return (index + (alignment - 1)) & (0 - alignment); 132 return (index + (alignment - 1)) & (0 - alignment);
74 } 133 }
75 134
(...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after
280 // to be used for analysis through snapshots. 339 // to be used for analysis through snapshots.
281 ImportExistingData(); 340 ImportExistingData();
282 } 341 }
283 342
284 ActivityUserData::~ActivityUserData() {} 343 ActivityUserData::~ActivityUserData() {}
285 344
286 void ActivityUserData::Set(StringPiece name, 345 void ActivityUserData::Set(StringPiece name,
287 ValueType type, 346 ValueType type,
288 const void* memory, 347 const void* memory,
289 size_t size) { 348 size_t size) {
290 DCHECK(thread_checker_.CalledOnValidThread());
291 DCHECK_GE(std::numeric_limits<uint8_t>::max(), name.length()); 349 DCHECK_GE(std::numeric_limits<uint8_t>::max(), name.length());
292 size = std::min(std::numeric_limits<uint16_t>::max() - (kMemoryAlignment - 1), 350 size = std::min(std::numeric_limits<uint16_t>::max() - (kMemoryAlignment - 1),
293 size); 351 size);
294 352
295 // It's possible that no user data is being stored. 353 // It's possible that no user data is being stored.
296 if (!memory_) 354 if (!memory_)
297 return; 355 return;
298 356
299 // The storage of a name is limited so use that limit during lookup. 357 // The storage of a name is limited so use that limit during lookup.
300 if (name.length() > kMaxUserDataNameLength) 358 if (name.length() > kMaxUserDataNameLength)
(...skipping 741 matching lines...) Expand 10 before | Expand all | Expand 10 after
1042 AutoLock lock(global->user_data_allocator_lock_); 1100 AutoLock lock(global->user_data_allocator_lock_);
1043 user_data_ = 1101 user_data_ =
1044 tracker_->GetUserData(activity_id_, &global->user_data_allocator_); 1102 tracker_->GetUserData(activity_id_, &global->user_data_allocator_);
1045 } else { 1103 } else {
1046 user_data_ = MakeUnique<ActivityUserData>(nullptr, 0); 1104 user_data_ = MakeUnique<ActivityUserData>(nullptr, 0);
1047 } 1105 }
1048 } 1106 }
1049 return *user_data_; 1107 return *user_data_;
1050 } 1108 }
1051 1109
1110 GlobalActivityTracker::GlobalUserData::GlobalUserData(void* memory, size_t size)
1111 : ActivityUserData(memory, size) {}
1112
1113 GlobalActivityTracker::GlobalUserData::~GlobalUserData() {}
1114
1115 void GlobalActivityTracker::GlobalUserData::Set(StringPiece name,
1116 ValueType type,
1117 const void* memory,
1118 size_t size) {
1119 AutoLock lock(data_lock_);
1120 ActivityUserData::Set(name, type, memory, size);
1121 }
1122
1052 GlobalActivityTracker::ManagedActivityTracker::ManagedActivityTracker( 1123 GlobalActivityTracker::ManagedActivityTracker::ManagedActivityTracker(
1053 PersistentMemoryAllocator::Reference mem_reference, 1124 PersistentMemoryAllocator::Reference mem_reference,
1054 void* base, 1125 void* base,
1055 size_t size) 1126 size_t size)
1056 : ThreadActivityTracker(base, size), 1127 : ThreadActivityTracker(base, size),
1057 mem_reference_(mem_reference), 1128 mem_reference_(mem_reference),
1058 mem_base_(base) {} 1129 mem_base_(base) {}
1059 1130
1060 GlobalActivityTracker::ManagedActivityTracker::~ManagedActivityTracker() { 1131 GlobalActivityTracker::ManagedActivityTracker::~ManagedActivityTracker() {
1061 // The global |g_tracker_| must point to the owner of this class since all 1132 // The global |g_tracker_| must point to the owner of this class since all
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after
1202 allocator_->AllocateObject<ModuleInfoRecord>(required_size); 1273 allocator_->AllocateObject<ModuleInfoRecord>(required_size);
1203 if (!record) 1274 if (!record)
1204 return; 1275 return;
1205 1276
1206 bool success = record->EncodeFrom(info, required_size); 1277 bool success = record->EncodeFrom(info, required_size);
1207 DCHECK(success); 1278 DCHECK(success);
1208 allocator_->MakeIterable(record); 1279 allocator_->MakeIterable(record);
1209 modules_.insert(std::make_pair(info.file, record)); 1280 modules_.insert(std::make_pair(info.file, record));
1210 } 1281 }
1211 1282
1283 // static
1284 void GlobalActivityTracker::RecordFieldTrial(const std::string& trial_name,
1285 const std::string& group_name) {
1286 g_field_trial_recorder.Get().Record(trial_name, group_name);
1287 }
1288
1289 // static
1290 void GlobalActivityTracker::DisableFieldTrialRecording() {
1291 g_field_trial_recorder.Get().Disable();
1292 }
1293
1212 GlobalActivityTracker::GlobalActivityTracker( 1294 GlobalActivityTracker::GlobalActivityTracker(
1213 std::unique_ptr<PersistentMemoryAllocator> allocator, 1295 std::unique_ptr<PersistentMemoryAllocator> allocator,
1214 int stack_depth) 1296 int stack_depth)
1215 : allocator_(std::move(allocator)), 1297 : allocator_(std::move(allocator)),
1216 stack_memory_size_(ThreadActivityTracker::SizeForStackDepth(stack_depth)), 1298 stack_memory_size_(ThreadActivityTracker::SizeForStackDepth(stack_depth)),
1217 this_thread_tracker_(&OnTLSDestroy), 1299 this_thread_tracker_(&OnTLSDestroy),
1218 thread_tracker_count_(0), 1300 thread_tracker_count_(0),
1219 thread_tracker_allocator_(allocator_.get(), 1301 thread_tracker_allocator_(allocator_.get(),
1220 kTypeIdActivityTracker, 1302 kTypeIdActivityTracker,
1221 kTypeIdActivityTrackerFree, 1303 kTypeIdActivityTrackerFree,
1222 stack_memory_size_, 1304 stack_memory_size_,
1223 kCachedThreadMemories, 1305 kCachedThreadMemories,
1224 /*make_iterable=*/true), 1306 /*make_iterable=*/true),
1225 user_data_allocator_(allocator_.get(), 1307 user_data_allocator_(allocator_.get(),
1226 kTypeIdUserDataRecord, 1308 kTypeIdUserDataRecord,
1227 kTypeIdUserDataRecordFree, 1309 kTypeIdUserDataRecordFree,
1228 kUserDataSize, 1310 kUserDataSize,
1229 kCachedUserDataMemories, 1311 kCachedUserDataMemories,
1230 /*make_iterable=*/false), 1312 /*make_iterable=*/false),
1231 user_data_( 1313 global_data_(
1232 allocator_->GetAsArray<char>( 1314 allocator_->GetAsArray<char>(
1233 allocator_->Allocate(kGlobalDataSize, kTypeIdGlobalDataRecord), 1315 allocator_->Allocate(kGlobalDataSize, kTypeIdGlobalDataRecord),
1234 kTypeIdGlobalDataRecord, 1316 kTypeIdGlobalDataRecord,
1235 PersistentMemoryAllocator::kSizeAny), 1317 PersistentMemoryAllocator::kSizeAny),
1236 kGlobalDataSize) { 1318 kGlobalDataSize) {
1237 // Ensure the passed memory is valid and empty (iterator finds nothing). 1319 // Ensure the passed memory is valid and empty (iterator finds nothing).
1238 uint32_t type; 1320 uint32_t type;
1239 DCHECK(!PersistentMemoryAllocator::Iterator(allocator_.get()).GetNext(&type)); 1321 DCHECK(!PersistentMemoryAllocator::Iterator(allocator_.get()).GetNext(&type));
1240 1322
1241 // Ensure that there is no other global object and then make this one such. 1323 // Ensure that there is no other global object and then make this one such.
1242 DCHECK(!g_tracker_); 1324 DCHECK(!g_tracker_);
1243 g_tracker_ = this; 1325 g_tracker_ = this;
1244 1326
1245 // The global records must be iterable in order to be found by an analyzer. 1327 // The global records must be iterable in order to be found by an analyzer.
1246 allocator_->MakeIterable(allocator_->GetAsReference( 1328 allocator_->MakeIterable(allocator_->GetAsReference(
1247 user_data_.GetBaseAddress(), kTypeIdGlobalDataRecord)); 1329 global_data_.GetBaseAddress(), kTypeIdGlobalDataRecord));
1330
1331 // Enable tracking (if not done previously) and dump previously collected
1332 // field-trial information to this global tracker.
1333 g_field_trial_recorder.Get().DumpCollectedActivity();
1248 } 1334 }
1249 1335
1250 GlobalActivityTracker::~GlobalActivityTracker() { 1336 GlobalActivityTracker::~GlobalActivityTracker() {
1251 DCHECK_EQ(g_tracker_, this); 1337 DCHECK_EQ(g_tracker_, this);
1252 DCHECK_EQ(0, thread_tracker_count_.load(std::memory_order_relaxed)); 1338 DCHECK_EQ(0, thread_tracker_count_.load(std::memory_order_relaxed));
1253 g_tracker_ = nullptr; 1339 g_tracker_ = nullptr;
1254 } 1340 }
1255 1341
1256 void GlobalActivityTracker::ReturnTrackerMemory( 1342 void GlobalActivityTracker::ReturnTrackerMemory(
1257 ManagedActivityTracker* tracker) { 1343 ManagedActivityTracker* tracker) {
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
1352 : GlobalActivityTracker::ScopedThreadActivity( 1438 : GlobalActivityTracker::ScopedThreadActivity(
1353 program_counter, 1439 program_counter,
1354 nullptr, 1440 nullptr,
1355 Activity::ACT_PROCESS_WAIT, 1441 Activity::ACT_PROCESS_WAIT,
1356 ActivityData::ForProcess(process->Pid()), 1442 ActivityData::ForProcess(process->Pid()),
1357 /*lock_allowed=*/true) {} 1443 /*lock_allowed=*/true) {}
1358 #endif 1444 #endif
1359 1445
1360 } // namespace debug 1446 } // namespace debug
1361 } // namespace base 1447 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698