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