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

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

Issue 981143006: Metrics provider for statistical stack profiler (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@lkcr
Patch Set: fix clang compilation 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 {
21 // Time to delay before first samples are taken.
22 const int64 kInitialDelayInMicroseconds = 0;
23 // Number of sampling bursts to perform.
24 const int kNumberOfBursts = 1;
25 // Interval between sampling bursts. This is the desired duration from the start
26 // of one burst to the start of the next burst.
27 const int64 kBurstIntervalInMicroseconds = 10000000; // 10 sec
28 // Number of samples to record per burst.
29 const int kNumberOfSamples = 300;
30 // Interval between samples during a sampling burst. This is the desired
31 // duration from the start of one burst to the start of the next burst.
32 const int64 kSamplingIntervalInMicroseconds = 100000; // 100 ms
33
34 // Thread-safe singleton class that stores collected profiles waiting to be
35 // processed.
36 class PendingProfiles {
37 public:
38 PendingProfiles();
39 ~PendingProfiles();
40
41 static PendingProfiles* GetInstance();
42
43 // Appends |profiles|. This function is thread safe.
44 void PutProfiles(const std::vector<StackSamplingProfiler::Profile>& profiles);
45 // Gets the pending profiles into *|profiles|. This function is thread safe.
46 void GetProfiles(std::vector<StackSamplingProfiler::Profile>* profiles);
47
48 private:
49 base::Lock profiles_lock_;
50 std::vector<StackSamplingProfiler::Profile> profiles_;
51
52 DISALLOW_COPY_AND_ASSIGN(PendingProfiles);
53 };
54
55 PendingProfiles::PendingProfiles() {}
56
57 PendingProfiles::~PendingProfiles() {}
58
59 // static
60 PendingProfiles* PendingProfiles::GetInstance() {
61 return Singleton<PendingProfiles>::get();
62 }
63
64 void PendingProfiles::PutProfiles(
65 const std::vector<StackSamplingProfiler::Profile>& profiles) {
66 base::AutoLock scoped_lock(profiles_lock_);
67 profiles_.insert(profiles_.end(), profiles.begin(), profiles.end());
68 }
69
70 void PendingProfiles::GetProfiles(
71 std::vector<StackSamplingProfiler::Profile>* profiles) {
72 profiles->clear();
73
74 base::AutoLock scoped_lock(profiles_lock_);
75 profiles_.swap(*profiles);
76 }
77 } // namespace
78
79 StackSamplingProfiler::Profile::Profile() {}
80
81 StackSamplingProfiler::Profile::~Profile() {}
82
83 class StackSamplingProfiler::SamplingThread : public PlatformThread::Delegate {
84 public:
85 // Samples stacks using |native_sampler|. When complete, invokes
86 // |profiles_callback| with the collected profiles. |profiles_callback| must
87 // be thread-safe and may consume the contents of the vector.
88 SamplingThread(
89 scoped_ptr<NativeStackSampler> native_sampler,
90 base::Callback<void(const std::vector<Profile>&)> profiles_callback);
91 ~SamplingThread() override;
92
93 // Implementation of PlatformThread::Delegate:
94 void ThreadMain() override;
95
96 void Stop();
97
98 private:
99 // Collects a profile from a single burst. Returns true if the profile was
100 // collected, or false if collection was stopped before it completed.
101 bool CollectProfile(Profile* profile, TimeDelta* elapsed_time);
102 // Collects profiles from all bursts, or until the sampling is stopped. If
103 // stopped before complete, |profiles| will contains only full bursts.
104 void CollectProfiles(std::vector<Profile>* profiles);
105
106 scoped_ptr<NativeStackSampler> native_sampler_;
107
108 base::WaitableEvent stop_event_;
109
110 base::Callback<void(const std::vector<Profile>&)> profiles_callback_;
111
112 DISALLOW_COPY_AND_ASSIGN(SamplingThread);
113 };
114
115 StackSamplingProfiler::SamplingThread::SamplingThread(
116 scoped_ptr<NativeStackSampler> native_sampler,
117 base::Callback<void(const std::vector<Profile>&)> profiles_callback)
118 : native_sampler_(native_sampler.Pass()),
119 stop_event_(false, false),
120 profiles_callback_(profiles_callback) {
121 }
122
123 StackSamplingProfiler::SamplingThread::~SamplingThread() {}
124
125 void StackSamplingProfiler::SamplingThread::ThreadMain() {
126 PlatformThread::SetName("Chrome_SamplingProfilerThread");
127
128 std::vector<Profile> profiles;
129 CollectProfiles(&profiles);
130 profiles_callback_.Run(profiles);
131 }
132
133 bool StackSamplingProfiler::SamplingThread::CollectProfile(
134 Profile* profile, TimeDelta* elapsed_time) {
135 base::ElapsedTimer profile_timer;
136 Profile current_profile;
137 native_sampler_->ProfileRecordingStarting(&current_profile);
138 const TimeDelta sampling_interval =
139 TimeDelta::FromMicroseconds(kSamplingIntervalInMicroseconds);
140 current_profile.sampling_period = sampling_interval;
141 bool stopped_early = false;
142 for (int j = 0; j < kNumberOfSamples; ++j) {
143 base::ElapsedTimer sample_timer;
144 current_profile.samples.push_back(Sample());
145 native_sampler_->RecordStackSample(&current_profile.samples.back());
146 base::TimeDelta elapsed_sample_time = sample_timer.Elapsed();
147 if (j != kNumberOfSamples - 1) {
148 if (stop_event_.TimedWait(
149 std::max(sampling_interval - elapsed_sample_time, TimeDelta()))) {
150 stopped_early = true;
151 break;
152 }
153 }
154 }
155
156 *elapsed_time = profile_timer.Elapsed();
157 current_profile.profile_duration = *elapsed_time;
158 native_sampler_->ProfileRecordingStopped();
159
160 if (!stopped_early)
161 *profile = current_profile;
162
163 return !stopped_early;
164 }
165
166 void StackSamplingProfiler::SamplingThread::CollectProfiles(
167 std::vector<Profile>* profiles) {
168 if (stop_event_.TimedWait(TimeDelta::FromMicroseconds(
169 kInitialDelayInMicroseconds)))
170 return;
171
172 const TimeDelta burst_interval =
173 TimeDelta::FromMicroseconds(kBurstIntervalInMicroseconds);
174 for (int i = 0; i < kNumberOfBursts; ++i) {
175 Profile profile;
176 base::TimeDelta elapsed_profile_time;
177 if (CollectProfile(&profile, &elapsed_profile_time))
178 profiles->push_back(profile);
179 else
180 return;
181
182 if (stop_event_.TimedWait(
183 std::max(burst_interval - elapsed_profile_time, TimeDelta())))
184 return;
185 }
186 }
187
188 void StackSamplingProfiler::SamplingThread::Stop() {
189 stop_event_.Signal();
190 }
191
192 void StackSamplingProfiler::SamplingThreadDeleter::operator()(
193 SamplingThread* thread) const {
194 delete thread;
195 }
196
197 StackSamplingProfiler::NativeStackSampler::NativeStackSampler() {}
198
199 StackSamplingProfiler::NativeStackSampler::~NativeStackSampler() {}
200
201 StackSamplingProfiler::StackSamplingProfiler(PlatformThreadId thread_id)
202 : thread_id_(thread_id) {}
203
204 StackSamplingProfiler::~StackSamplingProfiler() {}
205
206 void StackSamplingProfiler::Start() {
207 native_sampler_ = NativeStackSampler::Create(thread_id_);
208 if (!native_sampler_)
209 return;
210
211 sampling_thread_.reset(
212 new SamplingThread(
213 native_sampler_.Pass(),
214 base::Bind(&PendingProfiles::PutProfiles,
215 base::Unretained(PendingProfiles::GetInstance()))));
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 bool operator==(const StackSamplingProfiler::Frame &a,
231 const StackSamplingProfiler::Frame &b) {
232 return a.ip_offset == b.ip_offset && a.module_index == b.module_index;
233 }
234
235 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698