xref: /aosp_15_r20/external/libchrome/base/profiler/stack_sampling_profiler.cc (revision 635a864187cb8b6c713ff48b7e790a6b21769273)
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