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

Side by Side Diff: base/profiler/stack_sampling_profiler.cc

Issue 1016563004: Statistical stack profiler for Windows x64 (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@lkcr
Patch Set: Created 5 years, 9 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
(Empty)
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 "base/profiler/stack_sampling_profiler.h"
6
7 #include <algorithm>
8
9 #include "base/bind.h"
10 #include "base/callback.h"
11 #include "base/memory/singleton.h"
12 #include "base/synchronization/lock.h"
13 #include "base/synchronization/waitable_event.h"
14 #include "base/timer/elapsed_timer.h"
15
16 template <typename T> struct DefaultSingletonTraits;
17
18 namespace base {
19
20 namespace {
Alexei Svitkine (slow) 2015/03/17 13:10:00 Add a blank line after this.
Mike Wittman 2015/03/17 19:07:37 Done.
21 // Thread-safe singleton class that stores collected profiles waiting to be
22 // processed.
23 class PendingProfiles {
24 public:
Alexei Svitkine (slow) 2015/03/17 13:10:00 Indent is wrong. "git cl format"?
Mike Wittman 2015/03/17 19:07:37 Done.
25 PendingProfiles();
26 ~PendingProfiles();
27
28 static PendingProfiles* GetInstance();
29
30 // Appends |profiles|. This function is thread safe.
31 void PutProfiles(const std::vector<StackSamplingProfiler::Profile>& profiles);
32 // Gets the pending profiles into *|profiles|. This function is thread safe.
33 void GetProfiles(std::vector<StackSamplingProfiler::Profile>* profiles);
34
35 private:
36 Lock profiles_lock_;
37 std::vector<StackSamplingProfiler::Profile> profiles_;
38
39 DISALLOW_COPY_AND_ASSIGN(PendingProfiles);
40 };
41
42 PendingProfiles::PendingProfiles() {}
43
44 PendingProfiles::~PendingProfiles() {}
45
46 // static
47 PendingProfiles* PendingProfiles::GetInstance() {
48 return Singleton<PendingProfiles>::get();
49 }
50
51 void PendingProfiles::PutProfiles(
52 const std::vector<StackSamplingProfiler::Profile>& profiles) {
53 AutoLock scoped_lock(profiles_lock_);
54 profiles_.insert(profiles_.end(), profiles.begin(), profiles.end());
55 }
56
57 void PendingProfiles::GetProfiles(
58 std::vector<StackSamplingProfiler::Profile>* profiles) {
59 profiles->clear();
60
61 AutoLock scoped_lock(profiles_lock_);
62 profiles_.swap(*profiles);
63 }
64 } // namespace
65
66 StackSamplingProfiler::Profile::Profile() : preserve_sample_ordering(false) {}
67
68 StackSamplingProfiler::Profile::~Profile() {}
69
70 class StackSamplingProfiler::SamplingThread : public PlatformThread::Delegate {
71 public:
72 // Samples stacks using |native_sampler|. When complete, invokes
73 // |profiles_callback| with the collected profiles. |profiles_callback| must
74 // be thread-safe and may consume the contents of the vector.
75 SamplingThread(
76 scoped_ptr<NativeStackSampler> native_sampler,
77 const SamplingParams& params,
78 Callback<void(const std::vector<Profile>&)> completed_callback);
79 ~SamplingThread() override;
80
81 // Implementation of PlatformThread::Delegate:
82 void ThreadMain() override;
83
84 void Stop();
85
86 private:
87 // Collects a profile from a single burst. Returns true if the profile was
88 // collected, or false if collection was stopped before it completed.
89 bool CollectProfile(Profile* profile, TimeDelta* elapsed_time);
90 // Collects profiles from all bursts, or until the sampling is stopped. If
91 // stopped before complete, |profiles| will contains only full bursts.
92 void CollectProfiles(std::vector<Profile>* profiles);
93
94 scoped_ptr<NativeStackSampler> native_sampler_;
95
96 const SamplingParams params_;
97
98 WaitableEvent stop_event_;
99
100 Callback<void(const std::vector<Profile>&)> completed_callback_;
101
102 DISALLOW_COPY_AND_ASSIGN(SamplingThread);
103 };
104
105 StackSamplingProfiler::SamplingThread::SamplingThread(
106 scoped_ptr<NativeStackSampler> native_sampler,
107 const SamplingParams& params,
108 Callback<void(const std::vector<Profile>&)> completed_callback)
109 : native_sampler_(native_sampler.Pass()),
110 params_(params),
111 stop_event_(false, false),
112 completed_callback_(completed_callback) {
113 }
114
115 StackSamplingProfiler::SamplingThread::~SamplingThread() {}
116
117 void StackSamplingProfiler::SamplingThread::ThreadMain() {
118 PlatformThread::SetName("Chrome_SamplingProfilerThread");
119
120 std::vector<Profile> profiles;
121 CollectProfiles(&profiles);
122 completed_callback_.Run(profiles);
123 }
124
125 bool StackSamplingProfiler::SamplingThread::CollectProfile(
126 Profile* profile, TimeDelta* elapsed_time) {
Alexei Svitkine (slow) 2015/03/17 13:10:00 1 param per line if first one wraps.
Mike Wittman 2015/03/17 19:07:37 Done.
127 ElapsedTimer profile_timer;
128 Profile current_profile;
129 native_sampler_->ProfileRecordingStarting(&current_profile);
130 current_profile.sampling_period = params_.sampling_interval;
131 bool stopped_early = false;
132 for (int j = 0; j < params_.samples_per_burst; ++j) {
Alexei Svitkine (slow) 2015/03/17 13:10:00 Why j?
Mike Wittman 2015/03/17 19:07:37 This is an artifact from when this code was part o
133 ElapsedTimer sample_timer;
134 current_profile.samples.push_back(Sample());
135 native_sampler_->RecordStackSample(&current_profile.samples.back());
136 TimeDelta elapsed_sample_time = sample_timer.Elapsed();
137 if (j != params_.samples_per_burst - 1) {
138 if (stop_event_.TimedWait(
139 std::max(params_.sampling_interval - elapsed_sample_time,
140 TimeDelta()))) {
141 stopped_early = true;
142 break;
143 }
144 }
145 }
146
147 *elapsed_time = profile_timer.Elapsed();
148 current_profile.profile_duration = *elapsed_time;
149 native_sampler_->ProfileRecordingStopped();
150
151 if (!stopped_early)
152 *profile = current_profile;
153
154 return !stopped_early;
155 }
156
157 void StackSamplingProfiler::SamplingThread::CollectProfiles(
158 std::vector<Profile>* profiles) {
159 if (stop_event_.TimedWait(params_.initial_delay))
160 return;
161
162 for (int i = 0; i < params_.bursts; ++i) {
163 Profile profile;
164 TimeDelta elapsed_profile_time;
165 if (CollectProfile(&profile, &elapsed_profile_time))
166 profiles->push_back(profile);
167 else
168 return;
169
170 if (stop_event_.TimedWait(
171 std::max(params_.burst_interval - elapsed_profile_time,
172 TimeDelta())))
173 return;
174 }
175 }
176
177 void StackSamplingProfiler::SamplingThread::Stop() {
178 stop_event_.Signal();
179 }
180
181 void StackSamplingProfiler::SamplingThreadDeleter::operator()(
182 SamplingThread* thread) const {
183 delete thread;
184 }
185
186 StackSamplingProfiler::NativeStackSampler::NativeStackSampler() {}
187
188 StackSamplingProfiler::NativeStackSampler::~NativeStackSampler() {}
189
190 StackSamplingProfiler::SamplingParams::SamplingParams()
191 : initial_delay(TimeDelta::FromMilliseconds(0)), bursts(1),
192 burst_interval(TimeDelta::FromMilliseconds(10000)),
193 samples_per_burst(300),
194 sampling_interval(TimeDelta::FromMilliseconds(100)),
195 preserve_sample_ordering(false) {
196 }
197
198 StackSamplingProfiler::StackSamplingProfiler(PlatformThreadId thread_id,
199 const SamplingParams& params)
200 : thread_id_(thread_id), params_(params) {}
201
202 StackSamplingProfiler::~StackSamplingProfiler() {}
203
204 void StackSamplingProfiler::Start() {
205 native_sampler_ = NativeStackSampler::Create(thread_id_);
206 if (!native_sampler_)
207 return;
208
209 sampling_thread_.reset(
210 new SamplingThread(
211 native_sampler_.Pass(), params_,
212 (custom_completed_callback_.is_null() ?
213 Bind(&PendingProfiles::PutProfiles,
214 Unretained(PendingProfiles::GetInstance())) :
215 custom_completed_callback_)));
216 if (!PlatformThread::CreateNonJoinable(0, sampling_thread_.get()))
217 LOG(ERROR) << "failed to create thread";
218 }
219
220 void StackSamplingProfiler::Stop() {
221 if (sampling_thread_)
222 sampling_thread_->Stop();
223 }
224
225 // static
226 void StackSamplingProfiler::GetPendingProfiles(std::vector<Profile>* profiles) {
227 PendingProfiles::GetInstance()->GetProfiles(profiles);
228 }
229
230 void StackSamplingProfiler::SetCustomCompletedCallback(
231 Callback<void(const std::vector<Profile>&)> callback) {
232 custom_completed_callback_ = callback;
233 }
234
235 bool operator==(const StackSamplingProfiler::Frame &a,
236 const StackSamplingProfiler::Frame &b) {
237 return a.instruction_pointer == b.instruction_pointer &&
238 a.module_index == b.module_index;
239 }
240
241 bool operator<(const StackSamplingProfiler::Frame &a,
242 const StackSamplingProfiler::Frame &b) {
243 return (a.module_index < b.module_index) ||
244 (a.module_index == b.module_index &&
245 a.instruction_pointer < b.instruction_pointer);
246 }
247
248 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698