1 /*
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 #include "src/trace_processor/importers/proto/android_probes_module.h"
18
19 #include <cinttypes>
20 #include <cstdint>
21 #include <string>
22 #include <utility>
23 #include <vector>
24
25 #include "perfetto/base/logging.h"
26 #include "perfetto/ext/base/string_utils.h"
27 #include "perfetto/ext/base/string_view.h"
28 #include "perfetto/protozero/field.h"
29 #include "perfetto/protozero/scattered_heap_buffer.h"
30 #include "perfetto/public/compiler.h"
31 #include "perfetto/trace_processor/ref_counted.h"
32 #include "perfetto/trace_processor/trace_blob.h"
33 #include "src/trace_processor/importers/common/args_tracker.h"
34 #include "src/trace_processor/importers/common/parser_types.h"
35 #include "src/trace_processor/importers/common/track_tracker.h"
36 #include "src/trace_processor/importers/common/tracks.h"
37 #include "src/trace_processor/importers/common/tracks_common.h"
38 #include "src/trace_processor/importers/proto/android_probes_parser.h"
39 #include "src/trace_processor/importers/proto/android_probes_tracker.h"
40 #include "src/trace_processor/importers/proto/packet_sequence_state_generation.h"
41 #include "src/trace_processor/importers/proto/proto_importer_module.h"
42 #include "src/trace_processor/sorter/trace_sorter.h"
43 #include "src/trace_processor/storage/stats.h"
44 #include "src/trace_processor/storage/trace_storage.h"
45 #include "src/trace_processor/types/variadic.h"
46
47 #include "protos/perfetto/common/android_energy_consumer_descriptor.pbzero.h"
48 #include "protos/perfetto/config/trace_config.pbzero.h"
49 #include "protos/perfetto/trace/android/packages_list.pbzero.h"
50 #include "protos/perfetto/trace/power/android_energy_estimation_breakdown.pbzero.h"
51 #include "protos/perfetto/trace/power/android_entity_state_residency.pbzero.h"
52 #include "protos/perfetto/trace/power/power_rails.pbzero.h"
53 #include "protos/perfetto/trace/trace_packet.pbzero.h"
54 #include "protos/perfetto/trace/android/bluetooth_trace.pbzero.h"
55
56 namespace perfetto::trace_processor {
57 namespace {
58
MapToFriendlyPowerRailName(base::StringView raw)59 const char* MapToFriendlyPowerRailName(base::StringView raw) {
60 if (raw.EndsWith("M_VDD_CPUCL0")) {
61 return "cpu.little";
62 } else if (raw.EndsWith("M_VDD_CPUCL0_M")) {
63 return "cpu.little.mem";
64 } else if (raw.EndsWith("M_VDD_CPUCL1")) {
65 return "cpu.mid";
66 } else if (raw.EndsWith("M_VDD_CPUCL1_M")) {
67 return "cpu.mid.mem";
68 } else if (raw.EndsWith("M_VDD_CPUCL2")) {
69 return "cpu.big";
70 } else if (raw.EndsWith("M_VDD_INT")) {
71 return "system.fabric";
72 } else if (raw.EndsWith("M_VDD_TPU")) {
73 return "tpu";
74 } else if (raw.EndsWith("VSYS_PWR_DISP") ||
75 raw.EndsWith("VSYS_PWR_DISPLAY")) {
76 return "display";
77 } else if (raw.EndsWith("M_DISP")) {
78 return "ldo.main.a.display";
79 } else if (raw.EndsWith("VSYS_PWR_MODEM")) {
80 return "modem";
81 } else if (raw.EndsWith("M_VDD_MIF")) {
82 return "memory.interface";
83 } else if (raw.EndsWith("VSYS_PWR_WLAN_BT")) {
84 return "wifi.bt";
85 } else if (raw.EndsWith("VSYS_PWR_MMWAVE")) {
86 return "mmwave";
87 } else if (raw.EndsWith("S_VDD_AOC_RET")) {
88 return "aoc.memory";
89 } else if (raw.EndsWith("S_VDD_AOC")) {
90 return "aoc.logic";
91 } else if (raw.EndsWith("S_VDDQ_MEM")) {
92 return "ddr.a";
93 } else if (raw.EndsWith("S_VDD2L") || raw.EndsWith("S_VDD2L_MEM")) {
94 return "ddr.b";
95 } else if (raw.EndsWith("S_VDD2H_MEM")) {
96 return "ddr.c";
97 } else if (raw.EndsWith("S_VDD_G3D")) {
98 return "gpu";
99 } else if (raw.EndsWith("S_VDD_G3D_L2")) {
100 return "gpu.l2";
101 } else if (raw.EndsWith("S_GNSS_CORE")) {
102 return "gps";
103 } else if (raw.EndsWith("VSYS_PWR_RFFE")) {
104 return "radio.frontend";
105 } else if (raw.EndsWith("VSYS_PWR_CAMERA")) {
106 return "camera";
107 } else if (raw.EndsWith("S_VDD_CAM")) {
108 return "multimedia";
109 } else if (raw.EndsWith("S_UDFPS")) {
110 return "udfps";
111 } else if (raw.EndsWith("S_PLL_MIPI_UFS")) {
112 return "ufs";
113 } else if (raw.EndsWith("M_LLDO1")) {
114 return "ldo.main.a";
115 } else if (raw.EndsWith("M_LLDO2")) {
116 return "ldo.main.b";
117 } else if (raw.EndsWith("S_LLDO1")) {
118 return "ldo.sub";
119 }
120 return nullptr;
121 }
122
123 } // namespace
124
125 using perfetto::protos::pbzero::TracePacket;
126
AndroidProbesModule(TraceProcessorContext * context)127 AndroidProbesModule::AndroidProbesModule(TraceProcessorContext* context)
128 : parser_(context),
129 context_(context),
130 power_rail_raw_name_id_(context->storage->InternString("raw_name")),
131 power_rail_subsys_name_arg_id_(
132 context->storage->InternString("subsystem_name")) {
133 RegisterForField(TracePacket::kBatteryFieldNumber, context);
134 RegisterForField(TracePacket::kPowerRailsFieldNumber, context);
135 RegisterForField(TracePacket::kAndroidEnergyEstimationBreakdownFieldNumber,
136 context);
137 RegisterForField(TracePacket::kEntityStateResidencyFieldNumber, context);
138 RegisterForField(TracePacket::kAndroidLogFieldNumber, context);
139 RegisterForField(TracePacket::kPackagesListFieldNumber, context);
140 RegisterForField(TracePacket::kAndroidGameInterventionListFieldNumber,
141 context);
142 RegisterForField(TracePacket::kInitialDisplayStateFieldNumber, context);
143 RegisterForField(TracePacket::kAndroidSystemPropertyFieldNumber, context);
144 RegisterForField(TracePacket::kBluetoothTraceEventFieldNumber, context);
145 }
146
TokenizePacket(const protos::pbzero::TracePacket_Decoder &,TraceBlobView * packet,int64_t packet_timestamp,RefPtr<PacketSequenceStateGeneration> state,uint32_t field_id)147 ModuleResult AndroidProbesModule::TokenizePacket(
148 const protos::pbzero::TracePacket_Decoder&,
149 TraceBlobView* packet,
150 int64_t packet_timestamp,
151 RefPtr<PacketSequenceStateGeneration> state,
152 uint32_t field_id) {
153 protos::pbzero::TracePacket::Decoder decoder(packet->data(),
154 packet->length());
155
156 // The energy descriptor and packages list packets do not have a timestamp so
157 // need to be handled at the tokenization phase.
158 if (field_id == TracePacket::kAndroidEnergyEstimationBreakdownFieldNumber) {
159 return ParseEnergyDescriptor(decoder.android_energy_estimation_breakdown());
160 }
161 if (field_id == TracePacket::kPackagesListFieldNumber) {
162 return ParseAndroidPackagesList(decoder.packages_list());
163 }
164 if (field_id == TracePacket::kEntityStateResidencyFieldNumber) {
165 ParseEntityStateDescriptor(decoder.entity_state_residency());
166 // Ignore so that we get a go at parsing any actual residency data that
167 // should also be in the packet.
168 return ModuleResult::Ignored();
169 }
170
171 if (field_id != TracePacket::kPowerRailsFieldNumber) {
172 return ModuleResult::Ignored();
173 }
174
175 // Power rails are similar to ftrace in that they have many events, each with
176 // their own timestamp, packed inside a single TracePacket. This means that,
177 // similar to ftrace, we need to unpack them and individually sort them.
178
179 // However, as these events are not perf sensitive, it's not worth adding
180 // a lot of machinery to shepherd these events through the sorting queues
181 // in a special way. Therefore, we just forge new packets and sort them as if
182 // they came from the underlying trace.
183 auto power_rails = decoder.power_rails();
184 protos::pbzero::PowerRails::Decoder evt(power_rails);
185
186 for (auto it = evt.rail_descriptor(); it; ++it) {
187 protos::pbzero::PowerRails::RailDescriptor::Decoder desc(*it);
188 uint32_t idx = desc.index();
189 if (PERFETTO_UNLIKELY(idx > 256)) {
190 PERFETTO_DLOG("Skipping excessively large power_rail index %" PRIu32,
191 idx);
192 continue;
193 }
194 static constexpr auto kPowerBlueprint = tracks::CounterBlueprint(
195 "power_rails", tracks::UnknownUnitBlueprint(),
196 tracks::DimensionBlueprints(tracks::kNameFromTraceDimensionBlueprint),
197 tracks::DynamicNameBlueprint());
198 const char* friendly_name = MapToFriendlyPowerRailName(desc.rail_name());
199 TrackId track;
200 auto args_fn = [this, &desc](ArgsTracker::BoundInserter& inserter) {
201 StringId raw_name = context_->storage->InternString(desc.rail_name());
202 inserter.AddArg(power_rail_raw_name_id_, Variadic::String(raw_name));
203
204 StringId subsys_name =
205 context_->storage->InternString(desc.subsys_name());
206 inserter.AddArg(power_rail_subsys_name_arg_id_,
207 Variadic::String(subsys_name));
208 };
209 if (friendly_name) {
210 StringId id = context_->storage->InternString(
211 base::StackString<255>("power.rails.%s", friendly_name)
212 .string_view());
213 track = context_->track_tracker->InternTrack(
214 kPowerBlueprint, tracks::Dimensions(desc.rail_name()),
215 tracks::DynamicName(id), args_fn);
216 } else {
217 StringId id = context_->storage->InternString(
218 base::StackString<255>("power.%.*s_uws", int(desc.rail_name().size),
219 desc.rail_name().data)
220 .string_view());
221 track = context_->track_tracker->InternTrack(
222 kPowerBlueprint, tracks::Dimensions(desc.rail_name()),
223 tracks::DynamicName(id), args_fn);
224 }
225 AndroidProbesTracker::GetOrCreate(context_)->SetPowerRailTrack(desc.index(),
226 track);
227 }
228
229 // For each energy data message, turn it into its own trace packet
230 // making sure its timestamp is consistent between the packet level and
231 // the EnergyData level.
232 for (auto it = evt.energy_data(); it; ++it) {
233 protos::pbzero::PowerRails::EnergyData::Decoder data(*it);
234 int64_t actual_ts =
235 data.has_timestamp_ms()
236 ? static_cast<int64_t>(data.timestamp_ms()) * 1000000
237 : packet_timestamp;
238
239 protozero::HeapBuffered<protos::pbzero::TracePacket> data_packet;
240 // Keep the original timestamp to later extract as an arg; the sorter does
241 // not read this.
242 data_packet->set_timestamp(static_cast<uint64_t>(packet_timestamp));
243
244 auto* energy = data_packet->set_power_rails()->add_energy_data();
245 energy->set_energy(data.energy());
246 energy->set_index(data.index());
247 energy->set_timestamp_ms(static_cast<uint64_t>(actual_ts / 1000000));
248
249 std::vector<uint8_t> vec = data_packet.SerializeAsArray();
250 TraceBlob blob = TraceBlob::CopyFrom(vec.data(), vec.size());
251 context_->sorter->PushTracePacket(actual_ts, state,
252 TraceBlobView(std::move(blob)),
253 context_->machine_id());
254 }
255 return ModuleResult::Handled();
256 }
257
ParseTracePacketData(const TracePacket::Decoder & decoder,int64_t ts,const TracePacketData &,uint32_t field_id)258 void AndroidProbesModule::ParseTracePacketData(
259 const TracePacket::Decoder& decoder,
260 int64_t ts,
261 const TracePacketData&,
262 uint32_t field_id) {
263 switch (field_id) {
264 case TracePacket::kBatteryFieldNumber:
265 parser_.ParseBatteryCounters(ts, decoder.battery());
266 return;
267 case TracePacket::kPowerRailsFieldNumber:
268 parser_.ParsePowerRails(ts, decoder.timestamp(), decoder.power_rails());
269 return;
270 case TracePacket::kAndroidEnergyEstimationBreakdownFieldNumber:
271 parser_.ParseEnergyBreakdown(
272 ts, decoder.android_energy_estimation_breakdown());
273 return;
274 case TracePacket::kEntityStateResidencyFieldNumber:
275 parser_.ParseEntityStateResidency(ts, decoder.entity_state_residency());
276 return;
277 case TracePacket::kAndroidLogFieldNumber:
278 parser_.ParseAndroidLogPacket(decoder.android_log());
279 return;
280 case TracePacket::kAndroidGameInterventionListFieldNumber:
281 parser_.ParseAndroidGameIntervention(
282 decoder.android_game_intervention_list());
283 return;
284 case TracePacket::kInitialDisplayStateFieldNumber:
285 parser_.ParseInitialDisplayState(ts, decoder.initial_display_state());
286 return;
287 case TracePacket::kAndroidSystemPropertyFieldNumber:
288 parser_.ParseAndroidSystemProperty(ts, decoder.android_system_property());
289 return;
290 case TracePacket::kBluetoothTraceEventFieldNumber:
291 parser_.ParseBtTraceEvent(ts, decoder.bluetooth_trace_event());
292 return;
293 }
294 }
295
ParseTraceConfig(const protos::pbzero::TraceConfig::Decoder & decoder)296 void AndroidProbesModule::ParseTraceConfig(
297 const protos::pbzero::TraceConfig::Decoder& decoder) {
298 if (decoder.has_statsd_metadata()) {
299 parser_.ParseStatsdMetadata(decoder.statsd_metadata());
300 }
301 }
302
ParseEnergyDescriptor(protozero::ConstBytes blob)303 ModuleResult AndroidProbesModule::ParseEnergyDescriptor(
304 protozero::ConstBytes blob) {
305 protos::pbzero::AndroidEnergyEstimationBreakdown::Decoder event(blob);
306 if (!event.has_energy_consumer_descriptor())
307 return ModuleResult::Ignored();
308
309 protos::pbzero::AndroidEnergyConsumerDescriptor::Decoder descriptor(
310 event.energy_consumer_descriptor());
311
312 for (auto it = descriptor.energy_consumers(); it; ++it) {
313 protos::pbzero::AndroidEnergyConsumer::Decoder consumer(*it);
314
315 if (!consumer.has_energy_consumer_id()) {
316 context_->storage->IncrementStats(stats::energy_descriptor_invalid);
317 continue;
318 }
319
320 AndroidProbesTracker::GetOrCreate(context_)->SetEnergyBreakdownDescriptor(
321 consumer.energy_consumer_id(),
322 context_->storage->InternString(consumer.name()),
323 context_->storage->InternString(consumer.type()), consumer.ordinal());
324 }
325 return ModuleResult::Handled();
326 }
327
ParseAndroidPackagesList(protozero::ConstBytes blob)328 ModuleResult AndroidProbesModule::ParseAndroidPackagesList(
329 protozero::ConstBytes blob) {
330 protos::pbzero::PackagesList::Decoder pkg_list(blob.data, blob.size);
331 context_->storage->SetStats(stats::packages_list_has_read_errors,
332 pkg_list.read_error());
333 context_->storage->SetStats(stats::packages_list_has_parse_errors,
334 pkg_list.parse_error());
335
336 AndroidProbesTracker* tracker = AndroidProbesTracker::GetOrCreate(context_);
337 for (auto it = pkg_list.packages(); it; ++it) {
338 protos::pbzero::PackagesList_PackageInfo::Decoder pkg(*it);
339 std::string pkg_name = pkg.name().ToStdString();
340 if (!tracker->ShouldInsertPackage(pkg_name)) {
341 continue;
342 }
343 context_->storage->mutable_package_list_table()->Insert(
344 {context_->storage->InternString(pkg.name()),
345 static_cast<int64_t>(pkg.uid()), pkg.debuggable(),
346 pkg.profileable_from_shell(),
347 static_cast<int64_t>(pkg.version_code())});
348 tracker->InsertedPackage(std::move(pkg_name));
349 }
350 return ModuleResult::Handled();
351 }
352
ParseEntityStateDescriptor(protozero::ConstBytes blob)353 void AndroidProbesModule::ParseEntityStateDescriptor(
354 protozero::ConstBytes blob) {
355 protos::pbzero::EntityStateResidency::Decoder event(blob);
356 if (!event.has_power_entity_state())
357 return;
358
359 for (auto it = event.power_entity_state(); it; ++it) {
360 protos::pbzero::EntityStateResidency::PowerEntityState::Decoder
361 entity_state(*it);
362
363 if (!entity_state.has_entity_index() || !entity_state.has_state_index()) {
364 context_->storage->IncrementStats(stats::energy_descriptor_invalid);
365 continue;
366 }
367 AndroidProbesTracker::GetOrCreate(context_)->SetEntityStateDescriptor(
368 entity_state.entity_index(), entity_state.state_index(),
369 context_->storage->InternString(entity_state.entity_name()),
370 context_->storage->InternString(entity_state.state_name()));
371 }
372 }
373
374 } // namespace perfetto::trace_processor
375