xref: /aosp_15_r20/external/cronet/base/profiler/stack_sampling_profiler.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2015 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #include "base/profiler/stack_sampling_profiler.h"
6*6777b538SAndroid Build Coastguard Worker 
7*6777b538SAndroid Build Coastguard Worker #include <algorithm>
8*6777b538SAndroid Build Coastguard Worker #include <cmath>
9*6777b538SAndroid Build Coastguard Worker #include <map>
10*6777b538SAndroid Build Coastguard Worker #include <optional>
11*6777b538SAndroid Build Coastguard Worker #include <utility>
12*6777b538SAndroid Build Coastguard Worker 
13*6777b538SAndroid Build Coastguard Worker #include "base/atomic_sequence_num.h"
14*6777b538SAndroid Build Coastguard Worker #include "base/atomicops.h"
15*6777b538SAndroid Build Coastguard Worker #include "base/functional/bind.h"
16*6777b538SAndroid Build Coastguard Worker #include "base/functional/callback.h"
17*6777b538SAndroid Build Coastguard Worker #include "base/functional/callback_helpers.h"
18*6777b538SAndroid Build Coastguard Worker #include "base/location.h"
19*6777b538SAndroid Build Coastguard Worker #include "base/memory/ptr_util.h"
20*6777b538SAndroid Build Coastguard Worker #include "base/memory/raw_ptr.h"
21*6777b538SAndroid Build Coastguard Worker #include "base/memory/singleton.h"
22*6777b538SAndroid Build Coastguard Worker #include "base/profiler/profiler_buildflags.h"
23*6777b538SAndroid Build Coastguard Worker #include "base/profiler/stack_buffer.h"
24*6777b538SAndroid Build Coastguard Worker #include "base/profiler/stack_sampler.h"
25*6777b538SAndroid Build Coastguard Worker #include "base/profiler/unwinder.h"
26*6777b538SAndroid Build Coastguard Worker #include "base/synchronization/lock.h"
27*6777b538SAndroid Build Coastguard Worker #include "base/synchronization/waitable_event.h"
28*6777b538SAndroid Build Coastguard Worker #include "base/thread_annotations.h"
29*6777b538SAndroid Build Coastguard Worker #include "base/threading/thread.h"
30*6777b538SAndroid Build Coastguard Worker #include "base/threading/thread_restrictions.h"
31*6777b538SAndroid Build Coastguard Worker #include "base/time/time.h"
32*6777b538SAndroid Build Coastguard Worker #include "base/trace_event/base_tracing.h"
33*6777b538SAndroid Build Coastguard Worker #include "build/build_config.h"
34*6777b538SAndroid Build Coastguard Worker 
35*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_WIN)
36*6777b538SAndroid Build Coastguard Worker #include "base/win/static_constants.h"
37*6777b538SAndroid Build Coastguard Worker #endif
38*6777b538SAndroid Build Coastguard Worker 
39*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_APPLE)
40*6777b538SAndroid Build Coastguard Worker #include "base/mac/mac_util.h"
41*6777b538SAndroid Build Coastguard Worker #endif
42*6777b538SAndroid Build Coastguard Worker 
43*6777b538SAndroid Build Coastguard Worker namespace base {
44*6777b538SAndroid Build Coastguard Worker 
45*6777b538SAndroid Build Coastguard Worker // Allows StackSamplingProfiler to recall a thread which should already pretty
46*6777b538SAndroid Build Coastguard Worker // much be dead (thus it should be a fast Join()).
47*6777b538SAndroid Build Coastguard Worker class ScopedAllowThreadRecallForStackSamplingProfiler
48*6777b538SAndroid Build Coastguard Worker     : public ScopedAllowBaseSyncPrimitivesOutsideBlockingScope {};
49*6777b538SAndroid Build Coastguard Worker 
50*6777b538SAndroid Build Coastguard Worker namespace {
51*6777b538SAndroid Build Coastguard Worker 
52*6777b538SAndroid Build Coastguard Worker // This value is used to initialize the WaitableEvent object. This MUST BE set
53*6777b538SAndroid Build Coastguard Worker // to MANUAL for correct operation of the IsSignaled() call in Start(). See the
54*6777b538SAndroid Build Coastguard Worker // comment there for why.
55*6777b538SAndroid Build Coastguard Worker constexpr WaitableEvent::ResetPolicy kResetPolicy =
56*6777b538SAndroid Build Coastguard Worker     WaitableEvent::ResetPolicy::MANUAL;
57*6777b538SAndroid Build Coastguard Worker 
58*6777b538SAndroid Build Coastguard Worker // This value is used when there is no collection in progress and thus no ID
59*6777b538SAndroid Build Coastguard Worker // for referencing the active collection to the SamplingThread.
60*6777b538SAndroid Build Coastguard Worker const int kNullProfilerId = -1;
61*6777b538SAndroid Build Coastguard Worker 
GetNextSampleTimeImpl(TimeTicks scheduled_current_sample_time,TimeDelta sampling_interval,TimeTicks now)62*6777b538SAndroid Build Coastguard Worker TimeTicks GetNextSampleTimeImpl(TimeTicks scheduled_current_sample_time,
63*6777b538SAndroid Build Coastguard Worker                                 TimeDelta sampling_interval,
64*6777b538SAndroid Build Coastguard Worker                                 TimeTicks now) {
65*6777b538SAndroid Build Coastguard Worker   // Schedule the next sample at the next sampling_interval-aligned time in
66*6777b538SAndroid Build Coastguard Worker   // the future that's sufficiently far enough from the current sample. In the
67*6777b538SAndroid Build Coastguard Worker   // general case this will be one sampling_interval from the current
68*6777b538SAndroid Build Coastguard Worker   // sample. In cases where sample tasks were unable to be executed, such as
69*6777b538SAndroid Build Coastguard Worker   // during system suspend or bad system-wide jank, we may have missed some
70*6777b538SAndroid Build Coastguard Worker   // samples. The right thing to do for those cases is to skip the missed
71*6777b538SAndroid Build Coastguard Worker   // samples since the rest of the systems also wasn't executing.
72*6777b538SAndroid Build Coastguard Worker 
73*6777b538SAndroid Build Coastguard Worker   // Ensure that the next sample time is at least half a sampling interval
74*6777b538SAndroid Build Coastguard Worker   // away. This causes the second sample after resume to be taken between 0.5
75*6777b538SAndroid Build Coastguard Worker   // and 1.5 samples after the first, or 1 sample interval on average. The delay
76*6777b538SAndroid Build Coastguard Worker   // also serves to provide a grace period in the normal sampling case where the
77*6777b538SAndroid Build Coastguard Worker   // current sample may be taken slightly later than its scheduled time.
78*6777b538SAndroid Build Coastguard Worker   const TimeTicks earliest_next_sample_time = now + sampling_interval / 2;
79*6777b538SAndroid Build Coastguard Worker 
80*6777b538SAndroid Build Coastguard Worker   const TimeDelta minimum_time_delta_to_next_sample =
81*6777b538SAndroid Build Coastguard Worker       earliest_next_sample_time - scheduled_current_sample_time;
82*6777b538SAndroid Build Coastguard Worker 
83*6777b538SAndroid Build Coastguard Worker   // The minimum number of sampling intervals required to get from the scheduled
84*6777b538SAndroid Build Coastguard Worker   // current sample time to the earliest next sample time.
85*6777b538SAndroid Build Coastguard Worker   const int64_t required_sampling_intervals = static_cast<int64_t>(
86*6777b538SAndroid Build Coastguard Worker       std::ceil(minimum_time_delta_to_next_sample / sampling_interval));
87*6777b538SAndroid Build Coastguard Worker   return scheduled_current_sample_time +
88*6777b538SAndroid Build Coastguard Worker          required_sampling_intervals * sampling_interval;
89*6777b538SAndroid Build Coastguard Worker }
90*6777b538SAndroid Build Coastguard Worker 
91*6777b538SAndroid Build Coastguard Worker }  // namespace
92*6777b538SAndroid Build Coastguard Worker 
93*6777b538SAndroid Build Coastguard Worker // StackSamplingProfiler::SamplingThread --------------------------------------
94*6777b538SAndroid Build Coastguard Worker 
95*6777b538SAndroid Build Coastguard Worker class StackSamplingProfiler::SamplingThread : public Thread {
96*6777b538SAndroid Build Coastguard Worker  public:
97*6777b538SAndroid Build Coastguard Worker   class TestPeer {
98*6777b538SAndroid Build Coastguard Worker    public:
99*6777b538SAndroid Build Coastguard Worker     // Reset the existing sampler. This will unfortunately create the object
100*6777b538SAndroid Build Coastguard Worker     // unnecessarily if it doesn't already exist but there's no way around that.
101*6777b538SAndroid Build Coastguard Worker     static void Reset();
102*6777b538SAndroid Build Coastguard Worker 
103*6777b538SAndroid Build Coastguard Worker     // Disables inherent idle-shutdown behavior.
104*6777b538SAndroid Build Coastguard Worker     static void DisableIdleShutdown();
105*6777b538SAndroid Build Coastguard Worker 
106*6777b538SAndroid Build Coastguard Worker     // Begins an idle shutdown as if the idle-timer had expired and wait for
107*6777b538SAndroid Build Coastguard Worker     // it to execute. Since the timer would have only been started at a time
108*6777b538SAndroid Build Coastguard Worker     // when the sampling thread actually was idle, this must be called only
109*6777b538SAndroid Build Coastguard Worker     // when it is known that there are no active sampling threads. If
110*6777b538SAndroid Build Coastguard Worker     // |simulate_intervening_add| is true then, when executed, the shutdown
111*6777b538SAndroid Build Coastguard Worker     // task will believe that a new collection has been added since it was
112*6777b538SAndroid Build Coastguard Worker     // posted.
113*6777b538SAndroid Build Coastguard Worker     static void ShutdownAssumingIdle(bool simulate_intervening_add);
114*6777b538SAndroid Build Coastguard Worker 
115*6777b538SAndroid Build Coastguard Worker    private:
116*6777b538SAndroid Build Coastguard Worker     // Calls the sampling threads ShutdownTask and then signals an event.
117*6777b538SAndroid Build Coastguard Worker     static void ShutdownTaskAndSignalEvent(SamplingThread* sampler,
118*6777b538SAndroid Build Coastguard Worker                                            int add_events,
119*6777b538SAndroid Build Coastguard Worker                                            WaitableEvent* event);
120*6777b538SAndroid Build Coastguard Worker   };
121*6777b538SAndroid Build Coastguard Worker 
122*6777b538SAndroid Build Coastguard Worker   struct CollectionContext {
CollectionContextbase::StackSamplingProfiler::SamplingThread::CollectionContext123*6777b538SAndroid Build Coastguard Worker     CollectionContext(PlatformThreadId thread_id,
124*6777b538SAndroid Build Coastguard Worker                       const SamplingParams& params,
125*6777b538SAndroid Build Coastguard Worker                       WaitableEvent* finished,
126*6777b538SAndroid Build Coastguard Worker                       std::unique_ptr<StackSampler> sampler,
127*6777b538SAndroid Build Coastguard Worker                       std::unique_ptr<ProfileBuilder> profile_builder)
128*6777b538SAndroid Build Coastguard Worker         : collection_id(next_collection_id.GetNext()),
129*6777b538SAndroid Build Coastguard Worker           thread_id(thread_id),
130*6777b538SAndroid Build Coastguard Worker           params(params),
131*6777b538SAndroid Build Coastguard Worker           finished(finished),
132*6777b538SAndroid Build Coastguard Worker           profile_builder(std::move(profile_builder)),
133*6777b538SAndroid Build Coastguard Worker           sampler(std::move(sampler)) {}
134*6777b538SAndroid Build Coastguard Worker     ~CollectionContext() = default;
135*6777b538SAndroid Build Coastguard Worker 
136*6777b538SAndroid Build Coastguard Worker     // An identifier for this collection, used to uniquely identify the
137*6777b538SAndroid Build Coastguard Worker     // collection to outside interests.
138*6777b538SAndroid Build Coastguard Worker     const int collection_id;
139*6777b538SAndroid Build Coastguard Worker     const PlatformThreadId thread_id;  // Thread id of the sampled thread.
140*6777b538SAndroid Build Coastguard Worker 
141*6777b538SAndroid Build Coastguard Worker     const SamplingParams params;    // Information about how to sample.
142*6777b538SAndroid Build Coastguard Worker     const raw_ptr<WaitableEvent>
143*6777b538SAndroid Build Coastguard Worker         finished;  // Signaled when all sampling complete.
144*6777b538SAndroid Build Coastguard Worker 
145*6777b538SAndroid Build Coastguard Worker     // Receives the sampling data and builds a CallStackProfile.
146*6777b538SAndroid Build Coastguard Worker     std::unique_ptr<ProfileBuilder> profile_builder;
147*6777b538SAndroid Build Coastguard Worker 
148*6777b538SAndroid Build Coastguard Worker     // Platform-specific module that does the actual sampling.
149*6777b538SAndroid Build Coastguard Worker     std::unique_ptr<StackSampler> sampler;
150*6777b538SAndroid Build Coastguard Worker 
151*6777b538SAndroid Build Coastguard Worker     // The absolute time for the next sample.
152*6777b538SAndroid Build Coastguard Worker     TimeTicks next_sample_time;
153*6777b538SAndroid Build Coastguard Worker 
154*6777b538SAndroid Build Coastguard Worker     // The time that a profile was started, for calculating the total duration.
155*6777b538SAndroid Build Coastguard Worker     TimeTicks profile_start_time;
156*6777b538SAndroid Build Coastguard Worker 
157*6777b538SAndroid Build Coastguard Worker     // Counter that indicates the current sample position along the acquisition.
158*6777b538SAndroid Build Coastguard Worker     int sample_count = 0;
159*6777b538SAndroid Build Coastguard Worker 
160*6777b538SAndroid Build Coastguard Worker     // Sequence number for generating new collection ids.
161*6777b538SAndroid Build Coastguard Worker     static AtomicSequenceNumber next_collection_id;
162*6777b538SAndroid Build Coastguard Worker   };
163*6777b538SAndroid Build Coastguard Worker 
164*6777b538SAndroid Build Coastguard Worker   // Gets the single instance of this class.
165*6777b538SAndroid Build Coastguard Worker   static SamplingThread* GetInstance();
166*6777b538SAndroid Build Coastguard Worker 
167*6777b538SAndroid Build Coastguard Worker   SamplingThread(const SamplingThread&) = delete;
168*6777b538SAndroid Build Coastguard Worker   SamplingThread& operator=(const SamplingThread&) = delete;
169*6777b538SAndroid Build Coastguard Worker 
170*6777b538SAndroid Build Coastguard Worker   // Adds a new CollectionContext to the thread. This can be called externally
171*6777b538SAndroid Build Coastguard Worker   // from any thread. This returns a collection id that can later be used to
172*6777b538SAndroid Build Coastguard Worker   // stop the sampling.
173*6777b538SAndroid Build Coastguard Worker   int Add(std::unique_ptr<CollectionContext> collection);
174*6777b538SAndroid Build Coastguard Worker 
175*6777b538SAndroid Build Coastguard Worker   // Adds an auxiliary unwinder to be used for the collection, to handle
176*6777b538SAndroid Build Coastguard Worker   // additional, non-native-code unwind scenarios.
177*6777b538SAndroid Build Coastguard Worker   void AddAuxUnwinder(int collection_id, std::unique_ptr<Unwinder> unwinder);
178*6777b538SAndroid Build Coastguard Worker 
179*6777b538SAndroid Build Coastguard Worker   // Applies the metadata to already recorded samples in all collections.
180*6777b538SAndroid Build Coastguard Worker   void ApplyMetadataToPastSamples(base::TimeTicks period_start,
181*6777b538SAndroid Build Coastguard Worker                                   base::TimeTicks period_end,
182*6777b538SAndroid Build Coastguard Worker                                   uint64_t name_hash,
183*6777b538SAndroid Build Coastguard Worker                                   std::optional<int64_t> key,
184*6777b538SAndroid Build Coastguard Worker                                   int64_t value,
185*6777b538SAndroid Build Coastguard Worker                                   std::optional<PlatformThreadId> thread_id);
186*6777b538SAndroid Build Coastguard Worker 
187*6777b538SAndroid Build Coastguard Worker   // Adds the metadata as profile metadata. Profile metadata stores metadata
188*6777b538SAndroid Build Coastguard Worker   // global to the profile.
189*6777b538SAndroid Build Coastguard Worker   void AddProfileMetadata(uint64_t name_hash,
190*6777b538SAndroid Build Coastguard Worker                           std::optional<int64_t> key,
191*6777b538SAndroid Build Coastguard Worker                           int64_t value,
192*6777b538SAndroid Build Coastguard Worker                           std::optional<PlatformThreadId> thread_id);
193*6777b538SAndroid Build Coastguard Worker 
194*6777b538SAndroid Build Coastguard Worker   // Removes an active collection based on its collection id, forcing it to run
195*6777b538SAndroid Build Coastguard Worker   // its callback if any data has been collected. This can be called externally
196*6777b538SAndroid Build Coastguard Worker   // from any thread.
197*6777b538SAndroid Build Coastguard Worker   void Remove(int collection_id);
198*6777b538SAndroid Build Coastguard Worker 
199*6777b538SAndroid Build Coastguard Worker  private:
200*6777b538SAndroid Build Coastguard Worker   friend struct DefaultSingletonTraits<SamplingThread>;
201*6777b538SAndroid Build Coastguard Worker 
202*6777b538SAndroid Build Coastguard Worker   // The different states in which the sampling-thread can be.
203*6777b538SAndroid Build Coastguard Worker   enum ThreadExecutionState {
204*6777b538SAndroid Build Coastguard Worker     // The thread is not running because it has never been started. It will be
205*6777b538SAndroid Build Coastguard Worker     // started when a sampling request is received.
206*6777b538SAndroid Build Coastguard Worker     NOT_STARTED,
207*6777b538SAndroid Build Coastguard Worker 
208*6777b538SAndroid Build Coastguard Worker     // The thread is running and processing tasks. This is the state when any
209*6777b538SAndroid Build Coastguard Worker     // sampling requests are active and during the "idle" period afterward
210*6777b538SAndroid Build Coastguard Worker     // before the thread is stopped.
211*6777b538SAndroid Build Coastguard Worker     RUNNING,
212*6777b538SAndroid Build Coastguard Worker 
213*6777b538SAndroid Build Coastguard Worker     // Once all sampling requests have finished and the "idle" period has
214*6777b538SAndroid Build Coastguard Worker     // expired, the thread will be set to this state and its shutdown
215*6777b538SAndroid Build Coastguard Worker     // initiated. A call to Stop() must be made to ensure the previous thread
216*6777b538SAndroid Build Coastguard Worker     // has completely exited before calling Start() and moving back to the
217*6777b538SAndroid Build Coastguard Worker     // RUNNING state.
218*6777b538SAndroid Build Coastguard Worker     EXITING,
219*6777b538SAndroid Build Coastguard Worker   };
220*6777b538SAndroid Build Coastguard Worker 
221*6777b538SAndroid Build Coastguard Worker   SamplingThread();
222*6777b538SAndroid Build Coastguard Worker   ~SamplingThread() override;
223*6777b538SAndroid Build Coastguard Worker 
224*6777b538SAndroid Build Coastguard Worker   // Get task runner that is usable from the outside.
225*6777b538SAndroid Build Coastguard Worker   scoped_refptr<SingleThreadTaskRunner> GetOrCreateTaskRunnerForAdd();
226*6777b538SAndroid Build Coastguard Worker   scoped_refptr<SingleThreadTaskRunner> GetTaskRunner(
227*6777b538SAndroid Build Coastguard Worker       ThreadExecutionState* out_state);
228*6777b538SAndroid Build Coastguard Worker 
229*6777b538SAndroid Build Coastguard Worker   // Get task runner that is usable from the sampling thread itself.
230*6777b538SAndroid Build Coastguard Worker   scoped_refptr<SingleThreadTaskRunner> GetTaskRunnerOnSamplingThread();
231*6777b538SAndroid Build Coastguard Worker 
232*6777b538SAndroid Build Coastguard Worker   // Finishes a collection. The collection's |finished| waitable event will be
233*6777b538SAndroid Build Coastguard Worker   // signalled. The |collection| should already have been removed from
234*6777b538SAndroid Build Coastguard Worker   // |active_collections_| by the caller, as this is needed to avoid flakiness
235*6777b538SAndroid Build Coastguard Worker   // in unit tests.
236*6777b538SAndroid Build Coastguard Worker   void FinishCollection(std::unique_ptr<CollectionContext> collection);
237*6777b538SAndroid Build Coastguard Worker 
238*6777b538SAndroid Build Coastguard Worker   // Check if the sampling thread is idle and begin a shutdown if it is.
239*6777b538SAndroid Build Coastguard Worker   void ScheduleShutdownIfIdle();
240*6777b538SAndroid Build Coastguard Worker 
241*6777b538SAndroid Build Coastguard Worker   // These methods are tasks that get posted to the internal message queue.
242*6777b538SAndroid Build Coastguard Worker   void AddCollectionTask(std::unique_ptr<CollectionContext> collection);
243*6777b538SAndroid Build Coastguard Worker   void AddAuxUnwinderTask(int collection_id,
244*6777b538SAndroid Build Coastguard Worker                           std::unique_ptr<Unwinder> unwinder);
245*6777b538SAndroid Build Coastguard Worker   void ApplyMetadataToPastSamplesTask(
246*6777b538SAndroid Build Coastguard Worker       base::TimeTicks period_start,
247*6777b538SAndroid Build Coastguard Worker       base::TimeTicks period_end,
248*6777b538SAndroid Build Coastguard Worker       uint64_t name_hash,
249*6777b538SAndroid Build Coastguard Worker       std::optional<int64_t> key,
250*6777b538SAndroid Build Coastguard Worker       int64_t value,
251*6777b538SAndroid Build Coastguard Worker       std::optional<PlatformThreadId> thread_id);
252*6777b538SAndroid Build Coastguard Worker   void AddProfileMetadataTask(uint64_t name_hash,
253*6777b538SAndroid Build Coastguard Worker                               std::optional<int64_t> key,
254*6777b538SAndroid Build Coastguard Worker                               int64_t value,
255*6777b538SAndroid Build Coastguard Worker                               std::optional<PlatformThreadId> thread_id);
256*6777b538SAndroid Build Coastguard Worker   void RemoveCollectionTask(int collection_id);
257*6777b538SAndroid Build Coastguard Worker   void RecordSampleTask(int collection_id);
258*6777b538SAndroid Build Coastguard Worker   void ShutdownTask(int add_events);
259*6777b538SAndroid Build Coastguard Worker 
260*6777b538SAndroid Build Coastguard Worker   // Thread:
261*6777b538SAndroid Build Coastguard Worker   void CleanUp() override;
262*6777b538SAndroid Build Coastguard Worker 
263*6777b538SAndroid Build Coastguard Worker   // A stack-buffer used by the sampler for its work. This buffer is re-used
264*6777b538SAndroid Build Coastguard Worker   // across multiple sampler objects since their execution is serialized on the
265*6777b538SAndroid Build Coastguard Worker   // sampling thread.
266*6777b538SAndroid Build Coastguard Worker   std::unique_ptr<StackBuffer> stack_buffer_;
267*6777b538SAndroid Build Coastguard Worker 
268*6777b538SAndroid Build Coastguard Worker   // A map of collection ids to collection contexts. Because this class is a
269*6777b538SAndroid Build Coastguard Worker   // singleton that is never destroyed, context objects will never be destructed
270*6777b538SAndroid Build Coastguard Worker   // except by explicit action. Thus, it's acceptable to pass unretained
271*6777b538SAndroid Build Coastguard Worker   // pointers to these objects when posting tasks.
272*6777b538SAndroid Build Coastguard Worker   std::map<int, std::unique_ptr<CollectionContext>> active_collections_;
273*6777b538SAndroid Build Coastguard Worker 
274*6777b538SAndroid Build Coastguard Worker   // State maintained about the current execution (or non-execution) of
275*6777b538SAndroid Build Coastguard Worker   // the thread. This state must always be accessed while holding the
276*6777b538SAndroid Build Coastguard Worker   // lock. A copy of the task-runner is maintained here for use by any
277*6777b538SAndroid Build Coastguard Worker   // calling thread; this is necessary because Thread's accessor for it is
278*6777b538SAndroid Build Coastguard Worker   // not itself thread-safe. The lock is also used to order calls to the
279*6777b538SAndroid Build Coastguard Worker   // Thread API (Start, Stop, StopSoon, & DetachFromSequence) so that
280*6777b538SAndroid Build Coastguard Worker   // multiple threads may make those calls.
281*6777b538SAndroid Build Coastguard Worker   Lock thread_execution_state_lock_;  // Protects all thread_execution_state_*
282*6777b538SAndroid Build Coastguard Worker   ThreadExecutionState thread_execution_state_
283*6777b538SAndroid Build Coastguard Worker       GUARDED_BY(thread_execution_state_lock_) = NOT_STARTED;
284*6777b538SAndroid Build Coastguard Worker   scoped_refptr<SingleThreadTaskRunner> thread_execution_state_task_runner_
285*6777b538SAndroid Build Coastguard Worker       GUARDED_BY(thread_execution_state_lock_);
286*6777b538SAndroid Build Coastguard Worker   bool thread_execution_state_disable_idle_shutdown_for_testing_
287*6777b538SAndroid Build Coastguard Worker       GUARDED_BY(thread_execution_state_lock_) = false;
288*6777b538SAndroid Build Coastguard Worker 
289*6777b538SAndroid Build Coastguard Worker   // A counter that notes adds of new collection requests. It is incremented
290*6777b538SAndroid Build Coastguard Worker   // when changes occur so that delayed shutdown tasks are able to detect if
291*6777b538SAndroid Build Coastguard Worker   // something new has happened while it was waiting. Like all "execution_state"
292*6777b538SAndroid Build Coastguard Worker   // vars, this must be accessed while holding |thread_execution_state_lock_|.
293*6777b538SAndroid Build Coastguard Worker   int thread_execution_state_add_events_
294*6777b538SAndroid Build Coastguard Worker       GUARDED_BY(thread_execution_state_lock_) = 0;
295*6777b538SAndroid Build Coastguard Worker };
296*6777b538SAndroid Build Coastguard Worker 
297*6777b538SAndroid Build Coastguard Worker // static
Reset()298*6777b538SAndroid Build Coastguard Worker void StackSamplingProfiler::SamplingThread::TestPeer::Reset() {
299*6777b538SAndroid Build Coastguard Worker   SamplingThread* sampler = SamplingThread::GetInstance();
300*6777b538SAndroid Build Coastguard Worker 
301*6777b538SAndroid Build Coastguard Worker   ThreadExecutionState state;
302*6777b538SAndroid Build Coastguard Worker   {
303*6777b538SAndroid Build Coastguard Worker     AutoLock lock(sampler->thread_execution_state_lock_);
304*6777b538SAndroid Build Coastguard Worker     state = sampler->thread_execution_state_;
305*6777b538SAndroid Build Coastguard Worker     DCHECK(sampler->active_collections_.empty());
306*6777b538SAndroid Build Coastguard Worker   }
307*6777b538SAndroid Build Coastguard Worker 
308*6777b538SAndroid Build Coastguard Worker   // Stop the thread and wait for it to exit. This has to be done through by
309*6777b538SAndroid Build Coastguard Worker   // the thread itself because it has taken ownership of its own lifetime.
310*6777b538SAndroid Build Coastguard Worker   if (state == RUNNING) {
311*6777b538SAndroid Build Coastguard Worker     ShutdownAssumingIdle(false);
312*6777b538SAndroid Build Coastguard Worker     state = EXITING;
313*6777b538SAndroid Build Coastguard Worker   }
314*6777b538SAndroid Build Coastguard Worker   // Make sure thread is cleaned up since state will be reset to NOT_STARTED.
315*6777b538SAndroid Build Coastguard Worker   if (state == EXITING)
316*6777b538SAndroid Build Coastguard Worker     sampler->Stop();
317*6777b538SAndroid Build Coastguard Worker 
318*6777b538SAndroid Build Coastguard Worker   // Reset internal variables to the just-initialized state.
319*6777b538SAndroid Build Coastguard Worker   {
320*6777b538SAndroid Build Coastguard Worker     AutoLock lock(sampler->thread_execution_state_lock_);
321*6777b538SAndroid Build Coastguard Worker     sampler->thread_execution_state_ = NOT_STARTED;
322*6777b538SAndroid Build Coastguard Worker     sampler->thread_execution_state_task_runner_ = nullptr;
323*6777b538SAndroid Build Coastguard Worker     sampler->thread_execution_state_disable_idle_shutdown_for_testing_ = false;
324*6777b538SAndroid Build Coastguard Worker     sampler->thread_execution_state_add_events_ = 0;
325*6777b538SAndroid Build Coastguard Worker   }
326*6777b538SAndroid Build Coastguard Worker }
327*6777b538SAndroid Build Coastguard Worker 
328*6777b538SAndroid Build Coastguard Worker // static
DisableIdleShutdown()329*6777b538SAndroid Build Coastguard Worker void StackSamplingProfiler::SamplingThread::TestPeer::DisableIdleShutdown() {
330*6777b538SAndroid Build Coastguard Worker   SamplingThread* sampler = SamplingThread::GetInstance();
331*6777b538SAndroid Build Coastguard Worker 
332*6777b538SAndroid Build Coastguard Worker   {
333*6777b538SAndroid Build Coastguard Worker     AutoLock lock(sampler->thread_execution_state_lock_);
334*6777b538SAndroid Build Coastguard Worker     sampler->thread_execution_state_disable_idle_shutdown_for_testing_ = true;
335*6777b538SAndroid Build Coastguard Worker   }
336*6777b538SAndroid Build Coastguard Worker }
337*6777b538SAndroid Build Coastguard Worker 
338*6777b538SAndroid Build Coastguard Worker // static
ShutdownAssumingIdle(bool simulate_intervening_add)339*6777b538SAndroid Build Coastguard Worker void StackSamplingProfiler::SamplingThread::TestPeer::ShutdownAssumingIdle(
340*6777b538SAndroid Build Coastguard Worker     bool simulate_intervening_add) {
341*6777b538SAndroid Build Coastguard Worker   SamplingThread* sampler = SamplingThread::GetInstance();
342*6777b538SAndroid Build Coastguard Worker 
343*6777b538SAndroid Build Coastguard Worker   ThreadExecutionState state;
344*6777b538SAndroid Build Coastguard Worker   scoped_refptr<SingleThreadTaskRunner> task_runner =
345*6777b538SAndroid Build Coastguard Worker       sampler->GetTaskRunner(&state);
346*6777b538SAndroid Build Coastguard Worker   DCHECK_EQ(RUNNING, state);
347*6777b538SAndroid Build Coastguard Worker   DCHECK(task_runner);
348*6777b538SAndroid Build Coastguard Worker 
349*6777b538SAndroid Build Coastguard Worker   int add_events;
350*6777b538SAndroid Build Coastguard Worker   {
351*6777b538SAndroid Build Coastguard Worker     AutoLock lock(sampler->thread_execution_state_lock_);
352*6777b538SAndroid Build Coastguard Worker     add_events = sampler->thread_execution_state_add_events_;
353*6777b538SAndroid Build Coastguard Worker     if (simulate_intervening_add)
354*6777b538SAndroid Build Coastguard Worker       ++sampler->thread_execution_state_add_events_;
355*6777b538SAndroid Build Coastguard Worker   }
356*6777b538SAndroid Build Coastguard Worker 
357*6777b538SAndroid Build Coastguard Worker   WaitableEvent executed(WaitableEvent::ResetPolicy::MANUAL,
358*6777b538SAndroid Build Coastguard Worker                          WaitableEvent::InitialState::NOT_SIGNALED);
359*6777b538SAndroid Build Coastguard Worker   // PostTaskAndReply won't work because thread and associated message-loop may
360*6777b538SAndroid Build Coastguard Worker   // be shut down.
361*6777b538SAndroid Build Coastguard Worker   task_runner->PostTask(
362*6777b538SAndroid Build Coastguard Worker       FROM_HERE, BindOnce(&ShutdownTaskAndSignalEvent, Unretained(sampler),
363*6777b538SAndroid Build Coastguard Worker                           add_events, Unretained(&executed)));
364*6777b538SAndroid Build Coastguard Worker   executed.Wait();
365*6777b538SAndroid Build Coastguard Worker }
366*6777b538SAndroid Build Coastguard Worker 
367*6777b538SAndroid Build Coastguard Worker // static
368*6777b538SAndroid Build Coastguard Worker void StackSamplingProfiler::SamplingThread::TestPeer::
ShutdownTaskAndSignalEvent(SamplingThread * sampler,int add_events,WaitableEvent * event)369*6777b538SAndroid Build Coastguard Worker     ShutdownTaskAndSignalEvent(SamplingThread* sampler,
370*6777b538SAndroid Build Coastguard Worker                                int add_events,
371*6777b538SAndroid Build Coastguard Worker                                WaitableEvent* event) {
372*6777b538SAndroid Build Coastguard Worker   sampler->ShutdownTask(add_events);
373*6777b538SAndroid Build Coastguard Worker   event->Signal();
374*6777b538SAndroid Build Coastguard Worker }
375*6777b538SAndroid Build Coastguard Worker 
376*6777b538SAndroid Build Coastguard Worker AtomicSequenceNumber StackSamplingProfiler::SamplingThread::CollectionContext::
377*6777b538SAndroid Build Coastguard Worker     next_collection_id;
378*6777b538SAndroid Build Coastguard Worker 
SamplingThread()379*6777b538SAndroid Build Coastguard Worker StackSamplingProfiler::SamplingThread::SamplingThread()
380*6777b538SAndroid Build Coastguard Worker     : Thread("StackSamplingProfiler") {}
381*6777b538SAndroid Build Coastguard Worker 
382*6777b538SAndroid Build Coastguard Worker StackSamplingProfiler::SamplingThread::~SamplingThread() = default;
383*6777b538SAndroid Build Coastguard Worker 
384*6777b538SAndroid Build Coastguard Worker StackSamplingProfiler::SamplingThread*
GetInstance()385*6777b538SAndroid Build Coastguard Worker StackSamplingProfiler::SamplingThread::GetInstance() {
386*6777b538SAndroid Build Coastguard Worker   return Singleton<SamplingThread, LeakySingletonTraits<SamplingThread>>::get();
387*6777b538SAndroid Build Coastguard Worker }
388*6777b538SAndroid Build Coastguard Worker 
Add(std::unique_ptr<CollectionContext> collection)389*6777b538SAndroid Build Coastguard Worker int StackSamplingProfiler::SamplingThread::Add(
390*6777b538SAndroid Build Coastguard Worker     std::unique_ptr<CollectionContext> collection) {
391*6777b538SAndroid Build Coastguard Worker   // This is not to be run on the sampling thread.
392*6777b538SAndroid Build Coastguard Worker 
393*6777b538SAndroid Build Coastguard Worker   int collection_id = collection->collection_id;
394*6777b538SAndroid Build Coastguard Worker   scoped_refptr<SingleThreadTaskRunner> task_runner =
395*6777b538SAndroid Build Coastguard Worker       GetOrCreateTaskRunnerForAdd();
396*6777b538SAndroid Build Coastguard Worker 
397*6777b538SAndroid Build Coastguard Worker   task_runner->PostTask(
398*6777b538SAndroid Build Coastguard Worker       FROM_HERE, BindOnce(&SamplingThread::AddCollectionTask, Unretained(this),
399*6777b538SAndroid Build Coastguard Worker                           std::move(collection)));
400*6777b538SAndroid Build Coastguard Worker 
401*6777b538SAndroid Build Coastguard Worker   return collection_id;
402*6777b538SAndroid Build Coastguard Worker }
403*6777b538SAndroid Build Coastguard Worker 
AddAuxUnwinder(int collection_id,std::unique_ptr<Unwinder> unwinder)404*6777b538SAndroid Build Coastguard Worker void StackSamplingProfiler::SamplingThread::AddAuxUnwinder(
405*6777b538SAndroid Build Coastguard Worker     int collection_id,
406*6777b538SAndroid Build Coastguard Worker     std::unique_ptr<Unwinder> unwinder) {
407*6777b538SAndroid Build Coastguard Worker   ThreadExecutionState state;
408*6777b538SAndroid Build Coastguard Worker   scoped_refptr<SingleThreadTaskRunner> task_runner = GetTaskRunner(&state);
409*6777b538SAndroid Build Coastguard Worker   if (state != RUNNING)
410*6777b538SAndroid Build Coastguard Worker     return;
411*6777b538SAndroid Build Coastguard Worker   DCHECK(task_runner);
412*6777b538SAndroid Build Coastguard Worker   task_runner->PostTask(
413*6777b538SAndroid Build Coastguard Worker       FROM_HERE, BindOnce(&SamplingThread::AddAuxUnwinderTask, Unretained(this),
414*6777b538SAndroid Build Coastguard Worker                           collection_id, std::move(unwinder)));
415*6777b538SAndroid Build Coastguard Worker }
416*6777b538SAndroid Build Coastguard Worker 
ApplyMetadataToPastSamples(base::TimeTicks period_start,base::TimeTicks period_end,uint64_t name_hash,std::optional<int64_t> key,int64_t value,std::optional<PlatformThreadId> thread_id)417*6777b538SAndroid Build Coastguard Worker void StackSamplingProfiler::SamplingThread::ApplyMetadataToPastSamples(
418*6777b538SAndroid Build Coastguard Worker     base::TimeTicks period_start,
419*6777b538SAndroid Build Coastguard Worker     base::TimeTicks period_end,
420*6777b538SAndroid Build Coastguard Worker     uint64_t name_hash,
421*6777b538SAndroid Build Coastguard Worker     std::optional<int64_t> key,
422*6777b538SAndroid Build Coastguard Worker     int64_t value,
423*6777b538SAndroid Build Coastguard Worker     std::optional<PlatformThreadId> thread_id) {
424*6777b538SAndroid Build Coastguard Worker   ThreadExecutionState state;
425*6777b538SAndroid Build Coastguard Worker   scoped_refptr<SingleThreadTaskRunner> task_runner = GetTaskRunner(&state);
426*6777b538SAndroid Build Coastguard Worker   if (state != RUNNING)
427*6777b538SAndroid Build Coastguard Worker     return;
428*6777b538SAndroid Build Coastguard Worker   DCHECK(task_runner);
429*6777b538SAndroid Build Coastguard Worker   task_runner->PostTask(
430*6777b538SAndroid Build Coastguard Worker       FROM_HERE, BindOnce(&SamplingThread::ApplyMetadataToPastSamplesTask,
431*6777b538SAndroid Build Coastguard Worker                           Unretained(this), period_start, period_end, name_hash,
432*6777b538SAndroid Build Coastguard Worker                           key, value, thread_id));
433*6777b538SAndroid Build Coastguard Worker }
434*6777b538SAndroid Build Coastguard Worker 
AddProfileMetadata(uint64_t name_hash,std::optional<int64_t> key,int64_t value,std::optional<PlatformThreadId> thread_id)435*6777b538SAndroid Build Coastguard Worker void StackSamplingProfiler::SamplingThread::AddProfileMetadata(
436*6777b538SAndroid Build Coastguard Worker     uint64_t name_hash,
437*6777b538SAndroid Build Coastguard Worker     std::optional<int64_t> key,
438*6777b538SAndroid Build Coastguard Worker     int64_t value,
439*6777b538SAndroid Build Coastguard Worker     std::optional<PlatformThreadId> thread_id) {
440*6777b538SAndroid Build Coastguard Worker   ThreadExecutionState state;
441*6777b538SAndroid Build Coastguard Worker   scoped_refptr<SingleThreadTaskRunner> task_runner = GetTaskRunner(&state);
442*6777b538SAndroid Build Coastguard Worker   if (state != RUNNING) {
443*6777b538SAndroid Build Coastguard Worker     return;
444*6777b538SAndroid Build Coastguard Worker   }
445*6777b538SAndroid Build Coastguard Worker   DCHECK(task_runner);
446*6777b538SAndroid Build Coastguard Worker   task_runner->PostTask(
447*6777b538SAndroid Build Coastguard Worker       FROM_HERE, BindOnce(&SamplingThread::AddProfileMetadataTask,
448*6777b538SAndroid Build Coastguard Worker                           Unretained(this), name_hash, key, value, thread_id));
449*6777b538SAndroid Build Coastguard Worker }
450*6777b538SAndroid Build Coastguard Worker 
Remove(int collection_id)451*6777b538SAndroid Build Coastguard Worker void StackSamplingProfiler::SamplingThread::Remove(int collection_id) {
452*6777b538SAndroid Build Coastguard Worker   // This is not to be run on the sampling thread.
453*6777b538SAndroid Build Coastguard Worker 
454*6777b538SAndroid Build Coastguard Worker   ThreadExecutionState state;
455*6777b538SAndroid Build Coastguard Worker   scoped_refptr<SingleThreadTaskRunner> task_runner = GetTaskRunner(&state);
456*6777b538SAndroid Build Coastguard Worker   if (state != RUNNING)
457*6777b538SAndroid Build Coastguard Worker     return;
458*6777b538SAndroid Build Coastguard Worker   DCHECK(task_runner);
459*6777b538SAndroid Build Coastguard Worker 
460*6777b538SAndroid Build Coastguard Worker   // This can fail if the thread were to exit between acquisition of the task
461*6777b538SAndroid Build Coastguard Worker   // runner above and the call below. In that case, however, everything has
462*6777b538SAndroid Build Coastguard Worker   // stopped so there's no need to try to stop it.
463*6777b538SAndroid Build Coastguard Worker   task_runner->PostTask(FROM_HERE,
464*6777b538SAndroid Build Coastguard Worker                         BindOnce(&SamplingThread::RemoveCollectionTask,
465*6777b538SAndroid Build Coastguard Worker                                  Unretained(this), collection_id));
466*6777b538SAndroid Build Coastguard Worker }
467*6777b538SAndroid Build Coastguard Worker 
468*6777b538SAndroid Build Coastguard Worker scoped_refptr<SingleThreadTaskRunner>
GetOrCreateTaskRunnerForAdd()469*6777b538SAndroid Build Coastguard Worker StackSamplingProfiler::SamplingThread::GetOrCreateTaskRunnerForAdd() {
470*6777b538SAndroid Build Coastguard Worker   AutoLock lock(thread_execution_state_lock_);
471*6777b538SAndroid Build Coastguard Worker 
472*6777b538SAndroid Build Coastguard Worker   // The increment of the "add events" count is why this method is to be only
473*6777b538SAndroid Build Coastguard Worker   // called from "add".
474*6777b538SAndroid Build Coastguard Worker   ++thread_execution_state_add_events_;
475*6777b538SAndroid Build Coastguard Worker 
476*6777b538SAndroid Build Coastguard Worker   if (thread_execution_state_ == RUNNING) {
477*6777b538SAndroid Build Coastguard Worker     DCHECK(thread_execution_state_task_runner_);
478*6777b538SAndroid Build Coastguard Worker     // This shouldn't be called from the sampling thread as it's inefficient.
479*6777b538SAndroid Build Coastguard Worker     // Use GetTaskRunnerOnSamplingThread() instead.
480*6777b538SAndroid Build Coastguard Worker     DCHECK_NE(GetThreadId(), PlatformThread::CurrentId());
481*6777b538SAndroid Build Coastguard Worker     return thread_execution_state_task_runner_;
482*6777b538SAndroid Build Coastguard Worker   }
483*6777b538SAndroid Build Coastguard Worker 
484*6777b538SAndroid Build Coastguard Worker   if (thread_execution_state_ == EXITING) {
485*6777b538SAndroid Build Coastguard Worker     // StopSoon() was previously called to shut down the thread
486*6777b538SAndroid Build Coastguard Worker     // asynchonously. Stop() must now be called before calling Start() again to
487*6777b538SAndroid Build Coastguard Worker     // reset the thread state.
488*6777b538SAndroid Build Coastguard Worker     //
489*6777b538SAndroid Build Coastguard Worker     // We must allow blocking here to satisfy the Thread implementation, but in
490*6777b538SAndroid Build Coastguard Worker     // practice the Stop() call is unlikely to actually block. For this to
491*6777b538SAndroid Build Coastguard Worker     // happen a new profiling request would have to be made within the narrow
492*6777b538SAndroid Build Coastguard Worker     // window between StopSoon() and thread exit following the end of the 60
493*6777b538SAndroid Build Coastguard Worker     // second idle period.
494*6777b538SAndroid Build Coastguard Worker     ScopedAllowThreadRecallForStackSamplingProfiler allow_thread_join;
495*6777b538SAndroid Build Coastguard Worker     Stop();
496*6777b538SAndroid Build Coastguard Worker   }
497*6777b538SAndroid Build Coastguard Worker 
498*6777b538SAndroid Build Coastguard Worker   DCHECK(!stack_buffer_);
499*6777b538SAndroid Build Coastguard Worker   stack_buffer_ = StackSampler::CreateStackBuffer();
500*6777b538SAndroid Build Coastguard Worker 
501*6777b538SAndroid Build Coastguard Worker   // The thread is not running. Start it and get associated runner. The task-
502*6777b538SAndroid Build Coastguard Worker   // runner has to be saved for future use because though it can be used from
503*6777b538SAndroid Build Coastguard Worker   // any thread, it can be acquired via task_runner() only on the created
504*6777b538SAndroid Build Coastguard Worker   // thread and the thread that creates it (i.e. this thread) for thread-safety
505*6777b538SAndroid Build Coastguard Worker   // reasons which are alleviated in SamplingThread by gating access to it with
506*6777b538SAndroid Build Coastguard Worker   // the |thread_execution_state_lock_|.
507*6777b538SAndroid Build Coastguard Worker   Start();
508*6777b538SAndroid Build Coastguard Worker   thread_execution_state_ = RUNNING;
509*6777b538SAndroid Build Coastguard Worker   thread_execution_state_task_runner_ = Thread::task_runner();
510*6777b538SAndroid Build Coastguard Worker 
511*6777b538SAndroid Build Coastguard Worker   // Detach the sampling thread from the "sequence" (i.e. thread) that
512*6777b538SAndroid Build Coastguard Worker   // started it so that it can be self-managed or stopped by another thread.
513*6777b538SAndroid Build Coastguard Worker   DetachFromSequence();
514*6777b538SAndroid Build Coastguard Worker 
515*6777b538SAndroid Build Coastguard Worker   return thread_execution_state_task_runner_;
516*6777b538SAndroid Build Coastguard Worker }
517*6777b538SAndroid Build Coastguard Worker 
518*6777b538SAndroid Build Coastguard Worker scoped_refptr<SingleThreadTaskRunner>
GetTaskRunner(ThreadExecutionState * out_state)519*6777b538SAndroid Build Coastguard Worker StackSamplingProfiler::SamplingThread::GetTaskRunner(
520*6777b538SAndroid Build Coastguard Worker     ThreadExecutionState* out_state) {
521*6777b538SAndroid Build Coastguard Worker   AutoLock lock(thread_execution_state_lock_);
522*6777b538SAndroid Build Coastguard Worker   if (out_state)
523*6777b538SAndroid Build Coastguard Worker     *out_state = thread_execution_state_;
524*6777b538SAndroid Build Coastguard Worker   if (thread_execution_state_ == RUNNING) {
525*6777b538SAndroid Build Coastguard Worker     // This shouldn't be called from the sampling thread as it's inefficient.
526*6777b538SAndroid Build Coastguard Worker     // Use GetTaskRunnerOnSamplingThread() instead.
527*6777b538SAndroid Build Coastguard Worker     DCHECK_NE(GetThreadId(), PlatformThread::CurrentId());
528*6777b538SAndroid Build Coastguard Worker     DCHECK(thread_execution_state_task_runner_);
529*6777b538SAndroid Build Coastguard Worker   } else {
530*6777b538SAndroid Build Coastguard Worker     DCHECK(!thread_execution_state_task_runner_);
531*6777b538SAndroid Build Coastguard Worker   }
532*6777b538SAndroid Build Coastguard Worker 
533*6777b538SAndroid Build Coastguard Worker   return thread_execution_state_task_runner_;
534*6777b538SAndroid Build Coastguard Worker }
535*6777b538SAndroid Build Coastguard Worker 
536*6777b538SAndroid Build Coastguard Worker scoped_refptr<SingleThreadTaskRunner>
GetTaskRunnerOnSamplingThread()537*6777b538SAndroid Build Coastguard Worker StackSamplingProfiler::SamplingThread::GetTaskRunnerOnSamplingThread() {
538*6777b538SAndroid Build Coastguard Worker   // This should be called only from the sampling thread as it has limited
539*6777b538SAndroid Build Coastguard Worker   // accessibility.
540*6777b538SAndroid Build Coastguard Worker   DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId());
541*6777b538SAndroid Build Coastguard Worker 
542*6777b538SAndroid Build Coastguard Worker   return Thread::task_runner();
543*6777b538SAndroid Build Coastguard Worker }
544*6777b538SAndroid Build Coastguard Worker 
FinishCollection(std::unique_ptr<CollectionContext> collection)545*6777b538SAndroid Build Coastguard Worker void StackSamplingProfiler::SamplingThread::FinishCollection(
546*6777b538SAndroid Build Coastguard Worker     std::unique_ptr<CollectionContext> collection) {
547*6777b538SAndroid Build Coastguard Worker   DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId());
548*6777b538SAndroid Build Coastguard Worker   DCHECK_EQ(0u, active_collections_.count(collection->collection_id));
549*6777b538SAndroid Build Coastguard Worker 
550*6777b538SAndroid Build Coastguard Worker   TimeDelta profile_duration = TimeTicks::Now() -
551*6777b538SAndroid Build Coastguard Worker                                collection->profile_start_time +
552*6777b538SAndroid Build Coastguard Worker                                collection->params.sampling_interval;
553*6777b538SAndroid Build Coastguard Worker 
554*6777b538SAndroid Build Coastguard Worker   collection->profile_builder->OnProfileCompleted(
555*6777b538SAndroid Build Coastguard Worker       profile_duration, collection->params.sampling_interval);
556*6777b538SAndroid Build Coastguard Worker 
557*6777b538SAndroid Build Coastguard Worker   // Signal that this collection is finished.
558*6777b538SAndroid Build Coastguard Worker   WaitableEvent* collection_finished = collection->finished;
559*6777b538SAndroid Build Coastguard Worker   // Ensure the collection is destroyed before signaling, so that it may
560*6777b538SAndroid Build Coastguard Worker   // not outlive StackSamplingProfiler.
561*6777b538SAndroid Build Coastguard Worker   collection.reset();
562*6777b538SAndroid Build Coastguard Worker   collection_finished->Signal();
563*6777b538SAndroid Build Coastguard Worker 
564*6777b538SAndroid Build Coastguard Worker   ScheduleShutdownIfIdle();
565*6777b538SAndroid Build Coastguard Worker }
566*6777b538SAndroid Build Coastguard Worker 
ScheduleShutdownIfIdle()567*6777b538SAndroid Build Coastguard Worker void StackSamplingProfiler::SamplingThread::ScheduleShutdownIfIdle() {
568*6777b538SAndroid Build Coastguard Worker   DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId());
569*6777b538SAndroid Build Coastguard Worker 
570*6777b538SAndroid Build Coastguard Worker   if (!active_collections_.empty())
571*6777b538SAndroid Build Coastguard Worker     return;
572*6777b538SAndroid Build Coastguard Worker 
573*6777b538SAndroid Build Coastguard Worker   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cpu_profiler"),
574*6777b538SAndroid Build Coastguard Worker                "StackSamplingProfiler::SamplingThread::ScheduleShutdownIfIdle");
575*6777b538SAndroid Build Coastguard Worker 
576*6777b538SAndroid Build Coastguard Worker   int add_events;
577*6777b538SAndroid Build Coastguard Worker   {
578*6777b538SAndroid Build Coastguard Worker     AutoLock lock(thread_execution_state_lock_);
579*6777b538SAndroid Build Coastguard Worker     if (thread_execution_state_disable_idle_shutdown_for_testing_)
580*6777b538SAndroid Build Coastguard Worker       return;
581*6777b538SAndroid Build Coastguard Worker     add_events = thread_execution_state_add_events_;
582*6777b538SAndroid Build Coastguard Worker   }
583*6777b538SAndroid Build Coastguard Worker 
584*6777b538SAndroid Build Coastguard Worker   GetTaskRunnerOnSamplingThread()->PostDelayedTask(
585*6777b538SAndroid Build Coastguard Worker       FROM_HERE,
586*6777b538SAndroid Build Coastguard Worker       BindOnce(&SamplingThread::ShutdownTask, Unretained(this), add_events),
587*6777b538SAndroid Build Coastguard Worker       Seconds(60));
588*6777b538SAndroid Build Coastguard Worker }
589*6777b538SAndroid Build Coastguard Worker 
AddAuxUnwinderTask(int collection_id,std::unique_ptr<Unwinder> unwinder)590*6777b538SAndroid Build Coastguard Worker void StackSamplingProfiler::SamplingThread::AddAuxUnwinderTask(
591*6777b538SAndroid Build Coastguard Worker     int collection_id,
592*6777b538SAndroid Build Coastguard Worker     std::unique_ptr<Unwinder> unwinder) {
593*6777b538SAndroid Build Coastguard Worker   DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId());
594*6777b538SAndroid Build Coastguard Worker 
595*6777b538SAndroid Build Coastguard Worker   auto loc = active_collections_.find(collection_id);
596*6777b538SAndroid Build Coastguard Worker   if (loc == active_collections_.end())
597*6777b538SAndroid Build Coastguard Worker     return;
598*6777b538SAndroid Build Coastguard Worker 
599*6777b538SAndroid Build Coastguard Worker   loc->second->sampler->AddAuxUnwinder(std::move(unwinder));
600*6777b538SAndroid Build Coastguard Worker }
601*6777b538SAndroid Build Coastguard Worker 
ApplyMetadataToPastSamplesTask(base::TimeTicks period_start,base::TimeTicks period_end,uint64_t name_hash,std::optional<int64_t> key,int64_t value,std::optional<PlatformThreadId> thread_id)602*6777b538SAndroid Build Coastguard Worker void StackSamplingProfiler::SamplingThread::ApplyMetadataToPastSamplesTask(
603*6777b538SAndroid Build Coastguard Worker     base::TimeTicks period_start,
604*6777b538SAndroid Build Coastguard Worker     base::TimeTicks period_end,
605*6777b538SAndroid Build Coastguard Worker     uint64_t name_hash,
606*6777b538SAndroid Build Coastguard Worker     std::optional<int64_t> key,
607*6777b538SAndroid Build Coastguard Worker     int64_t value,
608*6777b538SAndroid Build Coastguard Worker     std::optional<PlatformThreadId> thread_id) {
609*6777b538SAndroid Build Coastguard Worker   DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId());
610*6777b538SAndroid Build Coastguard Worker   MetadataRecorder::Item item(name_hash, key, thread_id, value);
611*6777b538SAndroid Build Coastguard Worker   for (auto& id_collection_pair : active_collections_) {
612*6777b538SAndroid Build Coastguard Worker     if (thread_id && id_collection_pair.second->thread_id != thread_id)
613*6777b538SAndroid Build Coastguard Worker       continue;
614*6777b538SAndroid Build Coastguard Worker     id_collection_pair.second->profile_builder->ApplyMetadataRetrospectively(
615*6777b538SAndroid Build Coastguard Worker         period_start, period_end, item);
616*6777b538SAndroid Build Coastguard Worker   }
617*6777b538SAndroid Build Coastguard Worker }
618*6777b538SAndroid Build Coastguard Worker 
AddProfileMetadataTask(uint64_t name_hash,std::optional<int64_t> key,int64_t value,std::optional<PlatformThreadId> thread_id)619*6777b538SAndroid Build Coastguard Worker void StackSamplingProfiler::SamplingThread::AddProfileMetadataTask(
620*6777b538SAndroid Build Coastguard Worker     uint64_t name_hash,
621*6777b538SAndroid Build Coastguard Worker     std::optional<int64_t> key,
622*6777b538SAndroid Build Coastguard Worker     int64_t value,
623*6777b538SAndroid Build Coastguard Worker     std::optional<PlatformThreadId> thread_id) {
624*6777b538SAndroid Build Coastguard Worker   DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId());
625*6777b538SAndroid Build Coastguard Worker   MetadataRecorder::Item item(name_hash, key, thread_id, value);
626*6777b538SAndroid Build Coastguard Worker   for (auto& id_collection_pair : active_collections_) {
627*6777b538SAndroid Build Coastguard Worker     if (thread_id && id_collection_pair.second->thread_id != thread_id) {
628*6777b538SAndroid Build Coastguard Worker       continue;
629*6777b538SAndroid Build Coastguard Worker     }
630*6777b538SAndroid Build Coastguard Worker     id_collection_pair.second->profile_builder->AddProfileMetadata(item);
631*6777b538SAndroid Build Coastguard Worker   }
632*6777b538SAndroid Build Coastguard Worker }
633*6777b538SAndroid Build Coastguard Worker 
AddCollectionTask(std::unique_ptr<CollectionContext> collection)634*6777b538SAndroid Build Coastguard Worker void StackSamplingProfiler::SamplingThread::AddCollectionTask(
635*6777b538SAndroid Build Coastguard Worker     std::unique_ptr<CollectionContext> collection) {
636*6777b538SAndroid Build Coastguard Worker   DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId());
637*6777b538SAndroid Build Coastguard Worker 
638*6777b538SAndroid Build Coastguard Worker   const int collection_id = collection->collection_id;
639*6777b538SAndroid Build Coastguard Worker   const TimeDelta initial_delay = collection->params.initial_delay;
640*6777b538SAndroid Build Coastguard Worker 
641*6777b538SAndroid Build Coastguard Worker   collection->sampler->Initialize();
642*6777b538SAndroid Build Coastguard Worker 
643*6777b538SAndroid Build Coastguard Worker   active_collections_.insert(
644*6777b538SAndroid Build Coastguard Worker       std::make_pair(collection_id, std::move(collection)));
645*6777b538SAndroid Build Coastguard Worker 
646*6777b538SAndroid Build Coastguard Worker   GetTaskRunnerOnSamplingThread()->PostDelayedTask(
647*6777b538SAndroid Build Coastguard Worker       FROM_HERE,
648*6777b538SAndroid Build Coastguard Worker       BindOnce(&SamplingThread::RecordSampleTask, Unretained(this),
649*6777b538SAndroid Build Coastguard Worker                collection_id),
650*6777b538SAndroid Build Coastguard Worker       initial_delay);
651*6777b538SAndroid Build Coastguard Worker 
652*6777b538SAndroid Build Coastguard Worker   // Another increment of "add events" serves to invalidate any pending
653*6777b538SAndroid Build Coastguard Worker   // shutdown tasks that may have been initiated between the Add() and this
654*6777b538SAndroid Build Coastguard Worker   // task running.
655*6777b538SAndroid Build Coastguard Worker   {
656*6777b538SAndroid Build Coastguard Worker     AutoLock lock(thread_execution_state_lock_);
657*6777b538SAndroid Build Coastguard Worker     ++thread_execution_state_add_events_;
658*6777b538SAndroid Build Coastguard Worker   }
659*6777b538SAndroid Build Coastguard Worker }
660*6777b538SAndroid Build Coastguard Worker 
RemoveCollectionTask(int collection_id)661*6777b538SAndroid Build Coastguard Worker void StackSamplingProfiler::SamplingThread::RemoveCollectionTask(
662*6777b538SAndroid Build Coastguard Worker     int collection_id) {
663*6777b538SAndroid Build Coastguard Worker   DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId());
664*6777b538SAndroid Build Coastguard Worker 
665*6777b538SAndroid Build Coastguard Worker   auto found = active_collections_.find(collection_id);
666*6777b538SAndroid Build Coastguard Worker   if (found == active_collections_.end())
667*6777b538SAndroid Build Coastguard Worker     return;
668*6777b538SAndroid Build Coastguard Worker 
669*6777b538SAndroid Build Coastguard Worker   // Remove |collection| from |active_collections_|.
670*6777b538SAndroid Build Coastguard Worker   std::unique_ptr<CollectionContext> collection = std::move(found->second);
671*6777b538SAndroid Build Coastguard Worker   size_t count = active_collections_.erase(collection_id);
672*6777b538SAndroid Build Coastguard Worker   DCHECK_EQ(1U, count);
673*6777b538SAndroid Build Coastguard Worker 
674*6777b538SAndroid Build Coastguard Worker   FinishCollection(std::move(collection));
675*6777b538SAndroid Build Coastguard Worker }
676*6777b538SAndroid Build Coastguard Worker 
RecordSampleTask(int collection_id)677*6777b538SAndroid Build Coastguard Worker void StackSamplingProfiler::SamplingThread::RecordSampleTask(
678*6777b538SAndroid Build Coastguard Worker     int collection_id) {
679*6777b538SAndroid Build Coastguard Worker   DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId());
680*6777b538SAndroid Build Coastguard Worker 
681*6777b538SAndroid Build Coastguard Worker   auto found = active_collections_.find(collection_id);
682*6777b538SAndroid Build Coastguard Worker 
683*6777b538SAndroid Build Coastguard Worker   // The task won't be found if it has been stopped.
684*6777b538SAndroid Build Coastguard Worker   if (found == active_collections_.end())
685*6777b538SAndroid Build Coastguard Worker     return;
686*6777b538SAndroid Build Coastguard Worker 
687*6777b538SAndroid Build Coastguard Worker   CollectionContext* collection = found->second.get();
688*6777b538SAndroid Build Coastguard Worker 
689*6777b538SAndroid Build Coastguard Worker   // If this is the first sample, the collection params need to be filled.
690*6777b538SAndroid Build Coastguard Worker   if (collection->sample_count == 0) {
691*6777b538SAndroid Build Coastguard Worker     collection->profile_start_time = TimeTicks::Now();
692*6777b538SAndroid Build Coastguard Worker     collection->next_sample_time = TimeTicks::Now();
693*6777b538SAndroid Build Coastguard Worker   }
694*6777b538SAndroid Build Coastguard Worker 
695*6777b538SAndroid Build Coastguard Worker   // Record a single sample.
696*6777b538SAndroid Build Coastguard Worker   collection->sampler->RecordStackFrames(stack_buffer_.get(),
697*6777b538SAndroid Build Coastguard Worker                                          collection->profile_builder.get(),
698*6777b538SAndroid Build Coastguard Worker                                          collection->thread_id);
699*6777b538SAndroid Build Coastguard Worker 
700*6777b538SAndroid Build Coastguard Worker   // Schedule the next sample recording if there is one.
701*6777b538SAndroid Build Coastguard Worker   if (++collection->sample_count < collection->params.samples_per_profile) {
702*6777b538SAndroid Build Coastguard Worker     collection->next_sample_time = GetNextSampleTimeImpl(
703*6777b538SAndroid Build Coastguard Worker         collection->next_sample_time, collection->params.sampling_interval,
704*6777b538SAndroid Build Coastguard Worker         TimeTicks::Now());
705*6777b538SAndroid Build Coastguard Worker     bool success = GetTaskRunnerOnSamplingThread()->PostDelayedTask(
706*6777b538SAndroid Build Coastguard Worker         FROM_HERE,
707*6777b538SAndroid Build Coastguard Worker         BindOnce(&SamplingThread::RecordSampleTask, Unretained(this),
708*6777b538SAndroid Build Coastguard Worker                  collection_id),
709*6777b538SAndroid Build Coastguard Worker         std::max(collection->next_sample_time - TimeTicks::Now(), TimeDelta()));
710*6777b538SAndroid Build Coastguard Worker     DCHECK(success);
711*6777b538SAndroid Build Coastguard Worker     return;
712*6777b538SAndroid Build Coastguard Worker   }
713*6777b538SAndroid Build Coastguard Worker 
714*6777b538SAndroid Build Coastguard Worker   // Take ownership of |collection| and remove it from the map.
715*6777b538SAndroid Build Coastguard Worker   std::unique_ptr<CollectionContext> owned_collection =
716*6777b538SAndroid Build Coastguard Worker       std::move(found->second);
717*6777b538SAndroid Build Coastguard Worker   size_t count = active_collections_.erase(collection_id);
718*6777b538SAndroid Build Coastguard Worker   DCHECK_EQ(1U, count);
719*6777b538SAndroid Build Coastguard Worker 
720*6777b538SAndroid Build Coastguard Worker   // All capturing has completed so finish the collection.
721*6777b538SAndroid Build Coastguard Worker   FinishCollection(std::move(owned_collection));
722*6777b538SAndroid Build Coastguard Worker }
723*6777b538SAndroid Build Coastguard Worker 
ShutdownTask(int add_events)724*6777b538SAndroid Build Coastguard Worker void StackSamplingProfiler::SamplingThread::ShutdownTask(int add_events) {
725*6777b538SAndroid Build Coastguard Worker   DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId());
726*6777b538SAndroid Build Coastguard Worker 
727*6777b538SAndroid Build Coastguard Worker   // Holding this lock ensures that any attempt to start another job will
728*6777b538SAndroid Build Coastguard Worker   // get postponed until |thread_execution_state_| is updated, thus eliminating
729*6777b538SAndroid Build Coastguard Worker   // the race in starting a new thread while the previous one is exiting.
730*6777b538SAndroid Build Coastguard Worker   AutoLock lock(thread_execution_state_lock_);
731*6777b538SAndroid Build Coastguard Worker 
732*6777b538SAndroid Build Coastguard Worker   // If the current count of creation requests doesn't match the passed count
733*6777b538SAndroid Build Coastguard Worker   // then other tasks have been created since this was posted. Abort shutdown.
734*6777b538SAndroid Build Coastguard Worker   if (thread_execution_state_add_events_ != add_events)
735*6777b538SAndroid Build Coastguard Worker     return;
736*6777b538SAndroid Build Coastguard Worker 
737*6777b538SAndroid Build Coastguard Worker   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cpu_profiler"),
738*6777b538SAndroid Build Coastguard Worker                "StackSamplingProfiler::SamplingThread::ShutdownTask");
739*6777b538SAndroid Build Coastguard Worker 
740*6777b538SAndroid Build Coastguard Worker   // There can be no new AddCollectionTasks at this point because creating
741*6777b538SAndroid Build Coastguard Worker   // those always increments "add events". There may be other requests, like
742*6777b538SAndroid Build Coastguard Worker   // Remove, but it's okay to schedule the thread to stop once they've been
743*6777b538SAndroid Build Coastguard Worker   // executed (i.e. "soon").
744*6777b538SAndroid Build Coastguard Worker   DCHECK(active_collections_.empty());
745*6777b538SAndroid Build Coastguard Worker   StopSoon();
746*6777b538SAndroid Build Coastguard Worker 
747*6777b538SAndroid Build Coastguard Worker   // StopSoon will have set the owning sequence (again) so it must be detached
748*6777b538SAndroid Build Coastguard Worker   // (again) in order for Stop/Start to be called (again) should more work
749*6777b538SAndroid Build Coastguard Worker   // come in. Holding the |thread_execution_state_lock_| ensures the necessary
750*6777b538SAndroid Build Coastguard Worker   // happens-after with regard to this detach and future Thread API calls.
751*6777b538SAndroid Build Coastguard Worker   DetachFromSequence();
752*6777b538SAndroid Build Coastguard Worker 
753*6777b538SAndroid Build Coastguard Worker   // Set the thread_state variable so the thread will be restarted when new
754*6777b538SAndroid Build Coastguard Worker   // work comes in. Remove the |thread_execution_state_task_runner_| to avoid
755*6777b538SAndroid Build Coastguard Worker   // confusion.
756*6777b538SAndroid Build Coastguard Worker   thread_execution_state_ = EXITING;
757*6777b538SAndroid Build Coastguard Worker   thread_execution_state_task_runner_ = nullptr;
758*6777b538SAndroid Build Coastguard Worker   stack_buffer_.reset();
759*6777b538SAndroid Build Coastguard Worker }
760*6777b538SAndroid Build Coastguard Worker 
CleanUp()761*6777b538SAndroid Build Coastguard Worker void StackSamplingProfiler::SamplingThread::CleanUp() {
762*6777b538SAndroid Build Coastguard Worker   DCHECK_EQ(GetThreadId(), PlatformThread::CurrentId());
763*6777b538SAndroid Build Coastguard Worker 
764*6777b538SAndroid Build Coastguard Worker   // There should be no collections remaining when the thread stops.
765*6777b538SAndroid Build Coastguard Worker   DCHECK(active_collections_.empty());
766*6777b538SAndroid Build Coastguard Worker 
767*6777b538SAndroid Build Coastguard Worker   // Let the parent clean up.
768*6777b538SAndroid Build Coastguard Worker   Thread::CleanUp();
769*6777b538SAndroid Build Coastguard Worker }
770*6777b538SAndroid Build Coastguard Worker 
771*6777b538SAndroid Build Coastguard Worker // StackSamplingProfiler ------------------------------------------------------
772*6777b538SAndroid Build Coastguard Worker 
773*6777b538SAndroid Build Coastguard Worker // static
Reset()774*6777b538SAndroid Build Coastguard Worker void StackSamplingProfiler::TestPeer::Reset() {
775*6777b538SAndroid Build Coastguard Worker   SamplingThread::TestPeer::Reset();
776*6777b538SAndroid Build Coastguard Worker }
777*6777b538SAndroid Build Coastguard Worker 
778*6777b538SAndroid Build Coastguard Worker // static
IsSamplingThreadRunning()779*6777b538SAndroid Build Coastguard Worker bool StackSamplingProfiler::TestPeer::IsSamplingThreadRunning() {
780*6777b538SAndroid Build Coastguard Worker   return SamplingThread::GetInstance()->IsRunning();
781*6777b538SAndroid Build Coastguard Worker }
782*6777b538SAndroid Build Coastguard Worker 
783*6777b538SAndroid Build Coastguard Worker // static
DisableIdleShutdown()784*6777b538SAndroid Build Coastguard Worker void StackSamplingProfiler::TestPeer::DisableIdleShutdown() {
785*6777b538SAndroid Build Coastguard Worker   SamplingThread::TestPeer::DisableIdleShutdown();
786*6777b538SAndroid Build Coastguard Worker }
787*6777b538SAndroid Build Coastguard Worker 
788*6777b538SAndroid Build Coastguard Worker // static
PerformSamplingThreadIdleShutdown(bool simulate_intervening_start)789*6777b538SAndroid Build Coastguard Worker void StackSamplingProfiler::TestPeer::PerformSamplingThreadIdleShutdown(
790*6777b538SAndroid Build Coastguard Worker     bool simulate_intervening_start) {
791*6777b538SAndroid Build Coastguard Worker   SamplingThread::TestPeer::ShutdownAssumingIdle(simulate_intervening_start);
792*6777b538SAndroid Build Coastguard Worker }
793*6777b538SAndroid Build Coastguard Worker 
794*6777b538SAndroid Build Coastguard Worker // static
GetNextSampleTime(TimeTicks scheduled_current_sample_time,TimeDelta sampling_interval,TimeTicks now)795*6777b538SAndroid Build Coastguard Worker TimeTicks StackSamplingProfiler::TestPeer::GetNextSampleTime(
796*6777b538SAndroid Build Coastguard Worker     TimeTicks scheduled_current_sample_time,
797*6777b538SAndroid Build Coastguard Worker     TimeDelta sampling_interval,
798*6777b538SAndroid Build Coastguard Worker     TimeTicks now) {
799*6777b538SAndroid Build Coastguard Worker   return GetNextSampleTimeImpl(scheduled_current_sample_time, sampling_interval,
800*6777b538SAndroid Build Coastguard Worker                                now);
801*6777b538SAndroid Build Coastguard Worker }
802*6777b538SAndroid Build Coastguard Worker 
803*6777b538SAndroid Build Coastguard Worker // static
804*6777b538SAndroid Build Coastguard Worker // The profiler is currently supported for Windows x64, macOS, iOS 64-bit,
805*6777b538SAndroid Build Coastguard Worker // Android ARM32 and ARM64, and ChromeOS x64 and ARM64.
IsSupportedForCurrentPlatform()806*6777b538SAndroid Build Coastguard Worker bool StackSamplingProfiler::IsSupportedForCurrentPlatform() {
807*6777b538SAndroid Build Coastguard Worker #if (BUILDFLAG(IS_WIN) && defined(ARCH_CPU_X86_64)) || BUILDFLAG(IS_MAC) || \
808*6777b538SAndroid Build Coastguard Worker     (BUILDFLAG(IS_IOS) && defined(ARCH_CPU_64_BITS)) ||                     \
809*6777b538SAndroid Build Coastguard Worker     (BUILDFLAG(IS_ANDROID) &&                                               \
810*6777b538SAndroid Build Coastguard Worker      ((defined(ARCH_CPU_ARMEL) && BUILDFLAG(ENABLE_ARM_CFI_TABLE)) ||       \
811*6777b538SAndroid Build Coastguard Worker       (defined(ARCH_CPU_ARM64) &&                                           \
812*6777b538SAndroid Build Coastguard Worker        BUILDFLAG(CAN_UNWIND_WITH_FRAME_POINTERS)))) ||                      \
813*6777b538SAndroid Build Coastguard Worker     (BUILDFLAG(IS_CHROMEOS) &&                                              \
814*6777b538SAndroid Build Coastguard Worker      (defined(ARCH_CPU_X86_64) || defined(ARCH_CPU_ARM64)))
815*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_WIN)
816*6777b538SAndroid Build Coastguard Worker   // Do not start the profiler when Application Verifier is in use; running them
817*6777b538SAndroid Build Coastguard Worker   // simultaneously can cause crashes and has no known use case.
818*6777b538SAndroid Build Coastguard Worker   if (GetModuleHandleA(base::win::kApplicationVerifierDllName))
819*6777b538SAndroid Build Coastguard Worker     return false;
820*6777b538SAndroid Build Coastguard Worker   // Checks if Trend Micro DLLs are loaded in process, so we can disable the
821*6777b538SAndroid Build Coastguard Worker   // profiler to avoid hitting their performance bug. See
822*6777b538SAndroid Build Coastguard Worker   // https://crbug.com/1018291 and https://crbug.com/1113832.
823*6777b538SAndroid Build Coastguard Worker   if (GetModuleHandleA("tmmon64.dll") || GetModuleHandleA("tmmonmgr64.dll"))
824*6777b538SAndroid Build Coastguard Worker     return false;
825*6777b538SAndroid Build Coastguard Worker #endif
826*6777b538SAndroid Build Coastguard Worker   return true;
827*6777b538SAndroid Build Coastguard Worker #else
828*6777b538SAndroid Build Coastguard Worker   return false;
829*6777b538SAndroid Build Coastguard Worker #endif
830*6777b538SAndroid Build Coastguard Worker }
831*6777b538SAndroid Build Coastguard Worker 
StackSamplingProfiler(SamplingProfilerThreadToken thread_token,const SamplingParams & params,std::unique_ptr<ProfileBuilder> profile_builder,UnwindersFactory core_unwinders_factory,RepeatingClosure record_sample_callback,StackSamplerTestDelegate * test_delegate)832*6777b538SAndroid Build Coastguard Worker StackSamplingProfiler::StackSamplingProfiler(
833*6777b538SAndroid Build Coastguard Worker     SamplingProfilerThreadToken thread_token,
834*6777b538SAndroid Build Coastguard Worker     const SamplingParams& params,
835*6777b538SAndroid Build Coastguard Worker     std::unique_ptr<ProfileBuilder> profile_builder,
836*6777b538SAndroid Build Coastguard Worker     UnwindersFactory core_unwinders_factory,
837*6777b538SAndroid Build Coastguard Worker     RepeatingClosure record_sample_callback,
838*6777b538SAndroid Build Coastguard Worker     StackSamplerTestDelegate* test_delegate)
839*6777b538SAndroid Build Coastguard Worker     : thread_token_(thread_token),
840*6777b538SAndroid Build Coastguard Worker       params_(params),
841*6777b538SAndroid Build Coastguard Worker       profile_builder_(std::move(profile_builder)),
842*6777b538SAndroid Build Coastguard Worker       sampler_(StackSampler::Create(thread_token,
843*6777b538SAndroid Build Coastguard Worker                                     profile_builder_->GetModuleCache(),
844*6777b538SAndroid Build Coastguard Worker                                     std::move(core_unwinders_factory),
845*6777b538SAndroid Build Coastguard Worker                                     std::move(record_sample_callback),
846*6777b538SAndroid Build Coastguard Worker                                     test_delegate)),
847*6777b538SAndroid Build Coastguard Worker       // The event starts "signaled" so code knows it's safe to start thread
848*6777b538SAndroid Build Coastguard Worker       // and "manual" so that it can be waited in multiple places.
849*6777b538SAndroid Build Coastguard Worker       profiling_inactive_(kResetPolicy, WaitableEvent::InitialState::SIGNALED),
850*6777b538SAndroid Build Coastguard Worker       profiler_id_(kNullProfilerId) {
851*6777b538SAndroid Build Coastguard Worker   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cpu_profiler"),
852*6777b538SAndroid Build Coastguard Worker                "StackSamplingProfiler::StackSamplingProfiler");
853*6777b538SAndroid Build Coastguard Worker   DCHECK(profile_builder_);
854*6777b538SAndroid Build Coastguard Worker }
855*6777b538SAndroid Build Coastguard Worker 
~StackSamplingProfiler()856*6777b538SAndroid Build Coastguard Worker StackSamplingProfiler::~StackSamplingProfiler() {
857*6777b538SAndroid Build Coastguard Worker   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cpu_profiler"),
858*6777b538SAndroid Build Coastguard Worker                "StackSamplingProfiler::~StackSamplingProfiler");
859*6777b538SAndroid Build Coastguard Worker 
860*6777b538SAndroid Build Coastguard Worker   // Stop returns immediately but the shutdown runs asynchronously. There is a
861*6777b538SAndroid Build Coastguard Worker   // non-zero probability that one more sample will be taken after this call
862*6777b538SAndroid Build Coastguard Worker   // returns.
863*6777b538SAndroid Build Coastguard Worker   Stop();
864*6777b538SAndroid Build Coastguard Worker 
865*6777b538SAndroid Build Coastguard Worker   // The behavior of sampling a thread that has exited is undefined and could
866*6777b538SAndroid Build Coastguard Worker   // cause Bad Things(tm) to occur. The safety model provided by this class is
867*6777b538SAndroid Build Coastguard Worker   // that an instance of this object is expected to live at least as long as
868*6777b538SAndroid Build Coastguard Worker   // the thread it is sampling. However, because the sampling is performed
869*6777b538SAndroid Build Coastguard Worker   // asynchronously by the SamplingThread, there is no way to guarantee this
870*6777b538SAndroid Build Coastguard Worker   // is true without waiting for it to signal that it has finished.
871*6777b538SAndroid Build Coastguard Worker   //
872*6777b538SAndroid Build Coastguard Worker   // The wait time should, at most, be only as long as it takes to collect one
873*6777b538SAndroid Build Coastguard Worker   // sample (~200us) or none at all if sampling has already completed.
874*6777b538SAndroid Build Coastguard Worker   ScopedAllowBaseSyncPrimitivesOutsideBlockingScope allow_wait;
875*6777b538SAndroid Build Coastguard Worker   profiling_inactive_.Wait();
876*6777b538SAndroid Build Coastguard Worker }
877*6777b538SAndroid Build Coastguard Worker 
Start()878*6777b538SAndroid Build Coastguard Worker void StackSamplingProfiler::Start() {
879*6777b538SAndroid Build Coastguard Worker   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cpu_profiler"),
880*6777b538SAndroid Build Coastguard Worker                "StackSamplingProfiler::Start");
881*6777b538SAndroid Build Coastguard Worker 
882*6777b538SAndroid Build Coastguard Worker   // Multiple calls to Start() for a single StackSamplingProfiler object is not
883*6777b538SAndroid Build Coastguard Worker   // allowed. If profile_builder_ is nullptr, then Start() has been called
884*6777b538SAndroid Build Coastguard Worker   // already.
885*6777b538SAndroid Build Coastguard Worker   DCHECK(profile_builder_);
886*6777b538SAndroid Build Coastguard Worker 
887*6777b538SAndroid Build Coastguard Worker   // |sampler_| will be null if sampling isn't supported on the current
888*6777b538SAndroid Build Coastguard Worker   // platform.
889*6777b538SAndroid Build Coastguard Worker   if (!sampler_)
890*6777b538SAndroid Build Coastguard Worker     return;
891*6777b538SAndroid Build Coastguard Worker 
892*6777b538SAndroid Build Coastguard Worker   // The IsSignaled() check below requires that the WaitableEvent be manually
893*6777b538SAndroid Build Coastguard Worker   // reset, to avoid signaling the event in IsSignaled() itself.
894*6777b538SAndroid Build Coastguard Worker   static_assert(kResetPolicy == WaitableEvent::ResetPolicy::MANUAL,
895*6777b538SAndroid Build Coastguard Worker                 "The reset policy must be set to MANUAL");
896*6777b538SAndroid Build Coastguard Worker 
897*6777b538SAndroid Build Coastguard Worker   // If a previous profiling phase is still winding down, wait for it to
898*6777b538SAndroid Build Coastguard Worker   // complete. We can't use task posting for this coordination because the
899*6777b538SAndroid Build Coastguard Worker   // thread owning the profiler may not have a message loop.
900*6777b538SAndroid Build Coastguard Worker   if (!profiling_inactive_.IsSignaled())
901*6777b538SAndroid Build Coastguard Worker     profiling_inactive_.Wait();
902*6777b538SAndroid Build Coastguard Worker   profiling_inactive_.Reset();
903*6777b538SAndroid Build Coastguard Worker 
904*6777b538SAndroid Build Coastguard Worker   DCHECK_EQ(kNullProfilerId, profiler_id_);
905*6777b538SAndroid Build Coastguard Worker   profiler_id_ = SamplingThread::GetInstance()->Add(
906*6777b538SAndroid Build Coastguard Worker       std::make_unique<SamplingThread::CollectionContext>(
907*6777b538SAndroid Build Coastguard Worker           thread_token_.id, params_, &profiling_inactive_, std::move(sampler_),
908*6777b538SAndroid Build Coastguard Worker           std::move(profile_builder_)));
909*6777b538SAndroid Build Coastguard Worker   DCHECK_NE(kNullProfilerId, profiler_id_);
910*6777b538SAndroid Build Coastguard Worker 
911*6777b538SAndroid Build Coastguard Worker   TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cpu_profiler"),
912*6777b538SAndroid Build Coastguard Worker                "StackSamplingProfiler::Started", "profiler_id", profiler_id_);
913*6777b538SAndroid Build Coastguard Worker }
914*6777b538SAndroid Build Coastguard Worker 
Stop()915*6777b538SAndroid Build Coastguard Worker void StackSamplingProfiler::Stop() {
916*6777b538SAndroid Build Coastguard Worker   TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cpu_profiler"),
917*6777b538SAndroid Build Coastguard Worker                "StackSamplingProfiler::Stop", "profiler_id", profiler_id_);
918*6777b538SAndroid Build Coastguard Worker 
919*6777b538SAndroid Build Coastguard Worker   SamplingThread::GetInstance()->Remove(profiler_id_);
920*6777b538SAndroid Build Coastguard Worker   profiler_id_ = kNullProfilerId;
921*6777b538SAndroid Build Coastguard Worker }
922*6777b538SAndroid Build Coastguard Worker 
AddAuxUnwinder(std::unique_ptr<Unwinder> unwinder)923*6777b538SAndroid Build Coastguard Worker void StackSamplingProfiler::AddAuxUnwinder(std::unique_ptr<Unwinder> unwinder) {
924*6777b538SAndroid Build Coastguard Worker   if (profiler_id_ == kNullProfilerId) {
925*6777b538SAndroid Build Coastguard Worker     // We haven't started sampling, and so we can add |unwinder| to the sampler
926*6777b538SAndroid Build Coastguard Worker     // directly
927*6777b538SAndroid Build Coastguard Worker     if (sampler_)
928*6777b538SAndroid Build Coastguard Worker       sampler_->AddAuxUnwinder(std::move(unwinder));
929*6777b538SAndroid Build Coastguard Worker     return;
930*6777b538SAndroid Build Coastguard Worker   }
931*6777b538SAndroid Build Coastguard Worker 
932*6777b538SAndroid Build Coastguard Worker   SamplingThread::GetInstance()->AddAuxUnwinder(profiler_id_,
933*6777b538SAndroid Build Coastguard Worker                                                 std::move(unwinder));
934*6777b538SAndroid Build Coastguard Worker }
935*6777b538SAndroid Build Coastguard Worker 
936*6777b538SAndroid Build Coastguard Worker // static
ApplyMetadataToPastSamples(base::TimeTicks period_start,base::TimeTicks period_end,uint64_t name_hash,std::optional<int64_t> key,int64_t value,std::optional<PlatformThreadId> thread_id)937*6777b538SAndroid Build Coastguard Worker void StackSamplingProfiler::ApplyMetadataToPastSamples(
938*6777b538SAndroid Build Coastguard Worker     base::TimeTicks period_start,
939*6777b538SAndroid Build Coastguard Worker     base::TimeTicks period_end,
940*6777b538SAndroid Build Coastguard Worker     uint64_t name_hash,
941*6777b538SAndroid Build Coastguard Worker     std::optional<int64_t> key,
942*6777b538SAndroid Build Coastguard Worker     int64_t value,
943*6777b538SAndroid Build Coastguard Worker     std::optional<PlatformThreadId> thread_id) {
944*6777b538SAndroid Build Coastguard Worker   SamplingThread::GetInstance()->ApplyMetadataToPastSamples(
945*6777b538SAndroid Build Coastguard Worker       period_start, period_end, name_hash, key, value, thread_id);
946*6777b538SAndroid Build Coastguard Worker }
947*6777b538SAndroid Build Coastguard Worker 
948*6777b538SAndroid Build Coastguard Worker // static
AddProfileMetadata(uint64_t name_hash,int64_t key,int64_t value,std::optional<PlatformThreadId> thread_id)949*6777b538SAndroid Build Coastguard Worker void StackSamplingProfiler::AddProfileMetadata(
950*6777b538SAndroid Build Coastguard Worker     uint64_t name_hash,
951*6777b538SAndroid Build Coastguard Worker     int64_t key,
952*6777b538SAndroid Build Coastguard Worker     int64_t value,
953*6777b538SAndroid Build Coastguard Worker     std::optional<PlatformThreadId> thread_id) {
954*6777b538SAndroid Build Coastguard Worker   SamplingThread::GetInstance()->AddProfileMetadata(name_hash, key, value,
955*6777b538SAndroid Build Coastguard Worker                                                     thread_id);
956*6777b538SAndroid Build Coastguard Worker }
957*6777b538SAndroid Build Coastguard Worker 
958*6777b538SAndroid Build Coastguard Worker }  // namespace base
959