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