media: Add RAPPOR metrics for media player origin URLs.
[chromium-blink-merge.git] / base / profiler / stack_sampling_profiler.cc
blob9da662859fd9535cb4037d1d1302401b2566f5b3
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.
5 #include "base/profiler/stack_sampling_profiler.h"
7 #include <algorithm>
9 #include "base/bind.h"
10 #include "base/callback.h"
11 #include "base/memory/singleton.h"
12 #include "base/profiler/native_stack_sampler.h"
13 #include "base/synchronization/lock.h"
14 #include "base/timer/elapsed_timer.h"
16 namespace base {
18 // DefaultProfileProcessor ----------------------------------------------------
20 namespace {
22 // Singleton class responsible for providing the default processing for profiles
23 // (i.e. for profiles generated by profilers without their own completed
24 // callback).
25 class DefaultProfileProcessor {
26 public:
27 using CompletedCallback = StackSamplingProfiler::CompletedCallback;
29 ~DefaultProfileProcessor();
31 static DefaultProfileProcessor* GetInstance();
33 // Sets the callback to use for processing profiles captured without a
34 // per-profiler completed callback. Pending completed profiles are stored in
35 // this object until a non-null callback is provided here. This function is
36 // thread-safe.
37 void SetCompletedCallback(CompletedCallback callback);
39 // Processes |profiles|. This function is thread safe.
40 void ProcessProfiles(
41 const StackSamplingProfiler::CallStackProfiles& profiles);
43 private:
44 friend struct DefaultSingletonTraits<DefaultProfileProcessor>;
46 DefaultProfileProcessor();
48 // Copies the pending profiles from |profiles_| into |profiles|, and clears
49 // |profiles_|. This function may be called on any thread.
50 void GetAndClearPendingProfiles(
51 StackSamplingProfiler::CallStackProfiles* profiles);
53 // Gets the current completed callback, with proper locking.
54 CompletedCallback GetCompletedCallback() const;
56 mutable Lock callback_lock_;
57 CompletedCallback default_completed_callback_;
59 Lock profiles_lock_;
60 StackSamplingProfiler::CallStackProfiles profiles_;
62 DISALLOW_COPY_AND_ASSIGN(DefaultProfileProcessor);
65 DefaultProfileProcessor::~DefaultProfileProcessor() {}
67 // static
68 DefaultProfileProcessor* DefaultProfileProcessor::GetInstance() {
69 return Singleton<DefaultProfileProcessor>::get();
72 void DefaultProfileProcessor::SetCompletedCallback(CompletedCallback callback) {
74 AutoLock scoped_lock(callback_lock_);
75 default_completed_callback_ = callback;
78 if (!callback.is_null()) {
79 // Provide any pending profiles to the callback immediately.
80 StackSamplingProfiler::CallStackProfiles profiles;
81 GetAndClearPendingProfiles(&profiles);
82 if (!profiles.empty())
83 callback.Run(profiles);
87 void DefaultProfileProcessor::ProcessProfiles(
88 const StackSamplingProfiler::CallStackProfiles& profiles) {
89 CompletedCallback callback = GetCompletedCallback();
91 // Store pending profiles if we don't have a valid callback.
92 if (!callback.is_null()) {
93 callback.Run(profiles);
94 } else {
95 AutoLock scoped_lock(profiles_lock_);
96 profiles_.insert(profiles_.end(), profiles.begin(), profiles.end());
100 DefaultProfileProcessor::DefaultProfileProcessor() {}
102 void DefaultProfileProcessor::GetAndClearPendingProfiles(
103 StackSamplingProfiler::CallStackProfiles* profiles) {
104 profiles->clear();
106 AutoLock scoped_lock(profiles_lock_);
107 profiles_.swap(*profiles);
110 DefaultProfileProcessor::CompletedCallback
111 DefaultProfileProcessor::GetCompletedCallback() const {
112 AutoLock scoped_lock(callback_lock_);
113 return default_completed_callback_;
116 } // namespace
118 // StackSamplingProfiler::Module ----------------------------------------------
120 StackSamplingProfiler::Module::Module() : base_address(nullptr) {}
121 StackSamplingProfiler::Module::Module(const void* base_address,
122 const std::string& id,
123 const FilePath& filename)
124 : base_address(base_address), id(id), filename(filename) {}
126 StackSamplingProfiler::Module::~Module() {}
128 // StackSamplingProfiler::Frame -----------------------------------------------
130 StackSamplingProfiler::Frame::Frame(const void* instruction_pointer,
131 size_t module_index)
132 : instruction_pointer(instruction_pointer),
133 module_index(module_index) {}
135 StackSamplingProfiler::Frame::~Frame() {}
137 // StackSamplingProfiler::CallStackProfile ------------------------------------
139 StackSamplingProfiler::CallStackProfile::CallStackProfile()
140 : preserve_sample_ordering(false), user_data(0) {}
142 StackSamplingProfiler::CallStackProfile::~CallStackProfile() {}
144 // StackSamplingProfiler::SamplingThread --------------------------------------
146 StackSamplingProfiler::SamplingThread::SamplingThread(
147 scoped_ptr<NativeStackSampler> native_sampler,
148 const SamplingParams& params,
149 CompletedCallback completed_callback)
150 : native_sampler_(native_sampler.Pass()),
151 params_(params),
152 stop_event_(false, false),
153 completed_callback_(completed_callback) {
156 StackSamplingProfiler::SamplingThread::~SamplingThread() {}
158 void StackSamplingProfiler::SamplingThread::ThreadMain() {
159 PlatformThread::SetName("Chrome_SamplingProfilerThread");
161 CallStackProfiles profiles;
162 CollectProfiles(&profiles);
163 completed_callback_.Run(profiles);
166 // Depending on how long the sampling takes and the length of the sampling
167 // interval, a burst of samples could take arbitrarily longer than
168 // samples_per_burst * sampling_interval. In this case, we (somewhat
169 // arbitrarily) honor the number of samples requested rather than strictly
170 // adhering to the sampling intervals. Once we have established users for the
171 // StackSamplingProfiler and the collected data to judge, we may go the other
172 // way or make this behavior configurable.
173 bool StackSamplingProfiler::SamplingThread::CollectProfile(
174 CallStackProfile* profile,
175 TimeDelta* elapsed_time) {
176 ElapsedTimer profile_timer;
177 CallStackProfile current_profile;
178 native_sampler_->ProfileRecordingStarting(&current_profile.modules);
179 current_profile.sampling_period = params_.sampling_interval;
180 bool burst_completed = true;
181 TimeDelta previous_elapsed_sample_time;
182 for (int i = 0; i < params_.samples_per_burst; ++i) {
183 if (i != 0) {
184 // Always wait, even if for 0 seconds, so we can observe a signal on
185 // stop_event_.
186 if (stop_event_.TimedWait(
187 std::max(params_.sampling_interval - previous_elapsed_sample_time,
188 TimeDelta()))) {
189 burst_completed = false;
190 break;
193 ElapsedTimer sample_timer;
194 current_profile.samples.push_back(Sample());
195 native_sampler_->RecordStackSample(&current_profile.samples.back());
196 previous_elapsed_sample_time = sample_timer.Elapsed();
199 *elapsed_time = profile_timer.Elapsed();
200 current_profile.profile_duration = *elapsed_time;
201 current_profile.preserve_sample_ordering = params_.preserve_sample_ordering;
202 current_profile.user_data = params_.user_data;
203 native_sampler_->ProfileRecordingStopped();
205 if (burst_completed)
206 *profile = current_profile;
208 return burst_completed;
211 // In an analogous manner to CollectProfile() and samples exceeding the expected
212 // total sampling time, bursts may also exceed the burst_interval. We adopt the
213 // same wait-and-see approach here.
214 void StackSamplingProfiler::SamplingThread::CollectProfiles(
215 CallStackProfiles* profiles) {
216 if (stop_event_.TimedWait(params_.initial_delay))
217 return;
219 TimeDelta previous_elapsed_profile_time;
220 for (int i = 0; i < params_.bursts; ++i) {
221 if (i != 0) {
222 // Always wait, even if for 0 seconds, so we can observe a signal on
223 // stop_event_.
224 if (stop_event_.TimedWait(
225 std::max(params_.burst_interval - previous_elapsed_profile_time,
226 TimeDelta())))
227 return;
230 CallStackProfile profile;
231 if (!CollectProfile(&profile, &previous_elapsed_profile_time))
232 return;
233 profiles->push_back(profile);
237 void StackSamplingProfiler::SamplingThread::Stop() {
238 stop_event_.Signal();
241 // StackSamplingProfiler ------------------------------------------------------
243 StackSamplingProfiler::SamplingParams::SamplingParams()
244 : initial_delay(TimeDelta::FromMilliseconds(0)),
245 bursts(1),
246 burst_interval(TimeDelta::FromMilliseconds(10000)),
247 samples_per_burst(300),
248 sampling_interval(TimeDelta::FromMilliseconds(100)),
249 preserve_sample_ordering(false),
250 user_data(0) {
253 StackSamplingProfiler::StackSamplingProfiler(PlatformThreadId thread_id,
254 const SamplingParams& params)
255 : thread_id_(thread_id), params_(params) {}
257 StackSamplingProfiler::StackSamplingProfiler(PlatformThreadId thread_id,
258 const SamplingParams& params,
259 CompletedCallback callback)
260 : thread_id_(thread_id), params_(params), completed_callback_(callback) {}
262 StackSamplingProfiler::~StackSamplingProfiler() {
263 Stop();
264 if (!sampling_thread_handle_.is_null())
265 PlatformThread::Join(sampling_thread_handle_);
268 void StackSamplingProfiler::Start() {
269 scoped_ptr<NativeStackSampler> native_sampler =
270 NativeStackSampler::Create(thread_id_);
271 if (!native_sampler)
272 return;
274 CompletedCallback callback =
275 !completed_callback_.is_null() ? completed_callback_ :
276 Bind(&DefaultProfileProcessor::ProcessProfiles,
277 Unretained(DefaultProfileProcessor::GetInstance()));
278 sampling_thread_.reset(
279 new SamplingThread(native_sampler.Pass(), params_, callback));
280 if (!PlatformThread::Create(0, sampling_thread_.get(),
281 &sampling_thread_handle_))
282 sampling_thread_.reset();
285 void StackSamplingProfiler::Stop() {
286 if (sampling_thread_)
287 sampling_thread_->Stop();
290 // static
291 void StackSamplingProfiler::SetDefaultCompletedCallback(
292 CompletedCallback callback) {
293 DefaultProfileProcessor::GetInstance()->SetCompletedCallback(callback);
296 // StackSamplingProfiler::Frame global functions ------------------------------
298 bool operator==(const StackSamplingProfiler::Frame &a,
299 const StackSamplingProfiler::Frame &b) {
300 return a.instruction_pointer == b.instruction_pointer &&
301 a.module_index == b.module_index;
304 bool operator<(const StackSamplingProfiler::Frame &a,
305 const StackSamplingProfiler::Frame &b) {
306 return (a.module_index < b.module_index) ||
307 (a.module_index == b.module_index &&
308 a.instruction_pointer < b.instruction_pointer);
311 } // namespace base