blob: 8579213985f2cc903831d7cf84fc942877cb7718 [file] [log] [blame]
Eric Secklerde589952019-10-17 12:46:07 +01001/*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PROTO_IMPORTER_MODULE_H_
18#define SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PROTO_IMPORTER_MODULE_H_
19
20#include "perfetto/ext/base/optional.h"
21#include "perfetto/trace_processor/status.h"
Eric Seckler5c7866e2019-10-18 08:38:16 +010022#include "src/trace_processor/trace_blob_view.h"
Eric Secklerde589952019-10-17 12:46:07 +010023
Eric Secklerde589952019-10-17 12:46:07 +010024namespace perfetto {
Eric Secklerd2af9892019-11-01 10:10:53 +000025
26namespace protos {
27namespace pbzero {
28class TraceConfig_Decoder;
29class TracePacket_Decoder;
30} // namespace pbzero
31} // namespace protos
32
Eric Secklerde589952019-10-17 12:46:07 +010033namespace trace_processor {
34
Eric Seckler771960c2019-10-22 15:37:12 +010035class PacketSequenceState;
Eric Secklerde589952019-10-17 12:46:07 +010036struct TimestampedTracePiece;
37class TraceProcessorContext;
38
39// This file contains helper and base class templates for
40// ProtoTraceTokenizer/Parser modules. A module implements support for a subset
41// of features of the TracePacket proto format. Modules inherit from
42// ProtoImporterModuleBase, and should be instantiated using the
43// ProtoImporterModule<> wrapper template in trace_processor_context.h.
44//
45// To add and integrate a new module:
46// (1) Add MyModule as a subclass of ProtoImporterModuleBase<IsEnabled>,
47// defining the TokenizePacket() and/or ParsePacket() methods.
48// Typically, a build-time macro will inform the value of IsEnabled.
49// See ftrace_module.h for an example.
Eric Seckler87ede882019-10-18 10:48:36 +010050// (2) Add a member of type std::unique_ptr<ProtoImporterModule<MyModule>> to
51// TraceProcessorContext (trace_processor_context.h) and init it from
52// TraceProcessorImpl() and appropriate tests.
53// (3) Add an include of my_module.h and calls to your module's TokenizePacket /
Eric Secklerde589952019-10-17 12:46:07 +010054// ParsePacket methods in ProtoTraceTokenizer and/or ProtoTraceParser
55// (proxying via the wrapper).
56
57class ModuleResult {
58 public:
Eric Seckler87ede882019-10-18 10:48:36 +010059 // Allow auto conversion from util::Status to Handled / Error result.
60 ModuleResult(util::Status status)
61 : ignored_(false),
62 error_(status.ok() ? base::nullopt
63 : base::make_optional(status.message())) {}
64
Eric Secklerde589952019-10-17 12:46:07 +010065 // Constructs a result that indicates the module ignored the packet and is
66 // deferring the handling of the packet to other modules.
67 static ModuleResult Ignored() { return ModuleResult(true); }
68
69 // Constructs a result that indicates the module handled the packet. Other
70 // modules will not be notified about the packet.
71 static ModuleResult Handled() { return ModuleResult(false); }
72
73 // Constructs a result that indicates an error condition while handling the
74 // packet. Other modules will not be notified about the packet.
75 static ModuleResult Error(const std::string& message) {
76 return ModuleResult(message);
77 }
78
79 bool ignored() const { return ignored_; }
Eric Seckler87ede882019-10-18 10:48:36 +010080 bool ok() const { return !error_.has_value(); }
Eric Secklerde589952019-10-17 12:46:07 +010081 const std::string& message() const { return *error_; }
82
83 util::Status ToStatus() const {
84 PERFETTO_DCHECK(!ignored_);
85 if (error_)
86 return util::Status(*error_);
87 return util::OkStatus();
88 }
89
90 private:
Eric Seckler87ede882019-10-18 10:48:36 +010091 explicit ModuleResult(bool ignored) : ignored_(ignored) {}
92 explicit ModuleResult(const std::string& error)
93 : ignored_(false), error_(error) {}
Eric Secklerde589952019-10-17 12:46:07 +010094
95 bool ignored_;
96 base::Optional<std::string> error_;
97};
98
99// Wrapper class for a module. This wrapper allows modules to be disabled
100// disabled at compile time to remove support for its features from the trace
101// processor.
102//
103// The trace processor will instantiate enabled modules for each
104// TraceProcessorContext. The tokenizer and parser notify individual modules
105// about trace data by calling their respective methods via the wrapper class.
106// If the module is enabled, the wrapper will forward the call to the module
107// implementation. This way, we avoid virtual methods, so that calling any of
108// the module's methods is zero overhead - they can be inlined by the compiler
109// at callsites directly.
110template <class ModuleType>
111class ProtoImporterModule {
112 public:
113 ProtoImporterModule(TraceProcessorContext* context) {
114 if (ModuleType::kEnabled)
115 impl_.reset(new ModuleType(context));
116 }
117
118 // ModuleType may specify methods with the signatures below.
119 // ProtoImporterModule<ModuleType> acts as a wrapper for these methods.
120 // ModuleType only needs to specify the methods that
121 // ProtoTraceParser/Tokenizer actually calls on the respective module.
122
123 // Wraps ModuleType::TokenizePacket(). If the module is disabled, compiles
124 // into a noop in optimized builds. Called by ProtoTraceTokenizer for each
125 // TracePacket during the tokenization stage, i.e. before sorting. If this
126 // returns a result other than ModuleResult::Ignored(), tokenization of the
127 // packet will be aborted after the module.
128 ModuleResult TokenizePacket(
Eric Secklerd2af9892019-11-01 10:10:53 +0000129 const protos::pbzero::TracePacket_Decoder& decoder,
Eric Seckler5c7866e2019-10-18 08:38:16 +0100130 TraceBlobView* packet,
Eric Seckler771960c2019-10-22 15:37:12 +0100131 int64_t packet_timestamp,
132 PacketSequenceState* state) {
133 if (ModuleType::kEnabled) {
134 return impl_->TokenizePacket(decoder, packet, packet_timestamp, state);
135 }
Eric Secklerde589952019-10-17 12:46:07 +0100136 return ModuleResult::Ignored();
137 }
138
139 // Wraps ModuleType::ParsePacket(). If the module is disabled, compiles into a
140 // noop in optimized builds. Called by ProtoTraceParser for each non-ftrace
141 // TracePacket after the sorting stage. If this returns a result other than
142 // ModuleResult::Ignored(), parsing of the packet will be aborted after the
143 // module.
Eric Secklerd2af9892019-11-01 10:10:53 +0000144 ModuleResult ParsePacket(const protos::pbzero::TracePacket_Decoder& decoder,
Eric Secklerde589952019-10-17 12:46:07 +0100145 const TimestampedTracePiece& ttp) {
146 if (ModuleType::kEnabled)
147 return impl_->ParsePacket(decoder, ttp);
148 return ModuleResult::Ignored();
149 }
150
Eric Secklerab0604c2019-10-25 10:12:07 +0100151 // Wraps ModuleType::ParseTraceConfig(). If the module is disabled, compiles
152 // into a noop in optimized builds. Called by ProtoTraceParser for trace
153 // config packets after the sorting stage.
154 ModuleResult ParseTraceConfig(
Eric Secklerd2af9892019-11-01 10:10:53 +0000155 const protos::pbzero::TraceConfig_Decoder& decoder) {
Eric Secklerab0604c2019-10-25 10:12:07 +0100156 if (ModuleType::kEnabled)
157 return impl_->ParseTraceConfig(decoder);
158 return ModuleResult::Ignored();
159 }
160
Eric Secklerde589952019-10-17 12:46:07 +0100161 // For FtraceModule only. Wraps ModuleType::ParseFtracePacket(). If the module
162 // is disabled, compiles into a noop in optimized builds. Called by
163 // ProtoTraceParser for each ftrace TracePacket after the sorting stage.
164 // Ftrace packets are handled specially here because they are sorted in
165 // separate queues per CPU. If this returns a result other than
166 // ModuleResult::Ignored(), parsing of the packet will be aborted after the
167 // module.
168 ModuleResult ParseFtracePacket(uint32_t cpu,
169 const TimestampedTracePiece& ttp) {
170 if (ModuleType::kEnabled)
171 return impl_->ParseFtracePacket(cpu, ttp);
172 return ModuleResult::Ignored();
173 }
174
175 private:
176 // Only initialized if the module is enabled.
177 std::unique_ptr<ModuleType> impl_;
178};
179
180// Base class for a proto trace module that can be disabled at compile time.
181// Typically, a build-time macro will inform the value of IsEnabled.
182template <int IsEnabled>
183class ProtoImporterModuleBase {
184 public:
185 static constexpr bool kEnabled = static_cast<bool>(IsEnabled);
186
187 explicit ProtoImporterModuleBase(TraceProcessorContext* context)
188 : context_(context) {}
189 ~ProtoImporterModuleBase() {}
190
191 // See ProtoTraceModule<> for the public methods subclasses may implement.
192
193 protected:
194 TraceProcessorContext* context_;
195};
196
Mikhail Khokhlov785af542019-12-06 13:45:10 +0000197// This is a new module superclass that allows registering modules at runtime.
198// To add and integrate a new module:
199// (1) Add MyModule as a subclass of NewProtoImporterModule,
200// overriding the TokenizePacket(), ParsePacket() and/or ParseTraceConfig()
201// methods.
202// (2) In the constructor call the RegisterForField method for every field
203// that the module knows how to handle.
204// See GraphicsEventModule for an example.
205// TODO(b/141459049): Rename this to ProtoImporterModule after all modules
206// are based on it.
207class NewProtoImporterModule {
208 public:
209 NewProtoImporterModule();
210
211 virtual ~NewProtoImporterModule();
212
213 // Called by ProtoTraceTokenizer during the tokenization stage, i.e. before
214 // sorting. It's called for each TracePacket that contains fields for which
215 // the module was registered. If this returns a result other than
216 // ModuleResult::Ignored(), tokenization of the packet will be aborted after
217 // the module.
218 virtual ModuleResult TokenizePacket(
219 const protos::pbzero::TracePacket_Decoder&,
220 TraceBlobView* packet,
221 int64_t packet_timestamp,
222 PacketSequenceState*,
223 uint32_t field_id);
224
225 // Called by ProtoTraceParser after the sorting stage for each non-ftrace
226 // TracePacket that contains fields for which the module was registered.
227 virtual void ParsePacket(const protos::pbzero::TracePacket_Decoder&,
228 const TimestampedTracePiece&,
229 uint32_t field_id);
230
231 // Called by ProtoTraceParser for trace config packets after the sorting
232 // stage, on all existing modules.
233 virtual void ParseTraceConfig(const protos::pbzero::TraceConfig_Decoder&);
234
235 protected:
236 void RegisterForField(uint32_t field_id, TraceProcessorContext*);
237};
238
Eric Secklerde589952019-10-17 12:46:07 +0100239} // namespace trace_processor
240} // namespace perfetto
241
242#endif // SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PROTO_IMPORTER_MODULE_H_