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