1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef SERVICES_TRACING_PUBLIC_CPP_STACK_SAMPLING_TRACING_SAMPLER_PROFILER_H_
6 #define SERVICES_TRACING_PUBLIC_CPP_STACK_SAMPLING_TRACING_SAMPLER_PROFILER_H_
7 
8 #include <memory>
9 #include <string>
10 #include <utility>
11 #include <vector>
12 
13 #include "base/callback.h"
14 #include "base/component_export.h"
15 #include "base/debug/debugging_buildflags.h"
16 #include "base/macros.h"
17 #include "base/memory/weak_ptr.h"
18 #include "base/profiler/sampling_profiler_thread_token.h"
19 #include "base/profiler/stack_sampling_profiler.h"
20 #include "base/sequence_checker.h"
21 #include "base/threading/platform_thread.h"
22 #include "build/build_config.h"
23 #include "services/tracing/public/cpp/perfetto/interning_index.h"
24 #include "third_party/perfetto/include/perfetto/ext/tracing/core/trace_writer.h"
25 
26 namespace tracing {
27 
28 class PerfettoProducer;
29 
30 // This class is a bridge between the base stack sampling profiler and chrome
31 // tracing. It's listening to TraceLog enabled/disabled events and it's starting
32 // a stack profiler on the current thread if needed. The sampling profiler is
33 // lazily instantiated when tracing is activated and released when tracing is
34 // disabled.
35 //
36 // The TracingSamplerProfiler must be created and destroyed on the sampled
37 // thread. The tracelog observers can be called on any thread which force the
38 // field |profiler_| to be thread-safe.
COMPONENT_EXPORT(TRACING_CPP)39 class COMPONENT_EXPORT(TRACING_CPP) TracingSamplerProfiler {
40  public:
41   // This class will receive the sampling profiler stackframes and output them
42   // to the chrome trace via an event. Exposed for testing.
43   class COMPONENT_EXPORT(TRACING_CPP) TracingProfileBuilder
44       : public base::ProfileBuilder {
45    public:
46     TracingProfileBuilder(
47         base::PlatformThreadId sampled_thread_id,
48         std::unique_ptr<perfetto::TraceWriter> trace_writer,
49         bool should_enable_filtering,
50         const base::RepeatingClosure& sample_callback_for_testing =
51             base::RepeatingClosure());
52     ~TracingProfileBuilder() override;
53 
54     // base::ProfileBuilder
55     base::ModuleCache* GetModuleCache() override;
56     void OnSampleCompleted(std::vector<base::Frame> frames,
57                            base::TimeTicks sample_timestamp) override;
58     void OnProfileCompleted(base::TimeDelta profile_duration,
59                             base::TimeDelta sampling_period) override {}
60 
61     void SetTraceWriter(std::unique_ptr<perfetto::TraceWriter> trace_writer);
62 
63    private:
64     struct BufferedSample {
65       BufferedSample(base::TimeTicks, std::vector<base::Frame>&&);
66       BufferedSample(BufferedSample&& other);
67       ~BufferedSample();
68 
69       base::TimeTicks timestamp;
70       std::vector<base::Frame> sample;
71 
72       DISALLOW_COPY_AND_ASSIGN(BufferedSample);
73     };
74 
75     InterningID GetCallstackIDAndMaybeEmit(
76         const std::vector<base::Frame>& frames,
77         perfetto::TraceWriter::TracePacketHandle* trace_packet);
78     void WriteSampleToTrace(const BufferedSample& sample);
79 
80     // We usually sample at 50ms, and expect that tracing should have started in
81     // 10s.
82     constexpr static size_t kMaxBufferedSamples = 200;
83     std::vector<BufferedSample> buffered_samples_;
84 
85     base::ModuleCache module_cache_;
86     const base::PlatformThreadId sampled_thread_id_;
87     base::Lock trace_writer_lock_;
88     std::unique_ptr<perfetto::TraceWriter> trace_writer_;
89     InterningIndex<TypeList<size_t>, SizeList<1024>> interned_callstacks_{};
90     InterningIndex<TypeList<std::pair<std::string, std::string>,
91                             std::pair<uintptr_t, std::string>>,
92                    SizeList<1024, 1024>>
93         interned_frames_{};
94     InterningIndex<TypeList<std::string>, SizeList<1024>>
95         interned_frame_names_{};
96     InterningIndex<TypeList<std::string>, SizeList<1024>>
97         interned_module_names_{};
98     InterningIndex<TypeList<std::string>, SizeList<1024>>
99         interned_module_ids_{};
100     InterningIndex<TypeList<uintptr_t>, SizeList<1024>> interned_modules_{};
101     bool reset_incremental_state_ = true;
102     uint32_t last_incremental_state_reset_id_ = 0;
103     int32_t last_emitted_process_priority_ = -1;
104     base::TimeTicks last_timestamp_;
105     const bool should_enable_filtering_;
106     base::RepeatingClosure sample_callback_for_testing_;
107   };
108 
109   // Creates sampling profiler on main thread. The profiler *must* be
110   // destroyed prior to process shutdown.
111   static std::unique_ptr<TracingSamplerProfiler> CreateOnMainThread();
112 
113   // Sets up tracing sampling profiler on a child thread. The profiler will be
114   // stored in SequencedLocalStorageSlot and will be destroyed with the thread
115   // task runner.
116   static void CreateOnChildThread();
117 
118   // Registers the TracingSamplerProfiler as a Perfetto data source
119   static void RegisterDataSource();
120 
121   // For tests.
122   static void SetupStartupTracingForTesting();
123   static void DeleteOnChildThreadForTesting();
124   static void StartTracingForTesting(tracing::PerfettoProducer* producer);
125   static void StopTracingForTesting();
126   static void MangleModuleIDIfNeeded(std::string* module_id);
127 
128   // Returns whether of not the sampler profiling is able to unwind the stack
129   // on this platform.
130   constexpr static bool IsStackUnwindingSupported() {
131 #if defined(OS_MACOSX) || defined(OS_WIN) && defined(_WIN64) ||     \
132     (defined(OS_ANDROID) && BUILDFLAG(CAN_UNWIND_WITH_CFI_TABLE) && \
133      defined(OFFICIAL_BUILD))
134     return true;
135 #else
136     return false;
137 #endif
138   }
139 
140   explicit TracingSamplerProfiler(
141       base::SamplingProfilerThreadToken sampled_thread_token);
142   virtual ~TracingSamplerProfiler();
143 
144   // The given callback will be called for every received sample, and can be
145   // called on any thread. Must be called before tracing is started.
146   void SetSampleCallbackForTesting(
147       const base::RepeatingClosure& sample_callback_for_testing);
148 
149   void StartTracing(std::unique_ptr<perfetto::TraceWriter> trace_writer,
150                     bool should_enable_filtering);
151   void StopTracing();
152 
153  private:
154   const base::SamplingProfilerThreadToken sampled_thread_token_;
155 
156   base::Lock lock_;
157   std::unique_ptr<base::StackSamplingProfiler> profiler_;  // under |lock_|
158   TracingProfileBuilder* profile_builder_ = nullptr;
159   base::RepeatingClosure sample_callback_for_testing_;
160 
161   DISALLOW_COPY_AND_ASSIGN(TracingSamplerProfiler);
162 };
163 
164 }  // namespace tracing
165 
166 #endif  // SERVICES_TRACING_PUBLIC_CPP_STACK_SAMPLING_TRACING_SAMPLER_PROFILER_H_
167