• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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