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