1 /*
2 * Copyright (C) 2021 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/metadata_minimal_module.h"
18
19 #include "perfetto/ext/base/base64.h"
20 #include "perfetto/ext/base/string_utils.h"
21 #include "src/trace_processor/importers/common/metadata_tracker.h"
22 #include "src/trace_processor/importers/proto/packet_sequence_state_generation.h"
23 #include "src/trace_processor/types/trace_processor_context.h"
24
25 #include "protos/perfetto/trace/chrome/chrome_benchmark_metadata.pbzero.h"
26 #include "protos/perfetto/trace/chrome/chrome_metadata.pbzero.h"
27
28 namespace perfetto {
29 namespace trace_processor {
30
31 using perfetto::protos::pbzero::TracePacket;
32
MetadataMinimalModule(TraceProcessorContext * context)33 MetadataMinimalModule::MetadataMinimalModule(TraceProcessorContext* context)
34 : context_(context) {
35 RegisterForField(TracePacket::kChromeMetadataFieldNumber, context);
36 RegisterForField(TracePacket::kChromeBenchmarkMetadataFieldNumber, context);
37 }
38
TokenizePacket(const protos::pbzero::TracePacket::Decoder & decoder,TraceBlobView *,int64_t,RefPtr<PacketSequenceStateGeneration>,uint32_t field_id)39 ModuleResult MetadataMinimalModule::TokenizePacket(
40 const protos::pbzero::TracePacket::Decoder& decoder,
41 TraceBlobView*,
42 int64_t,
43 RefPtr<PacketSequenceStateGeneration>,
44 uint32_t field_id) {
45 switch (field_id) {
46 case TracePacket::kChromeMetadataFieldNumber: {
47 ParseChromeMetadataPacket(decoder.chrome_metadata());
48 return ModuleResult::Handled();
49 }
50 case TracePacket::kChromeBenchmarkMetadataFieldNumber: {
51 ParseChromeBenchmarkMetadata(decoder.chrome_benchmark_metadata());
52 return ModuleResult::Handled();
53 }
54 }
55 return ModuleResult::Ignored();
56 }
57
ParseChromeBenchmarkMetadata(ConstBytes blob)58 void MetadataMinimalModule::ParseChromeBenchmarkMetadata(ConstBytes blob) {
59 TraceStorage* storage = context_->storage.get();
60 MetadataTracker* metadata = context_->metadata_tracker.get();
61
62 protos::pbzero::ChromeBenchmarkMetadata::Decoder packet(blob.data, blob.size);
63 if (packet.has_benchmark_name()) {
64 auto benchmark_name_id = storage->InternString(packet.benchmark_name());
65 metadata->SetMetadata(metadata::benchmark_name,
66 Variadic::String(benchmark_name_id));
67 }
68 if (packet.has_benchmark_description()) {
69 auto benchmark_description_id =
70 storage->InternString(packet.benchmark_description());
71 metadata->SetMetadata(metadata::benchmark_description,
72 Variadic::String(benchmark_description_id));
73 }
74 if (packet.has_label()) {
75 auto label_id = storage->InternString(packet.label());
76 metadata->SetMetadata(metadata::benchmark_label,
77 Variadic::String(label_id));
78 }
79 if (packet.has_story_name()) {
80 auto story_name_id = storage->InternString(packet.story_name());
81 metadata->SetMetadata(metadata::benchmark_story_name,
82 Variadic::String(story_name_id));
83 }
84 for (auto it = packet.story_tags(); it; ++it) {
85 auto story_tag_id = storage->InternString(*it);
86 metadata->AppendMetadata(metadata::benchmark_story_tags,
87 Variadic::String(story_tag_id));
88 }
89 if (packet.has_benchmark_start_time_us()) {
90 metadata->SetMetadata(metadata::benchmark_start_time_us,
91 Variadic::Integer(packet.benchmark_start_time_us()));
92 }
93 if (packet.has_story_run_time_us()) {
94 metadata->SetMetadata(metadata::benchmark_story_run_time_us,
95 Variadic::Integer(packet.story_run_time_us()));
96 }
97 if (packet.has_story_run_index()) {
98 metadata->SetMetadata(metadata::benchmark_story_run_index,
99 Variadic::Integer(packet.story_run_index()));
100 }
101 if (packet.has_had_failures()) {
102 metadata->SetMetadata(metadata::benchmark_had_failures,
103 Variadic::Integer(packet.had_failures()));
104 }
105 }
106
ParseChromeMetadataPacket(ConstBytes blob)107 void MetadataMinimalModule::ParseChromeMetadataPacket(ConstBytes blob) {
108 TraceStorage* storage = context_->storage.get();
109 MetadataTracker* metadata = context_->metadata_tracker.get();
110
111 // TODO(b/322298334): There is no easy way to associate ChromeMetadataPacket
112 // with ChromeMetadata for the same instance, so we have opted for letters to
113 // differentiate Chrome instances for ChromeMetadataPacket. When a unifying
114 // Chrome instance ID is in place, update this code to use the same counter
115 // as ChromeMetadata values.
116 base::StackString<6> metadata_prefix(
117 "cr-%c-", static_cast<char>('a' + (chrome_metadata_count_ % 26)));
118 chrome_metadata_count_++;
119
120 // Typed chrome metadata proto. The untyped metadata is parsed below in
121 // ParseChromeEvents().
122 protos::pbzero::ChromeMetadataPacket::Decoder packet_decoder(blob.data,
123 blob.size);
124
125 if (packet_decoder.has_chrome_version_code()) {
126 metadata->SetDynamicMetadata(
127 storage->InternString(base::StringView(metadata_prefix.ToStdString() +
128 "playstore_version_code")),
129 Variadic::Integer(packet_decoder.chrome_version_code()));
130 }
131 if (packet_decoder.has_enabled_categories()) {
132 auto categories_id =
133 storage->InternString(packet_decoder.enabled_categories());
134 metadata->SetDynamicMetadata(
135 storage->InternString(base::StringView(metadata_prefix.ToStdString() +
136 "enabled_categories")),
137 Variadic::String(categories_id));
138 }
139
140 if (packet_decoder.has_field_trial_hashes()) {
141 std::string field_trials;
142
143 // Add a line break after every 2 field trial hashes to better utilize the
144 // UI space.
145 int line_size = 0;
146 for (auto it = packet_decoder.field_trial_hashes(); it; ++it) {
147 if (line_size == 2) {
148 field_trials.append("\n");
149 line_size = 1;
150 } else {
151 line_size++;
152 }
153
154 perfetto::protos::pbzero::ChromeMetadataPacket::FinchHash::Decoder
155 field_trial(*it);
156
157 base::StackString<45> field_trial_string(
158 "{ name: %u, group: %u } ", field_trial.name(), field_trial.group());
159
160 field_trials.append(field_trial_string.ToStdString());
161 }
162
163 StringId field_trials_string =
164 context_->storage->InternString(base::StringView(field_trials));
165 metadata->SetDynamicMetadata(
166 storage->InternString(base::StringView(metadata_prefix.ToStdString() +
167 "field_trial_hashes")),
168 Variadic::String(field_trials_string));
169 }
170
171 if (packet_decoder.has_background_tracing_metadata()) {
172 auto background_tracing_metadata =
173 packet_decoder.background_tracing_metadata();
174
175 std::string base64 = base::Base64Encode(background_tracing_metadata.data,
176 background_tracing_metadata.size);
177 metadata->SetDynamicMetadata(
178 storage->InternString("cr-background_tracing_metadata"),
179 Variadic::String(storage->InternString(base::StringView(base64))));
180
181 protos::pbzero::BackgroundTracingMetadata::Decoder metadata_decoder(
182 background_tracing_metadata.data, background_tracing_metadata.size);
183 if (metadata_decoder.has_scenario_name_hash()) {
184 metadata->SetDynamicMetadata(
185 storage->InternString("cr-scenario_name_hash"),
186 Variadic::Integer(metadata_decoder.scenario_name_hash()));
187 }
188 auto triggered_rule = metadata_decoder.triggered_rule();
189 if (!metadata_decoder.has_triggered_rule())
190 return;
191 protos::pbzero::BackgroundTracingMetadata::TriggerRule::Decoder
192 triggered_rule_decoder(triggered_rule.data, triggered_rule.size);
193 }
194 }
195
196 } // namespace trace_processor
197 } // namespace perfetto
198