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

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

Issue 2511043003: Support for extracting user-data from activity tracking. (Closed)
Patch Set: address review comments my PA Created 4 years 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 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/metrics/field_trial.h" 16 #include "base/metrics/field_trial.h"
16 #include "base/metrics/histogram_macros.h" 17 #include "base/metrics/histogram_macros.h"
17 #include "base/pending_task.h" 18 #include "base/pending_task.h"
18 #include "base/process/process.h" 19 #include "base/process/process.h"
19 #include "base/process/process_handle.h" 20 #include "base/process/process_handle.h"
20 #include "base/stl_util.h" 21 #include "base/stl_util.h"
21 #include "base/strings/string_util.h" 22 #include "base/strings/string_util.h"
22 #include "base/threading/platform_thread.h" 23 #include "base/threading/platform_thread.h"
23 24
24 namespace base { 25 namespace base {
25 namespace debug { 26 namespace debug {
26 27
27 namespace { 28 namespace {
28 29
29 // A number that identifies the memory as having been initialized. It's 30 // A number that identifies the memory as having been initialized. It's
30 // arbitrary but happens to be the first 4 bytes of SHA1(ThreadActivityTracker). 31 // arbitrary but happens to be the first 4 bytes of SHA1(ThreadActivityTracker).
31 // A version number is added on so that major structure changes won't try to 32 // A version number is added on so that major structure changes won't try to
32 // read an older version (since the cookie won't match). 33 // read an older version (since the cookie won't match).
33 const uint32_t kHeaderCookie = 0xC0029B24UL + 2; // v2 34 const uint32_t kHeaderCookie = 0xC0029B24UL + 2; // v2
34 35
35 // The minimum depth a stack should support. 36 // The minimum depth a stack should support.
36 const int kMinStackDepth = 2; 37 const int kMinStackDepth = 2;
37 38
38 // The amount of memory set aside for holding arbitrary user data (key/value 39 // The amount of memory set aside for holding arbitrary user data (key/value
39 // pairs) globally or associated with ActivityData entries. 40 // pairs) globally or associated with ActivityData entries.
40 const size_t kUserDataSize = 1024; // bytes 41 const size_t kUserDataSize = 1024; // bytes
41 const size_t kGlobalDataSize = 1024; // bytes 42 const size_t kGlobalDataSize = 4096; // bytes
42 const size_t kMaxUserDataNameLength = 43 const size_t kMaxUserDataNameLength =
43 static_cast<size_t>(std::numeric_limits<uint8_t>::max()); 44 static_cast<size_t>(std::numeric_limits<uint8_t>::max());
44 45
45 union ThreadRef { 46 union ThreadRef {
46 int64_t as_id; 47 int64_t as_id;
47 #if defined(OS_WIN) 48 #if defined(OS_WIN)
48 // On Windows, the handle itself is often a pseudo-handle with a common 49 // On Windows, the handle itself is often a pseudo-handle with a common
49 // value meaning "this thread" and so the thread-id is used. The former 50 // value meaning "this thread" and so the thread-id is used. The former
50 // can be converted to a thread-id with a system call. 51 // can be converted to a thread-id with a system call.
51 PlatformThreadId as_tid; 52 PlatformThreadId as_tid;
52 #elif defined(OS_POSIX) 53 #elif defined(OS_POSIX)
53 // On Posix, the handle is always a unique identifier so no conversion 54 // On Posix, the handle is always a unique identifier so no conversion
54 // needs to be done. However, it's value is officially opaque so there 55 // needs to be done. However, it's value is officially opaque so there
55 // is no one correct way to convert it to a numerical identifier. 56 // is no one correct way to convert it to a numerical identifier.
56 PlatformThreadHandle::Handle as_handle; 57 PlatformThreadHandle::Handle as_handle;
57 #endif 58 #endif
58 }; 59 };
59 60
61 // Determines the previous aligned index.
62 size_t RoundDownToAlignment(size_t index, size_t alignment) {
63 return index & (0 - alignment);
64 }
65
60 // Determines the next aligned index. 66 // Determines the next aligned index.
61 size_t RoundUpToAlignment(size_t index, size_t alignment) { 67 size_t RoundUpToAlignment(size_t index, size_t alignment) {
62 return (index + (alignment - 1)) & (0 - alignment); 68 return (index + (alignment - 1)) & (0 - alignment);
63 } 69 }
64 70
65 } // namespace 71 } // namespace
66 72
67 73
68 // It doesn't matter what is contained in this (though it will be all zeros) 74 // It doesn't matter what is contained in this (though it will be all zeros)
69 // as only the address of it is important. 75 // as only the address of it is important.
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
187 size_t i; 193 size_t i;
188 for (i = 1; i < stack_depth && i < kActivityCallStackSize; ++i) { 194 for (i = 1; i < stack_depth && i < kActivityCallStackSize; ++i) {
189 activity->call_stack[i - 1] = reinterpret_cast<uintptr_t>(stack_addrs[i]); 195 activity->call_stack[i - 1] = reinterpret_cast<uintptr_t>(stack_addrs[i]);
190 } 196 }
191 activity->call_stack[i - 1] = 0; 197 activity->call_stack[i - 1] = 0;
192 #else 198 #else
193 activity->call_stack[0] = 0; 199 activity->call_stack[0] = 0;
194 #endif 200 #endif
195 } 201 }
196 202
197 ActivitySnapshot::ActivitySnapshot() {} 203 ActivityUserData::TypedValue::TypedValue() {}
198 ActivitySnapshot::~ActivitySnapshot() {} 204 ActivityUserData::TypedValue::TypedValue(const TypedValue& other) = default;
205 ActivityUserData::TypedValue::~TypedValue() {}
206
207 StringPiece ActivityUserData::TypedValue::Get() const {
208 DCHECK_EQ(RAW_VALUE, type);
209 return long_value;
210 }
211
212 StringPiece ActivityUserData::TypedValue::GetReference() const {
213 DCHECK_EQ(RAW_VALUE_REFERENCE, type);
214 return ref_value;
215 }
216
217 StringPiece ActivityUserData::TypedValue::GetString() const {
218 DCHECK_EQ(STRING_VALUE, type);
219 return long_value;
220 }
221
222 StringPiece ActivityUserData::TypedValue::GetStringReference() const {
223 DCHECK_EQ(STRING_VALUE_REFERENCE, type);
224 return ref_value;
225 }
226
227 bool ActivityUserData::TypedValue::GetBool() const {
228 DCHECK_EQ(BOOL_VALUE, type);
229 return short_value != 0;
230 }
231
232 char ActivityUserData::TypedValue::GetChar() const {
233 DCHECK_EQ(CHAR_VALUE, type);
234 return static_cast<char>(short_value);
235 }
236
237 int64_t ActivityUserData::TypedValue::GetInt() const {
238 DCHECK_EQ(SIGNED_VALUE, type);
239 return static_cast<int64_t>(short_value);
240 }
241
242 uint64_t ActivityUserData::TypedValue::GetUint() const {
243 DCHECK_EQ(UNSIGNED_VALUE, type);
244 return static_cast<uint64_t>(short_value);
245 }
199 246
200 ActivityUserData::ValueInfo::ValueInfo() {} 247 ActivityUserData::ValueInfo::ValueInfo() {}
201 ActivityUserData::ValueInfo::ValueInfo(ValueInfo&&) = default; 248 ActivityUserData::ValueInfo::ValueInfo(ValueInfo&&) = default;
202 ActivityUserData::ValueInfo::~ValueInfo() {} 249 ActivityUserData::ValueInfo::~ValueInfo() {}
203 250
251 std::atomic<uint32_t> ActivityUserData::next_id_;
252
204 ActivityUserData::ActivityUserData(void* memory, size_t size) 253 ActivityUserData::ActivityUserData(void* memory, size_t size)
205 : memory_(static_cast<char*>(memory)), available_(size) {} 254 : memory_(reinterpret_cast<char*>(memory)),
255 available_(RoundDownToAlignment(size, kMemoryAlignment)),
256 id_(reinterpret_cast<std::atomic<uint32_t>*>(memory)) {
257 // It's possible that no user data is being stored.
258 if (!memory_)
259 return;
260
261 DCHECK_LT(kMemoryAlignment, available_);
262 if (id_->load(std::memory_order_relaxed) == 0) {
263 // Generate a new ID and store it in the first 32-bit word of memory_.
264 // |id_| must be non-zero for non-sink instances.
265 uint32_t id;
266 while ((id = next_id_.fetch_add(1, std::memory_order_relaxed)) == 0)
267 ;
268 id_->store(id, std::memory_order_relaxed);
269 DCHECK_NE(0U, id_->load(std::memory_order_relaxed));
270 }
271 memory_ += kMemoryAlignment;
272 available_ -= kMemoryAlignment;
273
274 // If there is already data present, load that. This allows the same class
275 // to be used for analysis through snapshots.
276 ImportExistingData();
277 }
206 278
207 ActivityUserData::~ActivityUserData() {} 279 ActivityUserData::~ActivityUserData() {}
208 280
209 void ActivityUserData::Set(StringPiece name, 281 void ActivityUserData::Set(StringPiece name,
210 ValueType type, 282 ValueType type,
211 const void* memory, 283 const void* memory,
212 size_t size) { 284 size_t size) {
213 DCHECK(thread_checker_.CalledOnValidThread()); 285 DCHECK(thread_checker_.CalledOnValidThread());
214 DCHECK_GE(std::numeric_limits<uint8_t>::max(), name.length()); 286 DCHECK_GE(std::numeric_limits<uint8_t>::max(), name.length());
215 size = std::min(std::numeric_limits<uint16_t>::max() - (kMemoryAlignment - 1), 287 size = std::min(std::numeric_limits<uint16_t>::max() - (kMemoryAlignment - 1),
(...skipping 16 matching lines...) Expand all
232 // because there are not alignment constraints on strings, it's set tight 304 // because there are not alignment constraints on strings, it's set tight
233 // against the header. Its extent (the reserved space, even if it's not 305 // against the header. Its extent (the reserved space, even if it's not
234 // all used) is calculated so that, when pressed against the header, the 306 // all used) is calculated so that, when pressed against the header, the
235 // following field will be aligned properly. 307 // following field will be aligned properly.
236 size_t name_size = name.length(); 308 size_t name_size = name.length();
237 size_t name_extent = 309 size_t name_extent =
238 RoundUpToAlignment(sizeof(Header) + name_size, kMemoryAlignment) - 310 RoundUpToAlignment(sizeof(Header) + name_size, kMemoryAlignment) -
239 sizeof(Header); 311 sizeof(Header);
240 size_t value_extent = RoundUpToAlignment(size, kMemoryAlignment); 312 size_t value_extent = RoundUpToAlignment(size, kMemoryAlignment);
241 313
242 // The "basic size" is the minimum size of the record. It's possible that 314 // The "base size" is the size of the header and string key. Stop now if
manzagop (departed) 2016/12/02 22:13:32 and alignment padding?
bcwhite 2016/12/08 21:30:56 Done.
243 // lengthy values will get truncated but there must be at least some bytes 315 // there's not room enough for even this.
244 // available. 316 size_t base_size = sizeof(Header) + name_extent;
245 size_t basic_size = sizeof(Header) + name_extent + kMemoryAlignment; 317 if (base_size > available_)
246 if (basic_size > available_) 318 return;
247 return; // No space to store even the smallest value.
248 319
249 // The "full size" is the size for storing the entire value, truncated 320 // The "full size" is the size for storing the entire value.
250 // to the amount of available memory.
251 size_t full_size = 321 size_t full_size =
252 std::min(sizeof(Header) + name_extent + value_extent, available_); 322 std::min(sizeof(Header) + name_extent + value_extent, available_);
manzagop (departed) 2016/12/02 22:13:32 nit: use base_size / fit on 1 line?
bcwhite 2016/12/08 21:30:56 Done.
323
324 // If the value is actually a single byte, see if it can be stuffed at the
325 // end of the name extent rather than wasting kMemoryAlignment bytes.
326 if (size == 1 && name_extent > name_size) {
327 full_size = base_size;
328 --name_extent;
manzagop (departed) 2016/12/02 22:13:32 Should you also update base_size to be safe if som
bcwhite 2016/12/08 21:30:56 Done.
329 }
330
331 // Truncate the stored size to the amount of available memory. Stop now if
332 // there's not any room for even part of the value.
253 size = std::min(full_size - sizeof(Header) - name_extent, size); 333 size = std::min(full_size - sizeof(Header) - name_extent, size);
manzagop (departed) 2016/12/02 22:13:32 nit: base_size is more readable? (Assuming you upd
bcwhite 2016/12/08 21:30:56 Done.
334 if (size == 0)
manzagop (departed) 2016/12/02 22:13:32 Are there cases where we'd want to only have a key
bcwhite 2016/12/08 21:30:56 I don't think there's a big need for intentional k
335 return;
254 336
255 // Allocate a chunk of memory. 337 // Allocate a chunk of memory.
256 Header* header = reinterpret_cast<Header*>(memory_); 338 Header* header = reinterpret_cast<Header*>(memory_);
257 memory_ += full_size; 339 memory_ += full_size;
258 available_ -= full_size; 340 available_ -= full_size;
259 341
260 // Datafill the header and name records. Memory must be zeroed. The |type| 342 // Datafill the header and name records. Memory must be zeroed. The |type|
261 // is written last, atomically, to release all the other values. 343 // is written last, atomically, to release all the other values.
262 DCHECK_EQ(END_OF_VALUES, header->type.load(std::memory_order_relaxed)); 344 DCHECK_EQ(END_OF_VALUES, header->type.load(std::memory_order_relaxed));
263 DCHECK_EQ(0, header->value_size.load(std::memory_order_relaxed)); 345 DCHECK_EQ(0, header->value_size.load(std::memory_order_relaxed));
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
296 void ActivityUserData::SetReference(StringPiece name, 378 void ActivityUserData::SetReference(StringPiece name,
297 ValueType type, 379 ValueType type,
298 const void* memory, 380 const void* memory,
299 size_t size) { 381 size_t size) {
300 ReferenceRecord rec; 382 ReferenceRecord rec;
301 rec.address = reinterpret_cast<uintptr_t>(memory); 383 rec.address = reinterpret_cast<uintptr_t>(memory);
302 rec.size = size; 384 rec.size = size;
303 Set(name, type, &rec, sizeof(rec)); 385 Set(name, type, &rec, sizeof(rec));
304 } 386 }
305 387
388 void ActivityUserData::ImportExistingData() const {
389 while (available_ > sizeof(Header)) {
390 Header* header = reinterpret_cast<Header*>(memory_);
391 ValueType type =
392 static_cast<ValueType>(header->type.load(std::memory_order_acquire));
393 if (type == END_OF_VALUES)
394 return;
395 if (header->record_size > available_)
396 return;
397
398 size_t value_offset = RoundUpToAlignment(sizeof(Header) + header->name_size,
399 kMemoryAlignment);
400 if (header->record_size == value_offset &&
401 header->value_size.load(std::memory_order_relaxed) == 1) {
402 value_offset -= 1;
403 }
404 if (value_offset + header->value_size > header->record_size)
405 return;
406
407 ValueInfo info;
408 info.name = StringPiece(memory_ + sizeof(Header), header->name_size);
409 info.type = type;
410 info.memory = memory_ + value_offset;
411 info.size_ptr = &header->value_size;
412 info.extent = header->record_size - value_offset;
413
414 StringPiece key(info.name);
415 values_.insert(std::make_pair(key, std::move(info)));
416
417 memory_ += header->record_size;
418 available_ -= header->record_size;
419 }
420 }
421
422 bool ActivityUserData::CreateSnapshot(Snapshot* output_snapshot) const {
423 DCHECK(output_snapshot);
424 DCHECK(output_snapshot->empty());
425
426 // Find any new data that may have been added by an active instance of this
427 // class that is adding records.
428 ImportExistingData();
429
430 for (const auto& entry : values_) {
431 TypedValue value;
432 value.type = entry.second.type;
433 DCHECK_GE(entry.second.extent,
434 entry.second.size_ptr->load(std::memory_order_relaxed));
435
436 switch (entry.second.type) {
437 case RAW_VALUE:
438 case STRING_VALUE:
439 value.long_value =
440 std::string(reinterpret_cast<char*>(entry.second.memory),
441 entry.second.size_ptr->load(std::memory_order_relaxed));
442 break;
443 case RAW_VALUE_REFERENCE:
444 case STRING_VALUE_REFERENCE: {
445 ReferenceRecord* ref =
446 reinterpret_cast<ReferenceRecord*>(entry.second.memory);
447 value.ref_value = StringPiece(
448 reinterpret_cast<char*>(static_cast<uintptr_t>(ref->address)),
449 static_cast<size_t>(ref->size));
450 } break;
451 case BOOL_VALUE:
452 case CHAR_VALUE:
453 value.short_value = *reinterpret_cast<char*>(entry.second.memory);
454 break;
455 case SIGNED_VALUE:
456 case UNSIGNED_VALUE:
457 value.short_value = *reinterpret_cast<uint64_t*>(entry.second.memory);
458 break;
459 case END_OF_VALUES: // Included for completeness purposes.
460 NOTREACHED();
461 }
462 auto inserted = output_snapshot->insert(
463 std::make_pair(entry.second.name.as_string(), std::move(value)));
464 DCHECK(inserted.second); // True if inserted, false if existed.
465 }
466
467 return true;
468 }
469
470 const void* ActivityUserData::GetBaseAddress() {
471 // The |memory_| pointer advances as elements are written but the |id_|
472 // value is always at the start of the block so just return that.
473 return id_;
474 }
475
476 ActivitySnapshot::ActivitySnapshot() {}
477 ActivitySnapshot::~ActivitySnapshot() {}
478
306 // This information is kept for every thread that is tracked. It is filled 479 // This information is kept for every thread that is tracked. It is filled
307 // the very first time the thread is seen. All fields must be of exact sizes 480 // the very first time the thread is seen. All fields must be of exact sizes
308 // so there is no issue moving between 32 and 64-bit builds. 481 // so there is no issue moving between 32 and 64-bit builds.
309 struct ThreadActivityTracker::Header { 482 struct ThreadActivityTracker::Header {
310 // Expected size for 32/64-bit check. 483 // Expected size for 32/64-bit check.
311 static constexpr size_t kExpectedInstanceSize = 80; 484 static constexpr size_t kExpectedInstanceSize = 80;
312 485
313 // This unique number indicates a valid initialization of the memory. 486 // This unique number indicates a valid initialization of the memory.
314 std::atomic<uint32_t> cookie; 487 std::atomic<uint32_t> cookie;
315 488
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
375 tracker_->PopActivity(activity_id_); 548 tracker_->PopActivity(activity_id_);
376 } 549 }
377 550
378 void ThreadActivityTracker::ScopedActivity::ChangeTypeAndData( 551 void ThreadActivityTracker::ScopedActivity::ChangeTypeAndData(
379 Activity::Type type, 552 Activity::Type type,
380 const ActivityData& data) { 553 const ActivityData& data) {
381 if (tracker_) 554 if (tracker_)
382 tracker_->ChangeActivity(activity_id_, type, data); 555 tracker_->ChangeActivity(activity_id_, type, data);
383 } 556 }
384 557
385 ActivityUserData& ThreadActivityTracker::ScopedActivity::user_data() {
386 if (!user_data_) {
387 if (tracker_)
388 user_data_ = tracker_->GetUserData(activity_id_);
389 else
390 user_data_ = MakeUnique<ActivityUserData>(nullptr, 0);
391 }
392 return *user_data_;
393 }
394
395 ThreadActivityTracker::ThreadActivityTracker(void* base, size_t size) 558 ThreadActivityTracker::ThreadActivityTracker(void* base, size_t size)
396 : header_(static_cast<Header*>(base)), 559 : header_(static_cast<Header*>(base)),
397 stack_(reinterpret_cast<Activity*>(reinterpret_cast<char*>(base) + 560 stack_(reinterpret_cast<Activity*>(reinterpret_cast<char*>(base) +
398 sizeof(Header))), 561 sizeof(Header))),
399 stack_slots_( 562 stack_slots_(
400 static_cast<uint32_t>((size - sizeof(Header)) / sizeof(Activity))) { 563 static_cast<uint32_t>((size - sizeof(Header)) / sizeof(Activity))) {
401 DCHECK(thread_checker_.CalledOnValidThread()); 564 DCHECK(thread_checker_.CalledOnValidThread());
402 565
403 // Verify the parameters but fail gracefully if they're not valid so that 566 // Verify the parameters but fail gracefully if they're not valid so that
404 // production code based on external inputs will not crash. IsValid() will 567 // production code based on external inputs will not crash. IsValid() will
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after
540 header_->current_depth.fetch_sub(1, std::memory_order_relaxed) - 1; 703 header_->current_depth.fetch_sub(1, std::memory_order_relaxed) - 1;
541 704
542 // Validate that everything is running correctly. 705 // Validate that everything is running correctly.
543 DCHECK_EQ(id, depth); 706 DCHECK_EQ(id, depth);
544 707
545 // A thread-checker creates a lock to check the thread-id which means 708 // A thread-checker creates a lock to check the thread-id which means
546 // re-entry into this code if lock acquisitions are being tracked. 709 // re-entry into this code if lock acquisitions are being tracked.
547 DCHECK(stack_[depth].activity_type == Activity::ACT_LOCK_ACQUIRE || 710 DCHECK(stack_[depth].activity_type == Activity::ACT_LOCK_ACQUIRE ||
548 thread_checker_.CalledOnValidThread()); 711 thread_checker_.CalledOnValidThread());
549 712
550 // Check if there was any user-data memory. It isn't free'd until later
551 // because the call to release it can push something on the stack.
552 PersistentMemoryAllocator::Reference user_data = stack_[depth].user_data;
553 stack_[depth].user_data = 0;
554
555 // The stack has shrunk meaning that some other thread trying to copy the 713 // The stack has shrunk meaning that some other thread trying to copy the
556 // contents for reporting purposes could get bad data. That thread would 714 // contents for reporting purposes could get bad data. That thread would
557 // have written a non-zero value into |stack_unchanged|; clearing it here 715 // have written a non-zero value into |stack_unchanged|; clearing it here
558 // will let that thread detect that something did change. This needs to 716 // will let that thread detect that something did change. This needs to
559 // happen after the atomic |depth| operation above so a "release" store 717 // happen after the atomic |depth| operation above so a "release" store
560 // is required. 718 // is required.
561 header_->stack_unchanged.store(0, std::memory_order_release); 719 header_->stack_unchanged.store(0, std::memory_order_release);
562
563 // Release resources located above. All stack processing is done so it's
564 // safe if some outside code does another push.
565 if (user_data)
566 GlobalActivityTracker::Get()->ReleaseUserDataMemory(&user_data);
567 } 720 }
568 721
569 std::unique_ptr<ActivityUserData> ThreadActivityTracker::GetUserData( 722 std::unique_ptr<ActivityUserData> ThreadActivityTracker::GetUserData(
570 ActivityId id) { 723 ActivityId id,
724 ActivityTrackerMemoryAllocator* allocator) {
571 // User-data is only stored for activities actually held in the stack. 725 // User-data is only stored for activities actually held in the stack.
572 if (id < stack_slots_) { 726 if (id < stack_slots_) {
727 // Don't allow user data for lock acquisition as recursion may occur.
728 if (stack_[id].activity_type == Activity::ACT_LOCK_ACQUIRE) {
729 NOTREACHED();
730 return MakeUnique<ActivityUserData>(nullptr, 0);
731 }
732
733 // Get (or reuse) a block of memory and create a real UserData object
734 // on it.
735 PersistentMemoryAllocator::Reference ref = allocator->GetObjectReference();
573 void* memory = 736 void* memory =
574 GlobalActivityTracker::Get()->GetUserDataMemory(&stack_[id].user_data); 737 allocator->GetAsArray<char>(ref, PersistentMemoryAllocator::kSizeAny);
575 if (memory) 738 if (memory) {
576 return MakeUnique<ActivityUserData>(memory, kUserDataSize); 739 std::unique_ptr<ActivityUserData> user_data =
740 MakeUnique<ActivityUserData>(memory, kUserDataSize);
741 stack_[id].user_data_ref = ref;
742 stack_[id].user_data_id = user_data->id();
743 return user_data;
744 }
577 } 745 }
578 746
579 // Return a dummy object that will still accept (but ignore) Set() calls. 747 // Return a dummy object that will still accept (but ignore) Set() calls.
580 return MakeUnique<ActivityUserData>(nullptr, 0); 748 return MakeUnique<ActivityUserData>(nullptr, 0);
581 } 749 }
582 750
751 bool ThreadActivityTracker::HasUserData(ActivityId id) {
752 // User-data is only stored for activities actually held in the stack.
753 return (id < stack_slots_ && stack_[id].user_data_ref);
754 }
755
756 void ThreadActivityTracker::ReleaseUserData(
757 ActivityId id,
758 ActivityTrackerMemoryAllocator* allocator) {
759 // User-data is only stored for activities actually held in the stack.
760 if (id < stack_slots_ && stack_[id].user_data_ref) {
761 allocator->ReleaseObjectReference(stack_[id].user_data_ref);
762 stack_[id].user_data_ref = 0;
763 }
764 }
765
583 bool ThreadActivityTracker::IsValid() const { 766 bool ThreadActivityTracker::IsValid() const {
584 if (header_->cookie.load(std::memory_order_acquire) != kHeaderCookie || 767 if (header_->cookie.load(std::memory_order_acquire) != kHeaderCookie ||
585 header_->process_id.load(std::memory_order_relaxed) == 0 || 768 header_->process_id.load(std::memory_order_relaxed) == 0 ||
586 header_->thread_ref.as_id == 0 || 769 header_->thread_ref.as_id == 0 ||
587 header_->start_time == 0 || 770 header_->start_time == 0 ||
588 header_->start_ticks == 0 || 771 header_->start_ticks == 0 ||
589 header_->stack_slots != stack_slots_ || 772 header_->stack_slots != stack_slots_ ||
590 header_->thread_name[sizeof(header_->thread_name) - 1] != '\0') { 773 header_->thread_name[sizeof(header_->thread_name) - 1] != '\0') {
591 return false; 774 return false;
592 } 775 }
593 776
594 return valid_; 777 return valid_;
595 } 778 }
596 779
597 bool ThreadActivityTracker::Snapshot(ActivitySnapshot* output_snapshot) const { 780 bool ThreadActivityTracker::CreateSnapshot(
781 ActivitySnapshot* output_snapshot) const {
598 DCHECK(output_snapshot); 782 DCHECK(output_snapshot);
599 783
600 // There is no "called on valid thread" check for this method as it can be 784 // There is no "called on valid thread" check for this method as it can be
601 // called from other threads or even other processes. It is also the reason 785 // called from other threads or even other processes. It is also the reason
602 // why atomic operations must be used in certain places above. 786 // why atomic operations must be used in certain places above.
603 787
604 // It's possible for the data to change while reading it in such a way that it 788 // It's possible for the data to change while reading it in such a way that it
605 // invalidates the read. Make several attempts but don't try forever. 789 // invalidates the read. Make several attempts but don't try forever.
606 const int kMaxAttempts = 10; 790 const int kMaxAttempts = 10;
607 uint32_t depth; 791 uint32_t depth;
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
703 } 887 }
704 888
705 // static 889 // static
706 size_t ThreadActivityTracker::SizeForStackDepth(int stack_depth) { 890 size_t ThreadActivityTracker::SizeForStackDepth(int stack_depth) {
707 return static_cast<size_t>(stack_depth) * sizeof(Activity) + sizeof(Header); 891 return static_cast<size_t>(stack_depth) * sizeof(Activity) + sizeof(Header);
708 } 892 }
709 893
710 894
711 GlobalActivityTracker* GlobalActivityTracker::g_tracker_ = nullptr; 895 GlobalActivityTracker* GlobalActivityTracker::g_tracker_ = nullptr;
712 896
897 GlobalActivityTracker::ScopedThreadActivity::ScopedThreadActivity(
898 const void* program_counter,
899 const void* origin,
900 Activity::Type type,
901 const ActivityData& data,
902 bool lock_allowed)
903 : ThreadActivityTracker::ScopedActivity(GetOrCreateTracker(lock_allowed),
904 program_counter,
905 origin,
906 type,
907 data) {}
908
909 GlobalActivityTracker::ScopedThreadActivity::~ScopedThreadActivity() {
910 if (tracker_ && tracker_->HasUserData(activity_id_)) {
911 GlobalActivityTracker* global = GlobalActivityTracker::Get();
912 AutoLock lock(global->user_data_allocator_lock_);
913 tracker_->ReleaseUserData(activity_id_, &global->user_data_allocator_);
914 }
915 }
916
917 ActivityUserData& GlobalActivityTracker::ScopedThreadActivity::user_data() {
918 if (!user_data_) {
919 if (tracker_) {
920 GlobalActivityTracker* global = GlobalActivityTracker::Get();
921 AutoLock lock(global->user_data_allocator_lock_);
922 user_data_ =
923 tracker_->GetUserData(activity_id_, &global->user_data_allocator_);
924 } else {
925 user_data_ = MakeUnique<ActivityUserData>(nullptr, 0);
926 }
927 }
928 return *user_data_;
929 }
930
713 GlobalActivityTracker::ManagedActivityTracker::ManagedActivityTracker( 931 GlobalActivityTracker::ManagedActivityTracker::ManagedActivityTracker(
714 PersistentMemoryAllocator::Reference mem_reference, 932 PersistentMemoryAllocator::Reference mem_reference,
715 void* base, 933 void* base,
716 size_t size) 934 size_t size)
717 : ThreadActivityTracker(base, size), 935 : ThreadActivityTracker(base, size),
718 mem_reference_(mem_reference), 936 mem_reference_(mem_reference),
719 mem_base_(base) {} 937 mem_base_(base) {}
720 938
721 GlobalActivityTracker::ManagedActivityTracker::~ManagedActivityTracker() { 939 GlobalActivityTracker::ManagedActivityTracker::~ManagedActivityTracker() {
722 // The global |g_tracker_| must point to the owner of this class since all 940 // The global |g_tracker_| must point to the owner of this class since all
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
828 return tracker; 1046 return tracker;
829 } 1047 }
830 1048
831 void GlobalActivityTracker::ReleaseTrackerForCurrentThreadForTesting() { 1049 void GlobalActivityTracker::ReleaseTrackerForCurrentThreadForTesting() {
832 ThreadActivityTracker* tracker = 1050 ThreadActivityTracker* tracker =
833 reinterpret_cast<ThreadActivityTracker*>(this_thread_tracker_.Get()); 1051 reinterpret_cast<ThreadActivityTracker*>(this_thread_tracker_.Get());
834 if (tracker) 1052 if (tracker)
835 delete tracker; 1053 delete tracker;
836 } 1054 }
837 1055
838 void* GlobalActivityTracker::GetUserDataMemory(
839 PersistentMemoryAllocator::Reference* reference) {
840 if (!*reference) {
841 base::AutoLock autolock(user_data_allocator_lock_);
842 *reference = user_data_allocator_.GetObjectReference();
843 if (!*reference)
844 return nullptr;
845 }
846
847 void* memory = allocator_->GetAsArray<char>(
848 *reference, kTypeIdUserDataRecord, PersistentMemoryAllocator::kSizeAny);
849 DCHECK(memory);
850 return memory;
851 }
852
853 void GlobalActivityTracker::ReleaseUserDataMemory(
854 PersistentMemoryAllocator::Reference* reference) {
855 DCHECK(*reference);
856 base::AutoLock autolock(user_data_allocator_lock_);
857 user_data_allocator_.ReleaseObjectReference(*reference);
858 *reference = PersistentMemoryAllocator::kReferenceNull;
859 }
860
861 GlobalActivityTracker::GlobalActivityTracker( 1056 GlobalActivityTracker::GlobalActivityTracker(
862 std::unique_ptr<PersistentMemoryAllocator> allocator, 1057 std::unique_ptr<PersistentMemoryAllocator> allocator,
863 int stack_depth) 1058 int stack_depth)
864 : allocator_(std::move(allocator)), 1059 : allocator_(std::move(allocator)),
865 stack_memory_size_(ThreadActivityTracker::SizeForStackDepth(stack_depth)), 1060 stack_memory_size_(ThreadActivityTracker::SizeForStackDepth(stack_depth)),
866 this_thread_tracker_(&OnTLSDestroy), 1061 this_thread_tracker_(&OnTLSDestroy),
867 thread_tracker_count_(0), 1062 thread_tracker_count_(0),
868 thread_tracker_allocator_(allocator_.get(), 1063 thread_tracker_allocator_(allocator_.get(),
869 kTypeIdActivityTracker, 1064 kTypeIdActivityTracker,
870 kTypeIdActivityTrackerFree, 1065 kTypeIdActivityTrackerFree,
(...skipping 12 matching lines...) Expand all
883 kTypeIdGlobalDataRecord, 1078 kTypeIdGlobalDataRecord,
884 PersistentMemoryAllocator::kSizeAny), 1079 PersistentMemoryAllocator::kSizeAny),
885 kGlobalDataSize) { 1080 kGlobalDataSize) {
886 // Ensure the passed memory is valid and empty (iterator finds nothing). 1081 // Ensure the passed memory is valid and empty (iterator finds nothing).
887 uint32_t type; 1082 uint32_t type;
888 DCHECK(!PersistentMemoryAllocator::Iterator(allocator_.get()).GetNext(&type)); 1083 DCHECK(!PersistentMemoryAllocator::Iterator(allocator_.get()).GetNext(&type));
889 1084
890 // Ensure that there is no other global object and then make this one such. 1085 // Ensure that there is no other global object and then make this one such.
891 DCHECK(!g_tracker_); 1086 DCHECK(!g_tracker_);
892 g_tracker_ = this; 1087 g_tracker_ = this;
1088
1089 // The global user-data record must be iterable in order to be found by an
1090 // analyzer.
1091 allocator_->MakeIterable(allocator_->GetAsReference(
1092 user_data_.GetBaseAddress(), kTypeIdGlobalDataRecord));
893 } 1093 }
894 1094
895 GlobalActivityTracker::~GlobalActivityTracker() { 1095 GlobalActivityTracker::~GlobalActivityTracker() {
896 DCHECK_EQ(g_tracker_, this); 1096 DCHECK_EQ(g_tracker_, this);
897 DCHECK_EQ(0, thread_tracker_count_.load(std::memory_order_relaxed)); 1097 DCHECK_EQ(0, thread_tracker_count_.load(std::memory_order_relaxed));
898 g_tracker_ = nullptr; 1098 g_tracker_ = nullptr;
899 } 1099 }
900 1100
901 void GlobalActivityTracker::ReturnTrackerMemory( 1101 void GlobalActivityTracker::ReturnTrackerMemory(
902 ManagedActivityTracker* tracker) { 1102 ManagedActivityTracker* tracker) {
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
997 : GlobalActivityTracker::ScopedThreadActivity( 1197 : GlobalActivityTracker::ScopedThreadActivity(
998 program_counter, 1198 program_counter,
999 nullptr, 1199 nullptr,
1000 Activity::ACT_PROCESS_WAIT, 1200 Activity::ACT_PROCESS_WAIT,
1001 ActivityData::ForProcess(process->Pid()), 1201 ActivityData::ForProcess(process->Pid()),
1002 /*lock_allowed=*/true) {} 1202 /*lock_allowed=*/true) {}
1003 #endif 1203 #endif
1004 1204
1005 } // namespace debug 1205 } // namespace debug
1006 } // namespace base 1206 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698