• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2025 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_kernel_wakelocks_module.h"
18 #include <cstdint>
19 
20 #include <string>
21 #include <unordered_set>
22 
23 #include "perfetto/ext/base/flat_hash_map.h"
24 #include "perfetto/protozero/field.h"
25 #include "src/trace_processor/importers/common/event_tracker.h"
26 #include "src/trace_processor/importers/common/parser_types.h"
27 #include "src/trace_processor/importers/common/track_tracker.h"
28 #include "src/trace_processor/importers/common/tracks.h"
29 #include "src/trace_processor/importers/proto/android_kernel_wakelocks_state.h"
30 #include "src/trace_processor/importers/proto/packet_sequence_state_generation.h"
31 #include "src/trace_processor/importers/proto/proto_importer_module.h"
32 #include "src/trace_processor/importers/proto/v8_module.h"
33 #include "src/trace_processor/storage/stats.h"
34 #include "src/trace_processor/storage/trace_storage.h"
35 
36 #include "protos/perfetto/trace/android/kernel_wakelock_data.pbzero.h"
37 #include "protos/perfetto/trace/trace_packet.pbzero.h"
38 
39 namespace perfetto::trace_processor {
40 
41 using perfetto::protos::pbzero::TracePacket;
42 
AndroidKernelWakelocksModule(TraceProcessorContext * context)43 AndroidKernelWakelocksModule::AndroidKernelWakelocksModule(
44     TraceProcessorContext* context)
45     : context_(context),
46       kernel_name_id_(context->storage->InternString("kernel")),
47       native_name_id_(context->storage->InternString("native")),
48       unknown_name_id_(context->storage->InternString("unknown")) {
49   RegisterForField(TracePacket::kKernelWakelockDataFieldNumber, context);
50 }
51 
52 AndroidKernelWakelocksModule::~AndroidKernelWakelocksModule() = default;
53 
ParseTracePacketData(const TracePacket::Decoder & decoder,int64_t ts,const TracePacketData & packet,uint32_t field_id)54 void AndroidKernelWakelocksModule::ParseTracePacketData(
55     const TracePacket::Decoder& decoder,
56     int64_t ts,
57     const TracePacketData& packet,
58     uint32_t field_id) {
59   if (field_id != TracePacket::kKernelWakelockDataFieldNumber) {
60     return;
61   }
62 
63   std::unordered_set<std::string> names_with_value_this_packet;
64 
65   auto* state =
66       packet.sequence_state->GetCustomState<AndroidKernelWakelockState>();
67   protos::pbzero::KernelWakelockData::Decoder evt(
68       decoder.kernel_wakelock_data());
69   for (auto it = evt.wakelock(); it; ++it) {
70     protos::pbzero::KernelWakelockData::Wakelock::Decoder wakelock(*it);
71     std::string name = wakelock.wakelock_name().ToStdString();
72     auto [info, inserted] = state->wakelocks.Insert(
73         wakelock.wakelock_id(), AndroidKernelWakelockState::Metadata{});
74     if (!inserted) {
75       context_->storage->IncrementStats(stats::kernel_wakelock_reused_id);
76       continue;
77     }
78     info->name = name;
79     info->type =
80         static_cast<protos::pbzero::KernelWakelockData::Wakelock::Type>(
81             wakelock.wakelock_type());
82   }
83 
84   bool parse_error = false;
85   auto time_it = evt.time_held_millis(&parse_error);
86   for (auto it = evt.wakelock_id(&parse_error); it && time_it;
87        ++it, ++time_it) {
88     auto* data = state->wakelocks.Find(*it);
89     if (!data) {
90       context_->storage->IncrementStats(stats::kernel_wakelock_unknown_id);
91       continue;
92     }
93 
94     const auto& name = data->name;
95     names_with_value_this_packet.insert(name);
96 
97     uint64_t delta = *time_it;
98     auto [last_value, inserted] = state->wakelock_last_values.Insert(
99         name, AndroidKernelWakelockState::LastValue{});
100     last_value->value += delta;
101     last_value->type = data->type;
102     UpdateCounter(ts, name, data->type, last_value->value);
103   }
104 
105   // Anything we knew about but didn't see in this packet must not have
106   // incremented.
107   for (auto it = state->wakelock_last_values.GetIterator(); it; ++it) {
108     if (names_with_value_this_packet.count(it.key())) {
109       continue;
110     }
111     UpdateCounter(ts, it.key(), it.value().type, it.value().value);
112   }
113 }
114 
UpdateCounter(int64_t ts,const std::string & name,protos::pbzero::KernelWakelockData_Wakelock_Type type,uint64_t value)115 void AndroidKernelWakelocksModule::UpdateCounter(
116     int64_t ts,
117     const std::string& name,
118     protos::pbzero::KernelWakelockData_Wakelock_Type type,
119     uint64_t value) {
120   static constexpr auto kBlueprint = tracks::CounterBlueprint(
121       "android_kernel_wakelock", tracks::StaticUnitBlueprint("ms"),
122       tracks::DimensionBlueprints(
123           tracks::StringDimensionBlueprint("wakelock_name"),
124           tracks::StringDimensionBlueprint("wakelock_type")),
125       tracks::DynamicNameBlueprint());
126   StringId type_id;
127   switch (type) {
128     case protos::pbzero::KernelWakelockData_Wakelock_Type::WAKELOCK_TYPE_KERNEL:
129       type_id = kernel_name_id_;
130       break;
131     case protos::pbzero::KernelWakelockData_Wakelock_Type::WAKELOCK_TYPE_NATIVE:
132       type_id = native_name_id_;
133       break;
134     case protos::pbzero::KernelWakelockData_Wakelock_Type::
135         WAKELOCK_TYPE_UNKNOWN:
136       type_id = unknown_name_id_;
137       break;
138   }
139 
140   StringId name_id = context_->storage->InternString(name);
141   TrackId track = context_->track_tracker->InternTrack(
142       kBlueprint,
143       tracks::Dimensions(context_->storage->GetString(name_id),
144                          context_->storage->GetString(type_id)),
145       tracks::DynamicName(name_id));
146   context_->event_tracker->PushCounter(ts, 1e6 * double(value), track);
147 }
148 
149 }  // namespace perfetto::trace_processor
150