1 // Copyright 2015 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include <stddef.h> 6 7 #include "base/trace_event/trace_event.h" 8 #include "base/trace_event/trace_event_impl.h" 9 #include "base/trace_event/trace_log.h" 10 #include "base/trace_event/trace_sampling_thread.h" 11 12 namespace base { 13 namespace trace_event { 14 15 class TraceBucketData { 16 public: 17 TraceBucketData(base::subtle::AtomicWord* bucket, 18 const char* name, 19 TraceSampleCallback callback); 20 ~TraceBucketData(); 21 22 TRACE_EVENT_API_ATOMIC_WORD* bucket; 23 const char* bucket_name; 24 TraceSampleCallback callback; 25 }; 26 27 TraceSamplingThread::TraceSamplingThread() 28 : thread_running_(false), 29 waitable_event_for_testing_(WaitableEvent::ResetPolicy::AUTOMATIC, 30 WaitableEvent::InitialState::NOT_SIGNALED) {} 31 32 TraceSamplingThread::~TraceSamplingThread() {} 33 34 void TraceSamplingThread::ThreadMain() { 35 PlatformThread::SetName("Sampling Thread"); 36 thread_running_ = true; 37 const int kSamplingFrequencyMicroseconds = 1000; 38 while (!cancellation_flag_.IsSet()) { 39 PlatformThread::Sleep( 40 TimeDelta::FromMicroseconds(kSamplingFrequencyMicroseconds)); 41 GetSamples(); 42 waitable_event_for_testing_.Signal(); 43 } 44 } 45 46 // static 47 void TraceSamplingThread::DefaultSamplingCallback( 48 TraceBucketData* bucket_data) { 49 TRACE_EVENT_API_ATOMIC_WORD category_and_name = 50 TRACE_EVENT_API_ATOMIC_LOAD(*bucket_data->bucket); 51 if (!category_and_name) 52 return; 53 const char* const combined = 54 reinterpret_cast<const char* const>(category_and_name); 55 const char* category_group; 56 const char* name; 57 ExtractCategoryAndName(combined, &category_group, &name); 58 TRACE_EVENT_API_ADD_TRACE_EVENT( 59 TRACE_EVENT_PHASE_SAMPLE, 60 TraceLog::GetCategoryGroupEnabled(category_group), name, 61 trace_event_internal::kGlobalScope, trace_event_internal::kNoId, 0, 62 NULL, NULL, NULL, NULL, 0); 63 } 64 65 void TraceSamplingThread::GetSamples() { 66 for (size_t i = 0; i < sample_buckets_.size(); ++i) { 67 TraceBucketData* bucket_data = &sample_buckets_[i]; 68 bucket_data->callback.Run(bucket_data); 69 } 70 } 71 72 void TraceSamplingThread::RegisterSampleBucket( 73 TRACE_EVENT_API_ATOMIC_WORD* bucket, 74 const char* const name, 75 TraceSampleCallback callback) { 76 // Access to sample_buckets_ doesn't cause races with the sampling thread 77 // that uses the sample_buckets_, because it is guaranteed that 78 // RegisterSampleBucket is called before the sampling thread is created. 79 DCHECK(!thread_running_); 80 sample_buckets_.push_back(TraceBucketData(bucket, name, callback)); 81 } 82 83 // static 84 void TraceSamplingThread::ExtractCategoryAndName(const char* combined, 85 const char** category, 86 const char** name) { 87 *category = combined; 88 *name = &combined[strlen(combined) + 1]; 89 } 90 91 void TraceSamplingThread::Stop() { 92 cancellation_flag_.Set(); 93 } 94 95 void TraceSamplingThread::WaitSamplingEventForTesting() { 96 waitable_event_for_testing_.Wait(); 97 } 98 99 TraceBucketData::TraceBucketData(base::subtle::AtomicWord* bucket, 100 const char* name, 101 TraceSampleCallback callback) 102 : bucket(bucket), bucket_name(name), callback(callback) {} 103 104 TraceBucketData::~TraceBucketData() {} 105 106 } // namespace trace_event 107 } // namespace base 108