This repository has been archived by the owner on Jan 18, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathstack_sampling_profiler.h
315 lines (256 loc) · 12.2 KB
/
stack_sampling_profiler.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_PROFILER_STACK_SAMPLING_PROFILER_H_
#define BASE_PROFILER_STACK_SAMPLING_PROFILER_H_
#include <stddef.h>
#include <memory>
#include <string>
#include <vector>
#include "base/atomicops.h"
#include "base/base_export.h"
#include "base/callback.h"
#include "base/files/file_path.h"
#include "base/macros.h"
#include "base/strings/string16.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/platform_thread.h"
#include "base/time/time.h"
namespace base {
class NativeStackSampler;
class NativeStackSamplerTestDelegate;
// StackSamplingProfiler periodically stops a thread to sample its stack, for
// the purpose of collecting information about which code paths are
// executing. This information is used in aggregate by UMA to identify hot
// and/or janky code paths.
//
// Sample StackSamplingProfiler usage:
//
// // Create and customize params as desired.
// base::StackStackSamplingProfiler::SamplingParams params;
// // Any thread's ID may be passed as the target.
// base::StackSamplingProfiler profiler(base::PlatformThread::CurrentId()),
// params);
//
// // Or, to process the profiles within Chrome rather than via UMA, use a
// // custom completed callback:
// base::StackStackSamplingProfiler::CompletedCallback
// thread_safe_callback = ...;
// base::StackSamplingProfiler profiler(base::PlatformThread::CurrentId()),
// params, thread_safe_callback);
//
// profiler.Start();
// // ... work being done on the target thread here ...
// profiler.Stop(); // optional, stops collection before complete per params
//
// The default SamplingParams causes stacks to be recorded in a single burst at
// a 10Hz interval for a total of 30 seconds. All of these parameters may be
// altered as desired.
//
// When all call stack profiles are complete, or the profiler is stopped, the
// completed callback is called from a thread created by the profiler with the
// collected profiles.
//
// The results of the profiling are passed to the completed callback and consist
// of a vector of CallStackProfiles. Each CallStackProfile corresponds to a
// burst as specified in SamplingParams and contains a set of Samples and
// Modules. One Sample corresponds to a single recorded stack, and the Modules
// record those modules associated with the recorded stack frames.
class BASE_EXPORT StackSamplingProfiler {
public:
// Module represents the module (DLL or exe) corresponding to a stack frame.
struct BASE_EXPORT Module {
Module();
Module(uintptr_t base_address,
const std::string& id,
const FilePath& filename);
~Module();
// Points to the base address of the module.
uintptr_t base_address;
// An opaque binary string that uniquely identifies a particular program
// version with high probability. This is parsed from headers of the loaded
// module.
// For binaries generated by GNU tools:
// Contents of the .note.gnu.build-id field.
// On Windows:
// GUID + AGE in the debug image headers of a module.
std::string id;
// The filename of the module.
FilePath filename;
};
// Frame represents an individual sampled stack frame with module information.
struct BASE_EXPORT Frame {
// Identifies an unknown module.
static const size_t kUnknownModuleIndex = static_cast<size_t>(-1);
Frame(uintptr_t instruction_pointer, size_t module_index);
~Frame();
// Default constructor to satisfy IPC macros. Do not use explicitly.
Frame();
// The sampled instruction pointer within the function.
uintptr_t instruction_pointer;
// Index of the module in CallStackProfile::modules. We don't represent
// module state directly here to save space.
size_t module_index;
};
// Sample represents a set of stack frames with some extra information.
struct BASE_EXPORT Sample {
Sample();
Sample(const Sample& sample);
~Sample();
// These constructors are used only during testing.
Sample(const Frame& frame);
Sample(const std::vector<Frame>& frames);
// The entire stack frame when the sample is taken.
std::vector<Frame> frames;
// A bit-field indicating which process milestones have passed. This can be
// used to tell where in the process lifetime the samples are taken. Just
// as a "lifetime" can only move forward, these bits mark the milestones of
// the processes life as they occur. Bits can be set but never reset. The
// actual definition of the individual bits is left to the user of this
// module.
uint32_t process_milestones = 0;
};
// CallStackProfile represents a set of samples.
struct BASE_EXPORT CallStackProfile {
CallStackProfile();
CallStackProfile(CallStackProfile&& other);
~CallStackProfile();
CallStackProfile& operator=(CallStackProfile&& other);
CallStackProfile CopyForTesting() const;
std::vector<Module> modules;
std::vector<Sample> samples;
// Duration of this profile.
TimeDelta profile_duration;
// Time between samples.
TimeDelta sampling_period;
private:
// Copying is possible but expensive so disallow it except for internal use
// (i.e. CopyForTesting); use std::move instead.
CallStackProfile(const CallStackProfile& other);
DISALLOW_ASSIGN(CallStackProfile);
};
using CallStackProfiles = std::vector<CallStackProfile>;
// Represents parameters that configure the sampling.
struct BASE_EXPORT SamplingParams {
// Time to delay before first samples are taken.
TimeDelta initial_delay = TimeDelta::FromMilliseconds(0);
// Number of sampling bursts to perform.
int bursts = 1;
// Interval between sampling bursts. This is the desired duration from the
// start of one burst to the start of the next burst.
TimeDelta burst_interval = TimeDelta::FromSeconds(10);
// Number of samples to record per burst.
int samples_per_burst = 300;
// Interval between samples during a sampling burst. This is the desired
// duration from the start of one sample to the start of the next sample.
TimeDelta sampling_interval = TimeDelta::FromMilliseconds(100);
};
// The callback type used to collect completed profiles. The passed |profiles|
// are move-only.
//
// IMPORTANT NOTE: the callback is invoked on a thread the profiler
// constructs, rather than on the thread used to construct the profiler and
// set the callback, and thus the callback must be callable on any thread. For
// threads with message loops that create StackSamplingProfilers, posting a
// task to the message loop with a copy of the profiles is the recommended
// thread-safe callback implementation.
using CompletedCallback = Callback<void(CallStackProfiles)>;
// Creates a profiler that sends completed profiles to |callback|. The second
// constructor is for test purposes.
StackSamplingProfiler(PlatformThreadId thread_id,
const SamplingParams& params,
const CompletedCallback& callback);
StackSamplingProfiler(PlatformThreadId thread_id,
const SamplingParams& params,
const CompletedCallback& callback,
NativeStackSamplerTestDelegate* test_delegate);
// Stops any profiling currently taking place before destroying the profiler.
~StackSamplingProfiler();
// The fire-and-forget interface: starts a profiler and allows it to complete
// without the caller needing to manage the profiler lifetime. May be invoked
// from any thread, but requires that the calling thread has a message loop.
static void StartAndRunAsync(PlatformThreadId thread_id,
const SamplingParams& params,
const CompletedCallback& callback);
// Initializes the profiler and starts sampling.
void Start();
// Stops the profiler and any ongoing sampling. Calling this function is
// optional; if not invoked profiling terminates when all the profiling bursts
// specified in the SamplingParams are completed or the profiler is destroyed,
// whichever occurs first.
void Stop();
// Set the current system state that is recorded with each captured stack
// frame. This is thread-safe so can be called from anywhere. The parameter
// value should be from an enumeration of the appropriate type with values
// ranging from 0 to 31, inclusive. This sets bits within Sample field of
// |process_milestones|. The actual meanings of these bits are defined
// (globally) by the caller(s).
static void SetProcessMilestone(int milestone);
static void ResetAnnotationsForTesting();
private:
// SamplingThread is a separate thread used to suspend and sample stacks from
// the target thread.
class SamplingThread : public PlatformThread::Delegate {
public:
// Samples stacks using |native_sampler|. When complete, invokes
// |completed_callback| with the collected call stack profiles.
// |completed_callback| must be callable on any thread.
SamplingThread(std::unique_ptr<NativeStackSampler> native_sampler,
const SamplingParams& params,
const CompletedCallback& completed_callback);
~SamplingThread() override;
// PlatformThread::Delegate:
void ThreadMain() override;
void Stop();
private:
// Collects |profile| from a single burst. If the profiler was stopped
// during collection, sets |was_stopped| and provides the set of samples
// collected up to that point.
void CollectProfile(CallStackProfile* profile, TimeDelta* elapsed_time,
bool* was_stopped);
// Collects call stack profiles from all bursts, or until the sampling is
// stopped. If stopped before complete, the last profile in
// |call_stack_profiles| may contain a partial burst.
void CollectProfiles(CallStackProfiles* profiles);
std::unique_ptr<NativeStackSampler> native_sampler_;
const SamplingParams params_;
// If Stop() is called, it signals this event to force the sampling to
// terminate before all the samples specified in |params_| are collected.
WaitableEvent stop_event_;
const CompletedCallback completed_callback_;
DISALLOW_COPY_AND_ASSIGN(SamplingThread);
};
// Adds annotations to a Sample.
static void RecordAnnotations(Sample* sample);
// This global variables holds the current system state and is recorded with
// every captured sample, done on a separate thread which is why updates to
// this must be atomic. A PostTask to move the the updates to that thread
// would skew the timing and a lock could result in deadlock if the thread
// making a change was also being profiled and got stopped.
static subtle::Atomic32 process_milestones_;
// The thread whose stack will be sampled.
PlatformThreadId thread_id_;
const SamplingParams params_;
std::unique_ptr<SamplingThread> sampling_thread_;
PlatformThreadHandle sampling_thread_handle_;
const CompletedCallback completed_callback_;
// Stored until it can be passed to the NativeStackSampler created in Start().
NativeStackSamplerTestDelegate* const test_delegate_;
DISALLOW_COPY_AND_ASSIGN(StackSamplingProfiler);
};
// These operators permit types to be compared and used in a map of Samples, as
// done in tests and by the metrics provider code.
BASE_EXPORT bool operator==(const StackSamplingProfiler::Module& a,
const StackSamplingProfiler::Module& b);
BASE_EXPORT bool operator==(const StackSamplingProfiler::Sample& a,
const StackSamplingProfiler::Sample& b);
BASE_EXPORT bool operator!=(const StackSamplingProfiler::Sample& a,
const StackSamplingProfiler::Sample& b);
BASE_EXPORT bool operator<(const StackSamplingProfiler::Sample& a,
const StackSamplingProfiler::Sample& b);
BASE_EXPORT bool operator==(const StackSamplingProfiler::Frame& a,
const StackSamplingProfiler::Frame& b);
BASE_EXPORT bool operator<(const StackSamplingProfiler::Frame& a,
const StackSamplingProfiler::Frame& b);
} // namespace base
#endif // BASE_PROFILER_STACK_SAMPLING_PROFILER_H_