1*635a8641SAndroid Build Coastguard Worker // Copyright 2015 The Chromium Authors. All rights reserved.
2*635a8641SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*635a8641SAndroid Build Coastguard Worker // found in the LICENSE file.
4*635a8641SAndroid Build Coastguard Worker
5*635a8641SAndroid Build Coastguard Worker #include "base/profiler/stack_sampling_profiler.h"
6*635a8641SAndroid Build Coastguard Worker
7*635a8641SAndroid Build Coastguard Worker #include <algorithm>
8*635a8641SAndroid Build Coastguard Worker #include <utility>
9*635a8641SAndroid Build Coastguard Worker
10*635a8641SAndroid Build Coastguard Worker #include "base/atomic_sequence_num.h"
11*635a8641SAndroid Build Coastguard Worker #include "base/atomicops.h"
12*635a8641SAndroid Build Coastguard Worker #include "base/bind.h"
13*635a8641SAndroid Build Coastguard Worker #include "base/bind_helpers.h"
14*635a8641SAndroid Build Coastguard Worker #include "base/callback.h"
15*635a8641SAndroid Build Coastguard Worker #include "base/location.h"
16*635a8641SAndroid Build Coastguard Worker #include "base/macros.h"
17*635a8641SAndroid Build Coastguard Worker #include "base/memory/ptr_util.h"
18*635a8641SAndroid Build Coastguard Worker #include "base/memory/singleton.h"
19*635a8641SAndroid Build Coastguard Worker #include "base/profiler/native_stack_sampler.h"
20*635a8641SAndroid Build Coastguard Worker #include "base/synchronization/lock.h"
21*635a8641SAndroid Build Coastguard Worker #include "base/threading/thread.h"
22*635a8641SAndroid Build Coastguard Worker #include "base/threading/thread_restrictions.h"
23*635a8641SAndroid Build Coastguard Worker #include "base/threading/thread_task_runner_handle.h"
24*635a8641SAndroid Build Coastguard Worker #include "base/timer/elapsed_timer.h"
25*635a8641SAndroid Build Coastguard Worker
26*635a8641SAndroid Build Coastguard Worker namespace base {
27*635a8641SAndroid Build Coastguard Worker
28*635a8641SAndroid Build Coastguard Worker const size_t kUnknownModuleIndex = static_cast<size_t>(-1);
29*635a8641SAndroid Build Coastguard Worker
30*635a8641SAndroid Build Coastguard Worker namespace {
31*635a8641SAndroid Build Coastguard Worker
32*635a8641SAndroid Build Coastguard Worker // This value is used to initialize the WaitableEvent object. This MUST BE set
33*635a8641SAndroid Build Coastguard Worker // to MANUAL for correct operation of the IsSignaled() call in Start(). See the
34*635a8641SAndroid Build Coastguard Worker // comment there for why.
35*635a8641SAndroid Build Coastguard Worker constexpr WaitableEvent::ResetPolicy kResetPolicy =
36*635a8641SAndroid Build Coastguard Worker WaitableEvent::ResetPolicy::MANUAL;
37*635a8641SAndroid Build Coastguard Worker
38*635a8641SAndroid Build Coastguard Worker // This value is used when there is no collection in progress and thus no ID
39*635a8641SAndroid Build Coastguard Worker // for referencing the active collection to the SamplingThread.
40*635a8641SAndroid Build Coastguard Worker const int kNullProfilerId = -1;
41*635a8641SAndroid Build Coastguard Worker
42*635a8641SAndroid Build Coastguard Worker } // namespace
43*635a8641SAndroid Build Coastguard Worker
44*635a8641SAndroid Build Coastguard Worker // StackSamplingProfiler::Module ----------------------------------------------
45*635a8641SAndroid Build Coastguard Worker
Module()46*635a8641SAndroid Build Coastguard Worker StackSamplingProfiler::Module::Module() : base_address(0u) {}
47*635a8641SAndroid Build Coastguard Worker
Module(uintptr_t base_address,const std::string & id,const FilePath & filename)48*635a8641SAndroid Build Coastguard Worker StackSamplingProfiler::Module::Module(uintptr_t base_address,
49*635a8641SAndroid Build Coastguard Worker const std::string& id,
50*635a8641SAndroid Build Coastguard Worker const FilePath& filename)
51*635a8641SAndroid Build Coastguard Worker : base_address(base_address), id(id), filename(filename) {}
52*635a8641SAndroid Build Coastguard Worker
53*635a8641SAndroid Build Coastguard Worker StackSamplingProfiler::Module::~Module() = default;
54*635a8641SAndroid Build Coastguard Worker
55*635a8641SAndroid Build Coastguard Worker // StackSamplingProfiler::InternalModule --------------------------------------
56*635a8641SAndroid Build Coastguard Worker
InternalModule()57*635a8641SAndroid Build Coastguard Worker StackSamplingProfiler::InternalModule::InternalModule() : is_valid(false) {}
58*635a8641SAndroid Build Coastguard Worker
InternalModule(uintptr_t base_address,const std::string & id,const FilePath & filename)59*635a8641SAndroid Build Coastguard Worker StackSamplingProfiler::InternalModule::InternalModule(uintptr_t base_address,
60*635a8641SAndroid Build Coastguard Worker const std::string& id,
61*635a8641SAndroid Build Coastguard Worker const FilePath& filename)
62*635a8641SAndroid Build Coastguard Worker : base_address(base_address), id(id), filename(filename), is_valid(true) {}
63*635a8641SAndroid Build Coastguard Worker
64*635a8641SAndroid Build Coastguard Worker StackSamplingProfiler::InternalModule::~InternalModule() = default;
65*635a8641SAndroid Build Coastguard Worker
66*635a8641SAndroid Build Coastguard Worker // StackSamplingProfiler::Frame -----------------------------------------------
67*635a8641SAndroid Build Coastguard Worker
Frame(uintptr_t instruction_pointer,size_t module_index)68*635a8641SAndroid Build Coastguard Worker StackSamplingProfiler::Frame::Frame(uintptr_t instruction_pointer,
69*635a8641SAndroid Build Coastguard Worker size_t module_index)
70*635a8641SAndroid Build Coastguard Worker : instruction_pointer(instruction_pointer), module_index(module_index) {}
71*635a8641SAndroid Build Coastguard Worker
72*635a8641SAndroid Build Coastguard Worker StackSamplingProfiler::Frame::~Frame() = default;
73*635a8641SAndroid Build Coastguard Worker
Frame()74*635a8641SAndroid Build Coastguard Worker StackSamplingProfiler::Frame::Frame()
75*635a8641SAndroid Build Coastguard Worker : instruction_pointer(0), module_index(kUnknownModuleIndex) {}
76*635a8641SAndroid Build Coastguard Worker
77*635a8641SAndroid Build Coastguard Worker // StackSamplingProfiler::InternalFrame -------------------------------------
78*635a8641SAndroid Build Coastguard Worker
InternalFrame(uintptr_t instruction_pointer,InternalModule internal_module)79*635a8641SAndroid Build Coastguard Worker StackSamplingProfiler::InternalFrame::InternalFrame(
80*635a8641SAndroid Build Coastguard Worker uintptr_t instruction_pointer,
81*635a8641SAndroid Build Coastguard Worker InternalModule internal_module)
82*635a8641SAndroid Build Coastguard Worker : instruction_pointer(instruction_pointer),
83*635a8641SAndroid Build Coastguard Worker internal_module(std::move(internal_module)) {}
84*635a8641SAndroid Build Coastguard Worker
85*635a8641SAndroid Build Coastguard Worker StackSamplingProfiler::InternalFrame::~InternalFrame() = default;
86*635a8641SAndroid Build Coastguard Worker
87*635a8641SAndroid Build Coastguard Worker // StackSamplingProfiler::Sample ----------------------------------------------
88*635a8641SAndroid Build Coastguard Worker
89*635a8641SAndroid Build Coastguard Worker StackSamplingProfiler::Sample::Sample() = default;
90*635a8641SAndroid Build Coastguard Worker
91*635a8641SAndroid Build Coastguard Worker StackSamplingProfiler::Sample::Sample(const Sample& sample) = default;
92*635a8641SAndroid Build Coastguard Worker
93*635a8641SAndroid Build Coastguard Worker StackSamplingProfiler::Sample::~Sample() = default;
94*635a8641SAndroid Build Coastguard Worker
Sample(const Frame & frame)95*635a8641SAndroid Build Coastguard Worker StackSamplingProfiler::Sample::Sample(const Frame& frame) {
96*635a8641SAndroid Build Coastguard Worker frames.push_back(std::move(frame));
97*635a8641SAndroid Build Coastguard Worker }
98*635a8641SAndroid Build Coastguard Worker
Sample(const std::vector<Frame> & frames)99*635a8641SAndroid Build Coastguard Worker StackSamplingProfiler::Sample::Sample(const std::vector<Frame>& frames)
100*635a8641SAndroid Build Coastguard Worker : frames(frames) {}
101*635a8641SAndroid Build Coastguard Worker
102*635a8641SAndroid Build Coastguard Worker // StackSamplingProfiler::CallStackProfile ------------------------------------
103*635a8641SAndroid Build Coastguard Worker
104*635a8641SAndroid Build Coastguard Worker StackSamplingProfiler::CallStackProfile::CallStackProfile() = default;
105*635a8641SAndroid Build Coastguard Worker
106*635a8641SAndroid Build Coastguard Worker StackSamplingProfiler::CallStackProfile::CallStackProfile(
107*635a8641SAndroid Build Coastguard Worker CallStackProfile&& other) = default;
108*635a8641SAndroid Build Coastguard Worker
109*635a8641SAndroid Build Coastguard Worker StackSamplingProfiler::CallStackProfile::~CallStackProfile() = default;
110*635a8641SAndroid Build Coastguard Worker
111*635a8641SAndroid Build Coastguard Worker StackSamplingProfiler::CallStackProfile&
112*635a8641SAndroid Build Coastguard Worker StackSamplingProfiler::CallStackProfile::operator=(CallStackProfile&& other) =
113*635a8641SAndroid Build Coastguard Worker default;
114*635a8641SAndroid Build Coastguard Worker
115*635a8641SAndroid Build Coastguard Worker StackSamplingProfiler::CallStackProfile
CopyForTesting() const116*635a8641SAndroid Build Coastguard Worker StackSamplingProfiler::CallStackProfile::CopyForTesting() const {
117*635a8641SAndroid Build Coastguard Worker return CallStackProfile(*this);
118*635a8641SAndroid Build Coastguard Worker }
119*635a8641SAndroid Build Coastguard Worker
120*635a8641SAndroid Build Coastguard Worker StackSamplingProfiler::CallStackProfile::CallStackProfile(
121*635a8641SAndroid Build Coastguard Worker const CallStackProfile& other) = default;
122*635a8641SAndroid Build Coastguard Worker
123*635a8641SAndroid Build Coastguard Worker // StackSamplingProfiler::SamplingThread --------------------------------------
124*635a8641SAndroid Build Coastguard Worker
125*635a8641SAndroid Build Coastguard Worker class StackSamplingProfiler::SamplingThread : public Thread {
126*635a8641SAndroid Build Coastguard Worker public:
127*635a8641SAndroid Build Coastguard Worker class TestAPI {
128*635a8641SAndroid Build Coastguard Worker public:
129*635a8641SAndroid Build Coastguard Worker // Reset the existing sampler. This will unfortunately create the object
130*635a8641SAndroid Build Coastguard Worker // unnecessarily if it doesn't already exist but there's no way around that.
131*635a8641SAndroid Build Coastguard Worker static void Reset();
132*635a8641SAndroid Build Coastguard Worker
133*635a8641SAndroid Build Coastguard Worker // Disables inherent idle-shutdown behavior.
134*635a8641SAndroid Build Coastguard Worker static void DisableIdleShutdown();
135*635a8641SAndroid Build Coastguard Worker
136*635a8641SAndroid Build Coastguard Worker // Begins an idle shutdown as if the idle-timer had expired and wait for
137*635a8641SAndroid Build Coastguard Worker // it to execute. Since the timer would have only been started at a time
138*635a8641SAndroid Build Coastguard Worker // when the sampling thread actually was idle, this must be called only
139*635a8641SAndroid Build Coastguard Worker // when it is known that there are no active sampling threads. If
140*635a8641SAndroid Build Coastguard Worker // |simulate_intervening_add| is true then, when executed, the shutdown
141*635a8641SAndroid Build Coastguard Worker // task will believe that a new collection has been added since it was
142*635a8641SAndroid Build Coastguard Worker // posted.
143*635a8641SAndroid Build Coastguard Worker static void ShutdownAssumingIdle(bool simulate_intervening_add);
144*635a8641SAndroid Build Coastguard Worker
145*635a8641SAndroid Build Coastguard Worker private:
146*635a8641SAndroid Build Coastguard Worker // Calls the sampling threads ShutdownTask and then signals an event.
147*635a8641SAndroid Build Coastguard Worker static void ShutdownTaskAndSignalEvent(SamplingThread* sampler,
148*635a8641SAndroid Build Coastguard Worker int add_events,
149*635a8641SAndroid Build Coastguard Worker WaitableEvent* event);
150*635a8641SAndroid Build Coastguard Worker };
151*635a8641SAndroid Build Coastguard Worker
152*635a8641SAndroid Build Coastguard Worker struct CollectionContext {
CollectionContextbase::StackSamplingProfiler::SamplingThread::CollectionContext153*635a8641SAndroid Build Coastguard Worker CollectionContext(PlatformThreadId target,
154*635a8641SAndroid Build Coastguard Worker const SamplingParams& params,
155*635a8641SAndroid Build Coastguard Worker WaitableEvent* finished,
156*635a8641SAndroid Build Coastguard Worker std::unique_ptr<NativeStackSampler> sampler,
157*635a8641SAndroid Build Coastguard Worker std::unique_ptr<ProfileBuilder> profile_builder)
158*635a8641SAndroid Build Coastguard Worker : collection_id(next_collection_id.GetNext()),
159*635a8641SAndroid Build Coastguard Worker target(target),
160*635a8641SAndroid Build Coastguard Worker params(params),
161*635a8641SAndroid Build Coastguard Worker finished(finished),
162*635a8641SAndroid Build Coastguard Worker native_sampler(std::move(sampler)),
163*635a8641SAndroid Build Coastguard Worker profile_builder(std::move(profile_builder)) {}
164*635a8641SAndroid Build Coastguard Worker ~CollectionContext() = default;
165*635a8641SAndroid Build Coastguard Worker
166*635a8641SAndroid Build Coastguard Worker // An identifier for this collection, used to uniquely identify the
167*635a8641SAndroid Build Coastguard Worker // collection to outside interests.
168*635a8641SAndroid Build Coastguard Worker const int collection_id;
169*635a8641SAndroid Build Coastguard Worker
170*635a8641SAndroid Build Coastguard Worker const PlatformThreadId target; // ID of The thread being sampled.
171*635a8641SAndroid Build Coastguard Worker const SamplingParams params; // Information about how to sample.
172*635a8641SAndroid Build Coastguard Worker WaitableEvent* const finished; // Signaled when all sampling complete.
173*635a8641SAndroid Build Coastguard Worker
174*635a8641SAndroid Build Coastguard Worker // Platform-specific module that does the actual sampling.
175*635a8641SAndroid Build Coastguard Worker std::unique_ptr<NativeStackSampler> native_sampler;
176*635a8641SAndroid Build Coastguard Worker
177*635a8641SAndroid Build Coastguard Worker // Receives the sampling data and builds a CallStackProfile.
178*635a8641SAndroid Build Coastguard Worker std::unique_ptr<ProfileBuilder> profile_builder;
179*635a8641SAndroid Build Coastguard Worker
180*635a8641SAndroid Build Coastguard Worker // The absolute time for the next sample.
181*635a8641SAndroid Build Coastguard Worker Time next_sample_time;
182*635a8641SAndroid Build Coastguard Worker
183*635a8641SAndroid Build Coastguard Worker // The time that a profile was started, for calculating the total duration.
184*635a8641SAndroid Build Coastguard Worker Time profile_start_time;
185*635a8641SAndroid Build Coastguard Worker
186*635a8641SAndroid Build Coastguard Worker // Counter that indicates the current sample position along the acquisition.
187*635a8641SAndroid Build Coastguard Worker int sample_count = 0;
188*635a8641SAndroid Build Coastguard Worker
189*635a8641SAndroid Build Coastguard Worker // Sequence number for generating new collection ids.
190*635a8641SAndroid Build Coastguard Worker static AtomicSequenceNumber next_collection_id;
191*635a8641SAndroid Build Coastguard Worker };
192*635a8641SAndroid Build Coastguard Worker
193*635a8641SAndroid Build Coastguard Worker // Gets the single instance of this class.
194*635a8641SAndroid Build Coastguard Worker static SamplingThread* GetInstance();
195*635a8641SAndroid Build Coastguard Worker
196*635a8641SAndroid Build Coastguard Worker // Adds a new CollectionContext to the thread. This can be called externally
197*635a8641SAndroid Build Coastguard Worker // from any thread. This returns a collection id that can later be used to
198*635a8641SAndroid Build Coastguard Worker // stop the sampling.
199*635a8641SAndroid Build Coastguard Worker int Add(std::unique_ptr<CollectionContext> collection);
200*635a8641SAndroid Build Coastguard Worker
201*635a8641SAndroid Build Coastguard Worker // Removes an active collection based on its collection id, forcing it to run
202*635a8641SAndroid Build Coastguard Worker // its callback if any data has been collected. This can be called externally
203*635a8641SAndroid Build Coastguard Worker // from any thread.
204*635a8641SAndroid Build Coastguard Worker void Remove(int collection_id);
205*635a8641SAndroid Build Coastguard Worker
206*635a8641SAndroid Build Coastguard Worker private:
207*635a8641SAndroid Build Coastguard Worker friend class TestAPI;
208*635a8641SAndroid Build Coastguard Worker friend struct DefaultSingletonTraits<SamplingThread>;
209*635a8641SAndroid Build Coastguard Worker
210*635a8641SAndroid Build Coastguard Worker // The different states in which the sampling-thread can be.
211*635a8641SAndroid Build Coastguard Worker enum ThreadExecutionState {
212*635a8641SAndroid Build Coastguard Worker // The thread is not running because it has never been started. It will be
213*635a8641SAndroid Build Coastguard Worker // started when a sampling request is received.
214*635a8641SAndroid Build Coastguard Worker NOT_STARTED,
215*635a8641SAndroid Build Coastguard Worker
216*635a8641SAndroid Build Coastguard Worker // The thread is running and processing tasks. This is the state when any
217*635a8641SAndroid Build Coastguard Worker // sampling requests are active and during the "idle" period afterward
218*635a8641SAndroid Build Coastguard Worker // before the thread is stopped.
219*635a8641SAndroid Build Coastguard Worker RUNNING,
220*635a8641SAndroid Build Coastguard Worker
221*635a8641SAndroid Build Coastguard Worker // Once all sampling requests have finished and the "idle" period has
222*635a8641SAndroid Build Coastguard Worker // expired, the thread will be set to this state and its shutdown
223*635a8641SAndroid Build Coastguard Worker // initiated. A call to Stop() must be made to ensure the previous thread
224*635a8641SAndroid Build Coastguard Worker // has completely exited before calling Start() and moving back to the
225*635a8641SAndroid Build Coastguard Worker // RUNNING state.
226*635a8641SAndroid Build Coastguard Worker EXITING,
227*635a8641SAndroid Build Coastguard Worker };
228*635a8641SAndroid Build Coastguard Worker
229*635a8641SAndroid Build Coastguard Worker SamplingThread();
230*635a8641SAndroid Build Coastguard Worker ~SamplingThread() override;
231*635a8641SAndroid Build Coastguard Worker
232*635a8641SAndroid Build Coastguard Worker // Get task runner that is usable from the outside.
233*635a8641SAndroid Build Coastguard Worker scoped_refptr<SingleThreadTaskRunner> GetOrCreateTaskRunnerForAdd();
234*635a8641SAndroid Build Coastguard Worker scoped_refptr<SingleThreadTaskRunner> GetTaskRunner(
235*635a8641SAndroid Build Coastguard Worker ThreadExecutionState* out_state);
236*635a8641SAndroid Build Coastguard Worker
237*635a8641SAndroid Build Coastguard Worker // Get task runner that is usable from the sampling thread itself.
238*635a8641SAndroid Build Coastguard Worker scoped_refptr<SingleThreadTaskRunner> GetTaskRunnerOnSamplingThread();
239*635a8641SAndroid Build Coastguard Worker
240*635a8641SAndroid Build Coastguard Worker // Finishes a collection. The collection's |finished| waitable event will be
241*635a8641SAndroid Build Coastguard Worker // signalled. The |collection| should already have been removed from
242*635a8641SAndroid Build Coastguard Worker // |active_collections_| by the caller, as this is needed to avoid flakiness
243*635a8641SAndroid Build Coastguard Worker // in unit tests.
244*635a8641SAndroid Build Coastguard Worker void FinishCollection(CollectionContext* collection);
245*635a8641SAndroid Build Coastguard Worker
246*635a8641SAndroid Build Coastguard Worker // Check if the sampling thread is idle and begin a shutdown if it is.
247*635a8641SAndroid Build Coastguard Worker void ScheduleShutdownIfIdle();
248*635a8641SAndroid Build Coastguard Worker
249*635a8641SAndroid Build Coastguard Worker // These methods are tasks that get posted to the internal message queue.
250*635a8641SAndroid Build Coastguard Worker void AddCollectionTask(std::unique_ptr<CollectionContext> collection);
251*635a8641SAndroid Build Coastguard Worker void RemoveCollectionTask(int collection_id);
252*635a8641SAndroid Build Coastguard Worker void RecordSampleTask(int collection_id);
253*635a8641SAndroid Build Coastguard Worker void ShutdownTask(int add_events);
254*635a8641SAndroid Build Coastguard Worker
255*635a8641SAndroid Build Coastguard Worker // Thread:
256*635a8641SAndroid Build Coastguard Worker void CleanUp() override;
257*635a8641SAndroid Build Coastguard Worker
258*635a8641SAndroid Build Coastguard Worker // A stack-buffer used by the native sampler for its work. This buffer can
259*635a8641SAndroid Build Coastguard Worker // be re-used for multiple native sampler objects so long as the API calls
260*635a8641SAndroid Build Coastguard Worker // that take it are not called concurrently.
261*635a8641SAndroid Build Coastguard Worker std::unique_ptr<NativeStackSampler::StackBuffer> stack_buffer_;
262*635a8641SAndroid Build Coastguard Worker
263*635a8641SAndroid Build Coastguard Worker // A map of collection ids to collection contexts. Because this class is a
264*635a8641SAndroid Build Coastguard Worker // singleton that is never destroyed, context objects will never be destructed
265*635a8641SAndroid Build Coastguard Worker // except by explicit action. Thus, it's acceptable to pass unretained
266*635a8641SAndroid Build Coastguard Worker // pointers to these objects when posting tasks.
267*635a8641SAndroid Build Coastguard Worker std::map<int, std::unique_ptr<CollectionContext>> active_collections_;
268*635a8641SAndroid Build Coastguard Worker
269*635a8641SAndroid Build Coastguard Worker // State maintained about the current execution (or non-execution) of
270*635a8641SAndroid Build Coastguard Worker // the thread. This state must always be accessed while holding the
271*635a8641SAndroid Build Coastguard Worker // lock. A copy of the task-runner is maintained here for use by any
272*635a8641SAndroid Build Coastguard Worker // calling thread; this is necessary because Thread's accessor for it is
273*635a8641SAndroid Build Coastguard Worker // not itself thread-safe. The lock is also used to order calls to the
274*635a8641SAndroid Build Coastguard Worker // Thread API (Start, Stop, StopSoon, & DetachFromSequence) so that
275*635a8641SAndroid Build Coastguard Worker // multiple threads may make those calls.
276*635a8641SAndroid Build Coastguard Worker Lock thread_execution_state_lock_; // Protects all thread_execution_state_*
277*635a8641SAndroid Build Coastguard Worker ThreadExecutionState thread_execution_state_ = NOT_STARTED;
278*635a8641SAndroid Build Coastguard Worker scoped_refptr<SingleThreadTaskRunner> thread_execution_state_task_runner_;
279*635a8641SAndroid Build Coastguard Worker bool thread_execution_state_disable_idle_shutdown_for_testing_ = false;
280*635a8641SAndroid Build Coastguard Worker
281*635a8641SAndroid Build Coastguard Worker // A counter that notes adds of new collection requests. It is incremented
282*635a8641SAndroid Build Coastguard Worker // when changes occur so that delayed shutdown tasks are able to detect if
283*635a8641SAndroid Build Coastguard Worker // something new has happened while it was waiting. Like all "execution_state"
284*635a8641SAndroid Build Coastguard Worker // vars, this must be accessed while holding |thread_execution_state_lock_|.
285*635a8641SAndroid Build Coastguard Worker int thread_execution_state_add_events_ = 0;
286*635a8641SAndroid Build Coastguard Worker
287*635a8641SAndroid Build Coastguard Worker DISALLOW_COPY_AND_ASSIGN(SamplingThread);
288*635a8641SAndroid Build Coastguard Worker };
289*635a8641SAndroid Build Coastguard Worker
290*635a8641SAndroid Build Coastguard Worker // static
Reset()291*635a8641SAndroid Build Coastguard Worker void StackSamplingProfiler::SamplingThread::TestAPI::Reset() {
292*635a8641SAndroid Build Coastguard Worker SamplingThread* sampler = SamplingThread::GetInstance();
293*635a8641SAndroid Build Coastguard Worker
294*635a8641SAndroid Build Coastguard Worker ThreadExecutionState state;
295*635a8641SAndroid Build Coastguard Worker {
296*635a8641SAndroid Build Coastguard Worker AutoLock lock(sampler->thread_execution_state_lock_);
297*635a8641SAndroid Build Coastguard Worker state = sampler->thread_execution_state_;
298*635a8641SAndroid Build Coastguard Worker DCHECK(sampler->active_collections_.empty());
299*635a8641SAndroid Build Coastguard Worker }
300*635a8641SAndroid Build Coastguard Worker
301*635a8641SAndroid Build Coastguard Worker // Stop the thread and wait for it to exit. This has to be done through by
302*635a8641SAndroid Build Coastguard Worker // the thread itself because it has taken ownership of its own lifetime.
303*635a8641SAndroid Build Coastguard Worker if (state == RUNNING) {
304*635a8641SAndroid Build Coastguard Worker ShutdownAssumingIdle(false);
305*635a8641SAndroid Build Coastguard Worker state = EXITING;
306*635a8641SAndroid Build Coastguard Worker }
307*635a8641SAndroid Build Coastguard Worker // Make sure thread is cleaned up since state will be reset to NOT_STARTED.
308*635a8641SAndroid Build Coastguard Worker if (state == EXITING)
309*635a8641SAndroid Build Coastguard Worker sampler->Stop();
310*635a8641SAndroid Build Coastguard Worker
311*635a8641SAndroid Build Coastguard Worker // Reset internal variables to the just-initialized state.
312*635a8641SAndroid Build Coastguard Worker {
313*635a8641SAndroid Build Coastguard Worker AutoLock lock(sampler->thread_execution_state_lock_);
314*635a8641SAndroid Build Coastguard Worker sampler->thread_execution_state_ = NOT_STARTED;
315*635a8641SAndroid Build Coastguard Worker sampler->thread_execution_state_task_runner_ = nullptr;
316*635a8641SAndroid Build Coastguard Worker sampler->thread_execution_state_disable_idle_shutdown_for_testing_ = false;
317*635a8641SAndroid Build Coastguard Worker sampler->thread_execution_state_add_events_ = 0;
318*635a8641SAndroid Build Coastguard Worker }
319*635a8641SAndroid Build Coastguard Worker }
320*635a8641SAndroid Build Coastguard Worker
321*635a8641SAndroid Build Coastguard Worker // static
DisableIdleShutdown()322*635a8641SAndroid Build Coastguard Worker void StackSamplingProfiler::SamplingThread::TestAPI::DisableIdleShutdown() {
323*635a8641SAndroid Build Coastguard Worker SamplingThread* sampler = SamplingThread::GetInstance();
324*635a8641SAndroid Build Coastguard Worker
325*635a8641SAndroid Build Coastguard Worker {
326*635a8641SAndroid Build Coastguard Worker AutoLock lock(sampler->thread_execution_state_lock_);
327*635a8641SAndroid Build Coastguard Worker sampler->thread_execution_state_disable_idle_shutdown_for_testing_ = true;
328*635a8641SAndroid Build Coastguard Worker }
329*635a8641SAndroid Build Coastguard Worker }
330*635a8641SAndroid Build Coastguard Worker
331*635a8641SAndroid Build Coastguard Worker // static
ShutdownAssumingIdle(bool simulate_intervening_add)332*635a8641SAndroid Build Coastguard Worker void StackSamplingProfiler::SamplingThread::TestAPI::ShutdownAssumingIdle(
333*635a8641SAndroid Build Coastguard Worker bool simulate_intervening_add) {
334*635a8641SAndroid Build Coastguard Worker SamplingThread* sampler = SamplingThread::GetInstance();
335*635a8641SAndroid Build Coastguard Worker
336*635a8641SAndroid Build Coastguard Worker ThreadExecutionState state;
337*635a8641SAndroid Build Coastguard Worker scoped_refptr<SingleThreadTaskRunner> task_runner =
338*635a8641SAndroid Build Coastguard Worker sampler->GetTaskRunner(&state);
339*635a8641SAndroid Build Coastguard Worker DCHECK_EQ(RUNNING, state);
340*635a8641SAndroid Build Coastguard Worker DCHECK(task_runner);
341*635a8641SAndroid Build Coastguard Worker
342*635a8641SAndroid Build Coastguard Worker int add_events;
343*635a8641SAndroid Build Coastguard Worker {
344*635a8641SAndroid Build Coastguard Worker AutoLock lock(sampler->thread_execution_state_lock_);
345*635a8641SAndroid Build Coastguard Worker add_events = sampler->thread_execution_state_add_events_;
346*635a8641SAndroid Build Coastguard Worker if (simulate_intervening_add)
347*635a8641SAndroid Build Coastguard Worker ++sampler->thread_execution_state_add_events_;
348*635a8641SAndroid Build Coastguard Worker }
349*635a8641SAndroid Build Coastguard Worker
350*635a8641SAndroid Build Coastguard Worker WaitableEvent executed(WaitableEvent::ResetPolicy::MANUAL,
351*635a8641SAndroid Build Coastguard Worker WaitableEvent::InitialState::NOT_SIGNALED);
352*635a8641SAndroid Build Coastguard Worker // PostTaskAndReply won't work because thread and associated message-loop may
353*635a8641SAndroid Build Coastguard Worker // be shut down.
354*635a8641SAndroid Build Coastguard Worker task_runner->PostTask(
355*635a8641SAndroid Build Coastguard Worker FROM_HERE, BindOnce(&ShutdownTaskAndSignalEvent, Unretained(sampler),
356*635a8641SAndroid Build Coastguard Worker add_events, Unretained(&executed)));
357*635a8641SAndroid Build Coastguard Worker executed.Wait();
358*635a8641SAndroid Build Coastguard Worker }
359*635a8641SAndroid Build Coastguard Worker
360*635a8641SAndroid Build Coastguard Worker // static
ShutdownTaskAndSignalEvent(SamplingThread * sampler,int add_events,WaitableEvent * event)361*635a8641SAndroid Build Coastguard Worker void StackSamplingProfiler::SamplingThread::TestAPI::ShutdownTaskAndSignalEvent(
362*635a8641SAndroid Build Coastguard Worker SamplingThread* sampler,
363*635a8641SAndroid Build Coastguard Worker int add_events,
364*635a8641SAndroid Build Coastguard Worker WaitableEvent* event) {
365*635a8641SAndroid Build Coastguard Worker sampler->ShutdownTask(add_events);
366*635a8641SAndroid Build Coastguard Worker event->Signal();
367*635a8641SAndroid Build Coastguard Worker }
368*635a8641SAndroid Build Coastguard Worker
369*635a8641SAndroid Build Coastguard Worker AtomicSequenceNumber StackSamplingProfiler::SamplingThread::CollectionContext::
370*635a8641SAndroid Build Coastguard Worker next_collection_id;
371*635a8641SAndroid Build Coastguard Worker
SamplingThread()372*635a8641SAndroid Build Coastguard Worker StackSamplingProfiler::SamplingThread::SamplingThread()
373*635a8641SAndroid Build Coastguard Worker : Thread("StackSamplingProfiler") {}
374*635a8641SAndroid Build Coastguard Worker
375*635a8641SAndroid Build Coastguard Worker StackSamplingProfiler::SamplingThread::~SamplingThread() = default;
376*635a8641SAndroid Build Coastguard Worker
377*635a8641SAndroid Build Coastguard Worker StackSamplingProfiler::SamplingThread*
GetInstance()378*635a8641SAndroid Build Coastguard Worker StackSamplingProfiler::SamplingThread::GetInstance() {
379*635a8641SAndroid Build Coastguard Worker return Singleton<SamplingThread, LeakySingletonTraits<SamplingThread>>::get();
380*635a8641SAndroid Build Coastguard Worker }
381*635a8641SAndroid Build Coastguard Worker
Add(std::unique_ptr<CollectionContext> collection)382*635a8641SAndroid Build Coastguard Worker int StackSamplingProfiler::SamplingThread::Add(
383*635a8641SAndroid Build Coastguard Worker std::unique_ptr<CollectionContext> collection) {
384*635a8641SAndroid Build Coastguard Worker // This is not to be run on the sampling thread.
385*635a8641SAndroid Build Coastguard Worker
386*635a8641SAndroid Build Coastguard Worker int collection_id = collection->collection_id;
387*635a8641SAndroid Build Coastguard Worker scoped_refptr<SingleThreadTaskRunner> task_runner =
388*635a8641SAndroid Build Coastguard Worker GetOrCreateTaskRunnerForAdd();
389*635a8641SAndroid Build Coastguard Worker
390*635a8641SAndroid Build Coastguard Worker task_runner->PostTask(
391*635a8641SAndroid Build Coastguard Worker FROM_HERE, BindOnce(&SamplingThread::AddCollectionTask, Unretained(this),
392*635a8641SAndroid Build Coastguard Worker std::move(collection)));
393*635a8641SAndroid Build Coastguard Worker
394*635a8641SAndroid Build Coastguard Worker return collection_id;
395*635a8641SAndroid Build Coastguard Worker }
396*635a8641SAndroid Build Coastguard Worker
Remove(int collection_id)397*635a8641SAndroid Build Coastguard Worker void StackSamplingProfiler::SamplingThread::Remove(int collection_id) {
398*635a8641SAndroid Build Coastguard Worker // This is not to be run on the sampling thread.
399*635a8641SAndroid Build Coastguard Worker
400*635a8641SAndroid Build Coastguard Worker ThreadExecutionState state;
401*635a8641SAndroid Build Coastguard Worker scoped_refptr<SingleThreadTaskRunner> task_runner = GetTaskRunner(&state);
402*635a8641SAndroid Build Coastguard Worker if (state != RUNNING)
403*635a8641SAndroid Build Coastguard Worker return;
404*635a8641SAndroid Build Coastguard Worker DCHECK(task_runner);
405*635a8641SAndroid Build Coastguard Worker
406*635a8641SAndroid Build Coastguard Worker // This can fail if the thread were to exit between acquisition of the task
407*635a8641SAndroid Build Coastguard Worker // runner above and the call below. In that case, however, everything has
408*635a8641SAndroid Build Coastguard Worker // stopped so there's no need to try to stop it.
409*635a8641SAndroid Build Coastguard Worker task_runner->PostTask(FROM_HERE,
410*635a8641SAndroid Build Coastguard Worker BindOnce(&SamplingThread::RemoveCollectionTask,
411*635a8641SAndroid Build Coastguard Worker Unretained(this), collection_id));
412*635a8641SAndroid Build Coastguard Worker }
413*635a8641SAndroid Build Coastguard Worker
414*635a8641SAndroid Build Coastguard Worker scoped_refptr<SingleThreadTaskRunner>
GetOrCreateTaskRunnerForAdd()415*635a8641SAndroid Build Coastguard Worker StackSamplingProfiler::SamplingThread::GetOrCreateTaskRunnerForAdd() {
416*635a8641SAndroid Build Coastguard Worker AutoLock lock(thread_execution_state_lock_);
417*635a8641SAndroid Build Coastguard Worker
418*635a8641SAndroid Build Coastguard Worker // The increment of the "add events" count is why this method is to be only
419*635a8641SAndroid Build Coastguard Worker // called from "add".
420*635a8641SAndroid Build Coastguard Worker ++thread_execution_state_add_events_;
421*635a8641SAndroid Build Coastguard Worker
422*635a8641SAndroid Build Coastguard Worker if (thread_execution_state_ == RUNNING) {
423*635a8641SAndroid Build Coastguard Worker DCHECK(thread_execution_state_task_runner_);
424*635a8641SAndroid Build Coastguard Worker // This shouldn't be called from the sampling thread as it's inefficient.
425*635a8641SAndroid Build Coastguard Worker // Use GetTaskRunnerOnSamplingThread() instead.
426*635a8641SAndroid Build Coastguard Worker DCHECK_NE(GetThreadId(), PlatformThread::CurrentId());
427*635a8641SAndroid Build Coastguard Worker return thread_execution_state_task_runner_;
428*635a8641SAndroid Build Coastguard Worker }
429*635a8641SAndroid Build Coastguard Worker
430*635a8641SAndroid Build Coastguard Worker if (thread_execution_state_ == EXITING) {
431*635a8641SAndroid Build Coastguard Worker // StopSoon() was previously called to shut down the thread
432*635a8641SAndroid Build Coastguard Worker // asynchonously. Stop() must now be called before calling Start() again to
433*635a8641SAndroid Build Coastguard Worker // reset the thread state.
434*635a8641SAndroid Build Coastguard Worker //
435*635a8641SAndroid Build Coastguard Worker // We must allow blocking here to satisfy the Thread implementation, but in
436*635a8641SAndroid Build Coastguard Worker // practice the Stop() call is unlikely to actually block. For this to
437*635a8641SAndroid Build Coastguard Worker // happen a new profiling request would have to be made within the narrow
438*635a8641SAndroid Build Coastguard Worker // window between StopSoon() and thread exit following the end of the 60
439*635a8641SAndroid Build Coastguard Worker // second idle period.
440*635a8641SAndroid Build Coastguard Worker ScopedAllowBlocking allow_blocking;
441*635a8641SAndroid Build Coastguard Worker Stop();
442*635a8641SAndroid Build Coastguard Worker }
443*635a8641SAndroid Build Coastguard Worker
444*635a8641SAndroid Build Coastguard Worker DCHECK(!stack_buffer_);
445*635a8641SAndroid Build Coastguard Worker stack_buffer_ = NativeStackSampler::CreateStackBuffer();
446*635a8641SAndroid Build Coastguard Worker
447*635a8641SAndroid Build Coastguard Worker // The thread is not running. Start it and get associated runner. The task-
448*635a8641SAndroid Build Coastguard Worker // runner has to be saved for future use because though it can be used from
449*635a8641SAndroid Build Coastguard Worker // any thread, it can be acquired via task_runner() only on the created
450*635a8641SAndroid Build Coastguard Worker // thread and the thread that creates it (i.e. this thread) for thread-safety
451*635a8641SAndroid Build Coastguard Worker // reasons which are alleviated in SamplingThread by gating access to it with
452*635a8641SAndroid Build Coastguard Worker // the |thread_execution_state_lock_|.
453*635a8641SAndroid Build Coastguard Worker Start();
454*635a8641SAndroid Build Coastguard Worker thread_execution_state_ = RUNNING;
455*635a8641SAndroid Build Coastguard Worker thread_execution_state_task_runner_ = Thread::task_runner();
456*635a8641SAndroid Build Coastguard Worker
457*635a8641SAndroid Build Coastguard Worker // Detach the sampling thread from the "sequence" (i.e. thread) that
458*635a8641SAndroid Build Coastguard Worker // started it so that it can be self-managed or stopped by another thread.
459*635a8641SAndroid Build Coastguard Worker DetachFromSequence();
460*635a8641SAndroid Build Coastguard Worker
461*635a8641SAndroid Build Coastguard Worker return thread_execution_state_task_runner_;
462*635a8641SAndroid Build Coastguard Worker }
463*635a8641SAndroid Build Coastguard Worker
464*635a8641SAndroid Build Coastguard Worker scoped_refptr<SingleThreadTaskRunner>
GetTaskRunner(ThreadExecutionState * out_state)465*635a8641SAndroid Build Coastguard Worker StackSamplingProfiler::SamplingThread::GetTaskRunner(
466*635a8641SAndroid Build Coastguard Worker ThreadExecutionState* out_state) {
467*635a8641SAndroid Build Coastguard Worker AutoLock lock(thread_execution_state_lock_);
468*635a8641SAndroid Build Coastguard Worker if (out_state)
469*635a8641SAndroid Build Coastguard Worker *out_state = thread_execution_state_;
470*635a8641SAndroid Build Coastguard Worker if (thread_execution_state_ == RUNNING) {
471*635a8641SAndroid Build Coastguard Worker // This shouldn't be called from the sampling thread as it's inefficient.
472*635a8641SAndroid Build Coastguard Worker // Use GetTaskRunnerOnSamplingThread() instead.
473*635a8641SAndroid Build Coastguard Worker DCHECK_NE(GetThreadId(), PlatformThread::CurrentId());
474*635a8641SAndroid Build Coastguard Worker DCHECK(thread_execution_state_task_runner_);
475*635a8641SAndroid Build Coastguard Worker } else {
476*635a8641SAndroid Build Coastguard Worker DCHECK(!thread_execution_state_task_runner_);
477*635a8641SAndroid Build Coastguard Worker }
478*635a8641SAndroid Build Coastguard Worker
479*635a8641SAndroid Build Coastguard Worker return thread_execution_state_task_runner_;
480*635a8641SAndroid Build Coastguard Worker }
481*635a8641SAndroid Build Coastguard Worker
482*635a8641SAndroid Build Coastguard Worker scoped_refptr<SingleThreadTaskRunner>
GetTaskRunnerOnSamplingThread()483*635a8641SAndroid Build Coastguard Worker StackSamplingProfiler::SamplingThread::GetTaskRunnerOnSamplingThread() {
484*635a8641SAndroid Build Coastguard Worker // This should be called only from the sampling thread as it has limited
485*635a8641SAndroid Build Coastguard Worker // accessibility.
486*635a8641SAndroid Build Coastguard Worker DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId());
487*635a8641SAndroid Build Coastguard Worker
488*635a8641SAndroid Build Coastguard Worker return Thread::task_runner();
489*635a8641SAndroid Build Coastguard Worker }
490*635a8641SAndroid Build Coastguard Worker
FinishCollection(CollectionContext * collection)491*635a8641SAndroid Build Coastguard Worker void StackSamplingProfiler::SamplingThread::FinishCollection(
492*635a8641SAndroid Build Coastguard Worker CollectionContext* collection) {
493*635a8641SAndroid Build Coastguard Worker DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId());
494*635a8641SAndroid Build Coastguard Worker DCHECK_EQ(0u, active_collections_.count(collection->collection_id));
495*635a8641SAndroid Build Coastguard Worker
496*635a8641SAndroid Build Coastguard Worker TimeDelta profile_duration = Time::Now() - collection->profile_start_time +
497*635a8641SAndroid Build Coastguard Worker collection->params.sampling_interval;
498*635a8641SAndroid Build Coastguard Worker
499*635a8641SAndroid Build Coastguard Worker collection->profile_builder->OnProfileCompleted(
500*635a8641SAndroid Build Coastguard Worker profile_duration, collection->params.sampling_interval);
501*635a8641SAndroid Build Coastguard Worker
502*635a8641SAndroid Build Coastguard Worker // Signal that this collection is finished.
503*635a8641SAndroid Build Coastguard Worker collection->finished->Signal();
504*635a8641SAndroid Build Coastguard Worker
505*635a8641SAndroid Build Coastguard Worker ScheduleShutdownIfIdle();
506*635a8641SAndroid Build Coastguard Worker }
507*635a8641SAndroid Build Coastguard Worker
ScheduleShutdownIfIdle()508*635a8641SAndroid Build Coastguard Worker void StackSamplingProfiler::SamplingThread::ScheduleShutdownIfIdle() {
509*635a8641SAndroid Build Coastguard Worker DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId());
510*635a8641SAndroid Build Coastguard Worker
511*635a8641SAndroid Build Coastguard Worker if (!active_collections_.empty())
512*635a8641SAndroid Build Coastguard Worker return;
513*635a8641SAndroid Build Coastguard Worker
514*635a8641SAndroid Build Coastguard Worker int add_events;
515*635a8641SAndroid Build Coastguard Worker {
516*635a8641SAndroid Build Coastguard Worker AutoLock lock(thread_execution_state_lock_);
517*635a8641SAndroid Build Coastguard Worker if (thread_execution_state_disable_idle_shutdown_for_testing_)
518*635a8641SAndroid Build Coastguard Worker return;
519*635a8641SAndroid Build Coastguard Worker add_events = thread_execution_state_add_events_;
520*635a8641SAndroid Build Coastguard Worker }
521*635a8641SAndroid Build Coastguard Worker
522*635a8641SAndroid Build Coastguard Worker GetTaskRunnerOnSamplingThread()->PostDelayedTask(
523*635a8641SAndroid Build Coastguard Worker FROM_HERE,
524*635a8641SAndroid Build Coastguard Worker BindOnce(&SamplingThread::ShutdownTask, Unretained(this), add_events),
525*635a8641SAndroid Build Coastguard Worker TimeDelta::FromSeconds(60));
526*635a8641SAndroid Build Coastguard Worker }
527*635a8641SAndroid Build Coastguard Worker
AddCollectionTask(std::unique_ptr<CollectionContext> collection)528*635a8641SAndroid Build Coastguard Worker void StackSamplingProfiler::SamplingThread::AddCollectionTask(
529*635a8641SAndroid Build Coastguard Worker std::unique_ptr<CollectionContext> collection) {
530*635a8641SAndroid Build Coastguard Worker DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId());
531*635a8641SAndroid Build Coastguard Worker
532*635a8641SAndroid Build Coastguard Worker const int collection_id = collection->collection_id;
533*635a8641SAndroid Build Coastguard Worker const TimeDelta initial_delay = collection->params.initial_delay;
534*635a8641SAndroid Build Coastguard Worker
535*635a8641SAndroid Build Coastguard Worker active_collections_.insert(
536*635a8641SAndroid Build Coastguard Worker std::make_pair(collection_id, std::move(collection)));
537*635a8641SAndroid Build Coastguard Worker
538*635a8641SAndroid Build Coastguard Worker GetTaskRunnerOnSamplingThread()->PostDelayedTask(
539*635a8641SAndroid Build Coastguard Worker FROM_HERE,
540*635a8641SAndroid Build Coastguard Worker BindOnce(&SamplingThread::RecordSampleTask, Unretained(this),
541*635a8641SAndroid Build Coastguard Worker collection_id),
542*635a8641SAndroid Build Coastguard Worker initial_delay);
543*635a8641SAndroid Build Coastguard Worker
544*635a8641SAndroid Build Coastguard Worker // Another increment of "add events" serves to invalidate any pending
545*635a8641SAndroid Build Coastguard Worker // shutdown tasks that may have been initiated between the Add() and this
546*635a8641SAndroid Build Coastguard Worker // task running.
547*635a8641SAndroid Build Coastguard Worker {
548*635a8641SAndroid Build Coastguard Worker AutoLock lock(thread_execution_state_lock_);
549*635a8641SAndroid Build Coastguard Worker ++thread_execution_state_add_events_;
550*635a8641SAndroid Build Coastguard Worker }
551*635a8641SAndroid Build Coastguard Worker }
552*635a8641SAndroid Build Coastguard Worker
RemoveCollectionTask(int collection_id)553*635a8641SAndroid Build Coastguard Worker void StackSamplingProfiler::SamplingThread::RemoveCollectionTask(
554*635a8641SAndroid Build Coastguard Worker int collection_id) {
555*635a8641SAndroid Build Coastguard Worker DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId());
556*635a8641SAndroid Build Coastguard Worker
557*635a8641SAndroid Build Coastguard Worker auto found = active_collections_.find(collection_id);
558*635a8641SAndroid Build Coastguard Worker if (found == active_collections_.end())
559*635a8641SAndroid Build Coastguard Worker return;
560*635a8641SAndroid Build Coastguard Worker
561*635a8641SAndroid Build Coastguard Worker // Remove |collection| from |active_collections_|.
562*635a8641SAndroid Build Coastguard Worker std::unique_ptr<CollectionContext> collection = std::move(found->second);
563*635a8641SAndroid Build Coastguard Worker size_t count = active_collections_.erase(collection_id);
564*635a8641SAndroid Build Coastguard Worker DCHECK_EQ(1U, count);
565*635a8641SAndroid Build Coastguard Worker
566*635a8641SAndroid Build Coastguard Worker FinishCollection(collection.get());
567*635a8641SAndroid Build Coastguard Worker }
568*635a8641SAndroid Build Coastguard Worker
RecordSampleTask(int collection_id)569*635a8641SAndroid Build Coastguard Worker void StackSamplingProfiler::SamplingThread::RecordSampleTask(
570*635a8641SAndroid Build Coastguard Worker int collection_id) {
571*635a8641SAndroid Build Coastguard Worker DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId());
572*635a8641SAndroid Build Coastguard Worker
573*635a8641SAndroid Build Coastguard Worker auto found = active_collections_.find(collection_id);
574*635a8641SAndroid Build Coastguard Worker
575*635a8641SAndroid Build Coastguard Worker // The task won't be found if it has been stopped.
576*635a8641SAndroid Build Coastguard Worker if (found == active_collections_.end())
577*635a8641SAndroid Build Coastguard Worker return;
578*635a8641SAndroid Build Coastguard Worker
579*635a8641SAndroid Build Coastguard Worker CollectionContext* collection = found->second.get();
580*635a8641SAndroid Build Coastguard Worker
581*635a8641SAndroid Build Coastguard Worker // If this is the first sample, the collection params need to be filled.
582*635a8641SAndroid Build Coastguard Worker if (collection->sample_count == 0) {
583*635a8641SAndroid Build Coastguard Worker collection->profile_start_time = Time::Now();
584*635a8641SAndroid Build Coastguard Worker collection->next_sample_time = Time::Now();
585*635a8641SAndroid Build Coastguard Worker collection->native_sampler->ProfileRecordingStarting();
586*635a8641SAndroid Build Coastguard Worker }
587*635a8641SAndroid Build Coastguard Worker
588*635a8641SAndroid Build Coastguard Worker // Record a single sample.
589*635a8641SAndroid Build Coastguard Worker collection->profile_builder->OnSampleCompleted(
590*635a8641SAndroid Build Coastguard Worker collection->native_sampler->RecordStackFrames(
591*635a8641SAndroid Build Coastguard Worker stack_buffer_.get(), collection->profile_builder.get()));
592*635a8641SAndroid Build Coastguard Worker
593*635a8641SAndroid Build Coastguard Worker // Schedule the next sample recording if there is one.
594*635a8641SAndroid Build Coastguard Worker if (++collection->sample_count < collection->params.samples_per_profile) {
595*635a8641SAndroid Build Coastguard Worker // This will keep a consistent average interval between samples but will
596*635a8641SAndroid Build Coastguard Worker // result in constant series of acquisitions, thus nearly locking out the
597*635a8641SAndroid Build Coastguard Worker // target thread, if the interval is smaller than the time it takes to
598*635a8641SAndroid Build Coastguard Worker // actually acquire the sample. Anything sampling that quickly is going
599*635a8641SAndroid Build Coastguard Worker // to be a problem anyway so don't worry about it.
600*635a8641SAndroid Build Coastguard Worker collection->next_sample_time += collection->params.sampling_interval;
601*635a8641SAndroid Build Coastguard Worker bool success = GetTaskRunnerOnSamplingThread()->PostDelayedTask(
602*635a8641SAndroid Build Coastguard Worker FROM_HERE,
603*635a8641SAndroid Build Coastguard Worker BindOnce(&SamplingThread::RecordSampleTask, Unretained(this),
604*635a8641SAndroid Build Coastguard Worker collection_id),
605*635a8641SAndroid Build Coastguard Worker std::max(collection->next_sample_time - Time::Now(), TimeDelta()));
606*635a8641SAndroid Build Coastguard Worker DCHECK(success);
607*635a8641SAndroid Build Coastguard Worker return;
608*635a8641SAndroid Build Coastguard Worker }
609*635a8641SAndroid Build Coastguard Worker
610*635a8641SAndroid Build Coastguard Worker // Take ownership of |collection| and remove it from the map.
611*635a8641SAndroid Build Coastguard Worker std::unique_ptr<CollectionContext> owned_collection =
612*635a8641SAndroid Build Coastguard Worker std::move(found->second);
613*635a8641SAndroid Build Coastguard Worker size_t count = active_collections_.erase(collection_id);
614*635a8641SAndroid Build Coastguard Worker DCHECK_EQ(1U, count);
615*635a8641SAndroid Build Coastguard Worker
616*635a8641SAndroid Build Coastguard Worker // All capturing has completed so finish the collection.
617*635a8641SAndroid Build Coastguard Worker FinishCollection(collection);
618*635a8641SAndroid Build Coastguard Worker }
619*635a8641SAndroid Build Coastguard Worker
ShutdownTask(int add_events)620*635a8641SAndroid Build Coastguard Worker void StackSamplingProfiler::SamplingThread::ShutdownTask(int add_events) {
621*635a8641SAndroid Build Coastguard Worker DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId());
622*635a8641SAndroid Build Coastguard Worker
623*635a8641SAndroid Build Coastguard Worker // Holding this lock ensures that any attempt to start another job will
624*635a8641SAndroid Build Coastguard Worker // get postponed until |thread_execution_state_| is updated, thus eliminating
625*635a8641SAndroid Build Coastguard Worker // the race in starting a new thread while the previous one is exiting.
626*635a8641SAndroid Build Coastguard Worker AutoLock lock(thread_execution_state_lock_);
627*635a8641SAndroid Build Coastguard Worker
628*635a8641SAndroid Build Coastguard Worker // If the current count of creation requests doesn't match the passed count
629*635a8641SAndroid Build Coastguard Worker // then other tasks have been created since this was posted. Abort shutdown.
630*635a8641SAndroid Build Coastguard Worker if (thread_execution_state_add_events_ != add_events)
631*635a8641SAndroid Build Coastguard Worker return;
632*635a8641SAndroid Build Coastguard Worker
633*635a8641SAndroid Build Coastguard Worker // There can be no new AddCollectionTasks at this point because creating
634*635a8641SAndroid Build Coastguard Worker // those always increments "add events". There may be other requests, like
635*635a8641SAndroid Build Coastguard Worker // Remove, but it's okay to schedule the thread to stop once they've been
636*635a8641SAndroid Build Coastguard Worker // executed (i.e. "soon").
637*635a8641SAndroid Build Coastguard Worker DCHECK(active_collections_.empty());
638*635a8641SAndroid Build Coastguard Worker StopSoon();
639*635a8641SAndroid Build Coastguard Worker
640*635a8641SAndroid Build Coastguard Worker // StopSoon will have set the owning sequence (again) so it must be detached
641*635a8641SAndroid Build Coastguard Worker // (again) in order for Stop/Start to be called (again) should more work
642*635a8641SAndroid Build Coastguard Worker // come in. Holding the |thread_execution_state_lock_| ensures the necessary
643*635a8641SAndroid Build Coastguard Worker // happens-after with regard to this detach and future Thread API calls.
644*635a8641SAndroid Build Coastguard Worker DetachFromSequence();
645*635a8641SAndroid Build Coastguard Worker
646*635a8641SAndroid Build Coastguard Worker // Set the thread_state variable so the thread will be restarted when new
647*635a8641SAndroid Build Coastguard Worker // work comes in. Remove the |thread_execution_state_task_runner_| to avoid
648*635a8641SAndroid Build Coastguard Worker // confusion.
649*635a8641SAndroid Build Coastguard Worker thread_execution_state_ = EXITING;
650*635a8641SAndroid Build Coastguard Worker thread_execution_state_task_runner_ = nullptr;
651*635a8641SAndroid Build Coastguard Worker stack_buffer_.reset();
652*635a8641SAndroid Build Coastguard Worker }
653*635a8641SAndroid Build Coastguard Worker
CleanUp()654*635a8641SAndroid Build Coastguard Worker void StackSamplingProfiler::SamplingThread::CleanUp() {
655*635a8641SAndroid Build Coastguard Worker DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId());
656*635a8641SAndroid Build Coastguard Worker
657*635a8641SAndroid Build Coastguard Worker // There should be no collections remaining when the thread stops.
658*635a8641SAndroid Build Coastguard Worker DCHECK(active_collections_.empty());
659*635a8641SAndroid Build Coastguard Worker
660*635a8641SAndroid Build Coastguard Worker // Let the parent clean up.
661*635a8641SAndroid Build Coastguard Worker Thread::CleanUp();
662*635a8641SAndroid Build Coastguard Worker }
663*635a8641SAndroid Build Coastguard Worker
664*635a8641SAndroid Build Coastguard Worker // StackSamplingProfiler ------------------------------------------------------
665*635a8641SAndroid Build Coastguard Worker
666*635a8641SAndroid Build Coastguard Worker // static
Reset()667*635a8641SAndroid Build Coastguard Worker void StackSamplingProfiler::TestAPI::Reset() {
668*635a8641SAndroid Build Coastguard Worker SamplingThread::TestAPI::Reset();
669*635a8641SAndroid Build Coastguard Worker }
670*635a8641SAndroid Build Coastguard Worker
671*635a8641SAndroid Build Coastguard Worker // static
IsSamplingThreadRunning()672*635a8641SAndroid Build Coastguard Worker bool StackSamplingProfiler::TestAPI::IsSamplingThreadRunning() {
673*635a8641SAndroid Build Coastguard Worker return SamplingThread::GetInstance()->IsRunning();
674*635a8641SAndroid Build Coastguard Worker }
675*635a8641SAndroid Build Coastguard Worker
676*635a8641SAndroid Build Coastguard Worker // static
DisableIdleShutdown()677*635a8641SAndroid Build Coastguard Worker void StackSamplingProfiler::TestAPI::DisableIdleShutdown() {
678*635a8641SAndroid Build Coastguard Worker SamplingThread::TestAPI::DisableIdleShutdown();
679*635a8641SAndroid Build Coastguard Worker }
680*635a8641SAndroid Build Coastguard Worker
681*635a8641SAndroid Build Coastguard Worker // static
PerformSamplingThreadIdleShutdown(bool simulate_intervening_start)682*635a8641SAndroid Build Coastguard Worker void StackSamplingProfiler::TestAPI::PerformSamplingThreadIdleShutdown(
683*635a8641SAndroid Build Coastguard Worker bool simulate_intervening_start) {
684*635a8641SAndroid Build Coastguard Worker SamplingThread::TestAPI::ShutdownAssumingIdle(simulate_intervening_start);
685*635a8641SAndroid Build Coastguard Worker }
686*635a8641SAndroid Build Coastguard Worker
StackSamplingProfiler(const SamplingParams & params,std::unique_ptr<ProfileBuilder> profile_builder,NativeStackSamplerTestDelegate * test_delegate)687*635a8641SAndroid Build Coastguard Worker StackSamplingProfiler::StackSamplingProfiler(
688*635a8641SAndroid Build Coastguard Worker const SamplingParams& params,
689*635a8641SAndroid Build Coastguard Worker std::unique_ptr<ProfileBuilder> profile_builder,
690*635a8641SAndroid Build Coastguard Worker NativeStackSamplerTestDelegate* test_delegate)
691*635a8641SAndroid Build Coastguard Worker : StackSamplingProfiler(PlatformThread::CurrentId(),
692*635a8641SAndroid Build Coastguard Worker params,
693*635a8641SAndroid Build Coastguard Worker std::move(profile_builder),
694*635a8641SAndroid Build Coastguard Worker test_delegate) {}
695*635a8641SAndroid Build Coastguard Worker
StackSamplingProfiler(PlatformThreadId thread_id,const SamplingParams & params,std::unique_ptr<ProfileBuilder> profile_builder,NativeStackSamplerTestDelegate * test_delegate)696*635a8641SAndroid Build Coastguard Worker StackSamplingProfiler::StackSamplingProfiler(
697*635a8641SAndroid Build Coastguard Worker PlatformThreadId thread_id,
698*635a8641SAndroid Build Coastguard Worker const SamplingParams& params,
699*635a8641SAndroid Build Coastguard Worker std::unique_ptr<ProfileBuilder> profile_builder,
700*635a8641SAndroid Build Coastguard Worker NativeStackSamplerTestDelegate* test_delegate)
701*635a8641SAndroid Build Coastguard Worker : thread_id_(thread_id),
702*635a8641SAndroid Build Coastguard Worker params_(params),
703*635a8641SAndroid Build Coastguard Worker profile_builder_(std::move(profile_builder)),
704*635a8641SAndroid Build Coastguard Worker // The event starts "signaled" so code knows it's safe to start thread
705*635a8641SAndroid Build Coastguard Worker // and "manual" so that it can be waited in multiple places.
706*635a8641SAndroid Build Coastguard Worker profiling_inactive_(kResetPolicy, WaitableEvent::InitialState::SIGNALED),
707*635a8641SAndroid Build Coastguard Worker profiler_id_(kNullProfilerId),
708*635a8641SAndroid Build Coastguard Worker test_delegate_(test_delegate) {
709*635a8641SAndroid Build Coastguard Worker DCHECK(profile_builder_);
710*635a8641SAndroid Build Coastguard Worker }
711*635a8641SAndroid Build Coastguard Worker
~StackSamplingProfiler()712*635a8641SAndroid Build Coastguard Worker StackSamplingProfiler::~StackSamplingProfiler() {
713*635a8641SAndroid Build Coastguard Worker // Stop returns immediately but the shutdown runs asynchronously. There is a
714*635a8641SAndroid Build Coastguard Worker // non-zero probability that one more sample will be taken after this call
715*635a8641SAndroid Build Coastguard Worker // returns.
716*635a8641SAndroid Build Coastguard Worker Stop();
717*635a8641SAndroid Build Coastguard Worker
718*635a8641SAndroid Build Coastguard Worker // The behavior of sampling a thread that has exited is undefined and could
719*635a8641SAndroid Build Coastguard Worker // cause Bad Things(tm) to occur. The safety model provided by this class is
720*635a8641SAndroid Build Coastguard Worker // that an instance of this object is expected to live at least as long as
721*635a8641SAndroid Build Coastguard Worker // the thread it is sampling. However, because the sampling is performed
722*635a8641SAndroid Build Coastguard Worker // asynchronously by the SamplingThread, there is no way to guarantee this
723*635a8641SAndroid Build Coastguard Worker // is true without waiting for it to signal that it has finished.
724*635a8641SAndroid Build Coastguard Worker //
725*635a8641SAndroid Build Coastguard Worker // The wait time should, at most, be only as long as it takes to collect one
726*635a8641SAndroid Build Coastguard Worker // sample (~200us) or none at all if sampling has already completed.
727*635a8641SAndroid Build Coastguard Worker ThreadRestrictions::ScopedAllowWait allow_wait;
728*635a8641SAndroid Build Coastguard Worker profiling_inactive_.Wait();
729*635a8641SAndroid Build Coastguard Worker }
730*635a8641SAndroid Build Coastguard Worker
Start()731*635a8641SAndroid Build Coastguard Worker void StackSamplingProfiler::Start() {
732*635a8641SAndroid Build Coastguard Worker // Multiple calls to Start() for a single StackSamplingProfiler object is not
733*635a8641SAndroid Build Coastguard Worker // allowed. If profile_builder_ is nullptr, then Start() has been called
734*635a8641SAndroid Build Coastguard Worker // already.
735*635a8641SAndroid Build Coastguard Worker DCHECK(profile_builder_);
736*635a8641SAndroid Build Coastguard Worker
737*635a8641SAndroid Build Coastguard Worker std::unique_ptr<NativeStackSampler> native_sampler =
738*635a8641SAndroid Build Coastguard Worker NativeStackSampler::Create(thread_id_, test_delegate_);
739*635a8641SAndroid Build Coastguard Worker
740*635a8641SAndroid Build Coastguard Worker if (!native_sampler)
741*635a8641SAndroid Build Coastguard Worker return;
742*635a8641SAndroid Build Coastguard Worker
743*635a8641SAndroid Build Coastguard Worker // The IsSignaled() check below requires that the WaitableEvent be manually
744*635a8641SAndroid Build Coastguard Worker // reset, to avoid signaling the event in IsSignaled() itself.
745*635a8641SAndroid Build Coastguard Worker static_assert(kResetPolicy == WaitableEvent::ResetPolicy::MANUAL,
746*635a8641SAndroid Build Coastguard Worker "The reset policy must be set to MANUAL");
747*635a8641SAndroid Build Coastguard Worker
748*635a8641SAndroid Build Coastguard Worker // If a previous profiling phase is still winding down, wait for it to
749*635a8641SAndroid Build Coastguard Worker // complete. We can't use task posting for this coordination because the
750*635a8641SAndroid Build Coastguard Worker // thread owning the profiler may not have a message loop.
751*635a8641SAndroid Build Coastguard Worker if (!profiling_inactive_.IsSignaled())
752*635a8641SAndroid Build Coastguard Worker profiling_inactive_.Wait();
753*635a8641SAndroid Build Coastguard Worker profiling_inactive_.Reset();
754*635a8641SAndroid Build Coastguard Worker
755*635a8641SAndroid Build Coastguard Worker DCHECK_EQ(kNullProfilerId, profiler_id_);
756*635a8641SAndroid Build Coastguard Worker profiler_id_ = SamplingThread::GetInstance()->Add(
757*635a8641SAndroid Build Coastguard Worker std::make_unique<SamplingThread::CollectionContext>(
758*635a8641SAndroid Build Coastguard Worker thread_id_, params_, &profiling_inactive_, std::move(native_sampler),
759*635a8641SAndroid Build Coastguard Worker std::move(profile_builder_)));
760*635a8641SAndroid Build Coastguard Worker DCHECK_NE(kNullProfilerId, profiler_id_);
761*635a8641SAndroid Build Coastguard Worker }
762*635a8641SAndroid Build Coastguard Worker
Stop()763*635a8641SAndroid Build Coastguard Worker void StackSamplingProfiler::Stop() {
764*635a8641SAndroid Build Coastguard Worker SamplingThread::GetInstance()->Remove(profiler_id_);
765*635a8641SAndroid Build Coastguard Worker profiler_id_ = kNullProfilerId;
766*635a8641SAndroid Build Coastguard Worker }
767*635a8641SAndroid Build Coastguard Worker
768*635a8641SAndroid Build Coastguard Worker // StackSamplingProfiler::Frame global functions ------------------------------
769*635a8641SAndroid Build Coastguard Worker
operator ==(const StackSamplingProfiler::Module & a,const StackSamplingProfiler::Module & b)770*635a8641SAndroid Build Coastguard Worker bool operator==(const StackSamplingProfiler::Module& a,
771*635a8641SAndroid Build Coastguard Worker const StackSamplingProfiler::Module& b) {
772*635a8641SAndroid Build Coastguard Worker return a.base_address == b.base_address && a.id == b.id &&
773*635a8641SAndroid Build Coastguard Worker a.filename == b.filename;
774*635a8641SAndroid Build Coastguard Worker }
775*635a8641SAndroid Build Coastguard Worker
operator ==(const StackSamplingProfiler::Sample & a,const StackSamplingProfiler::Sample & b)776*635a8641SAndroid Build Coastguard Worker bool operator==(const StackSamplingProfiler::Sample& a,
777*635a8641SAndroid Build Coastguard Worker const StackSamplingProfiler::Sample& b) {
778*635a8641SAndroid Build Coastguard Worker return a.process_milestones == b.process_milestones && a.frames == b.frames;
779*635a8641SAndroid Build Coastguard Worker }
780*635a8641SAndroid Build Coastguard Worker
operator !=(const StackSamplingProfiler::Sample & a,const StackSamplingProfiler::Sample & b)781*635a8641SAndroid Build Coastguard Worker bool operator!=(const StackSamplingProfiler::Sample& a,
782*635a8641SAndroid Build Coastguard Worker const StackSamplingProfiler::Sample& b) {
783*635a8641SAndroid Build Coastguard Worker return !(a == b);
784*635a8641SAndroid Build Coastguard Worker }
785*635a8641SAndroid Build Coastguard Worker
operator <(const StackSamplingProfiler::Sample & a,const StackSamplingProfiler::Sample & b)786*635a8641SAndroid Build Coastguard Worker bool operator<(const StackSamplingProfiler::Sample& a,
787*635a8641SAndroid Build Coastguard Worker const StackSamplingProfiler::Sample& b) {
788*635a8641SAndroid Build Coastguard Worker if (a.process_milestones != b.process_milestones)
789*635a8641SAndroid Build Coastguard Worker return a.process_milestones < b.process_milestones;
790*635a8641SAndroid Build Coastguard Worker
791*635a8641SAndroid Build Coastguard Worker return a.frames < b.frames;
792*635a8641SAndroid Build Coastguard Worker }
793*635a8641SAndroid Build Coastguard Worker
operator ==(const StackSamplingProfiler::Frame & a,const StackSamplingProfiler::Frame & b)794*635a8641SAndroid Build Coastguard Worker bool operator==(const StackSamplingProfiler::Frame& a,
795*635a8641SAndroid Build Coastguard Worker const StackSamplingProfiler::Frame& b) {
796*635a8641SAndroid Build Coastguard Worker return a.instruction_pointer == b.instruction_pointer &&
797*635a8641SAndroid Build Coastguard Worker a.module_index == b.module_index;
798*635a8641SAndroid Build Coastguard Worker }
799*635a8641SAndroid Build Coastguard Worker
operator <(const StackSamplingProfiler::Frame & a,const StackSamplingProfiler::Frame & b)800*635a8641SAndroid Build Coastguard Worker bool operator<(const StackSamplingProfiler::Frame& a,
801*635a8641SAndroid Build Coastguard Worker const StackSamplingProfiler::Frame& b) {
802*635a8641SAndroid Build Coastguard Worker if (a.module_index != b.module_index)
803*635a8641SAndroid Build Coastguard Worker return a.module_index < b.module_index;
804*635a8641SAndroid Build Coastguard Worker
805*635a8641SAndroid Build Coastguard Worker return a.instruction_pointer < b.instruction_pointer;
806*635a8641SAndroid Build Coastguard Worker }
807*635a8641SAndroid Build Coastguard Worker
808*635a8641SAndroid Build Coastguard Worker } // namespace base
809