xref: /aosp_15_r20/external/perfetto/src/trace_processor/importers/proto/pixel_modem_parser.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1 /*
2  * Copyright (C) 2024 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/pixel_modem_parser.h"
18 
19 #include <cstddef>
20 #include <cstdint>
21 
22 #include "perfetto/ext/base/string_utils.h"
23 #include "perfetto/protozero/field.h"
24 #include "src/trace_processor/importers/common/async_track_set_tracker.h"
25 #include "src/trace_processor/importers/common/slice_tracker.h"
26 #include "src/trace_processor/importers/proto/pigweed_detokenizer.h"
27 #include "src/trace_processor/storage/trace_storage.h"
28 #include "src/trace_processor/util/status_macros.h"
29 
30 namespace perfetto::trace_processor {
31 
32 namespace {
33 
34 constexpr std::string_view kKeyDelimiterStart = "\u25A0";
35 constexpr std::string_view kKeyDelimiterEnd = "\u2666";
36 constexpr std::string_view kKeyDomain = "domain";
37 constexpr std::string_view kKeyFormat = "format";
38 constexpr std::string_view kModemNamePrefix = "Pixel Modem Events: ";
39 constexpr std::string_view kModemName = "Pixel Modem Events";
40 
41 // Modem inputs in particular have this key-value encoding. It's not a Pigweed
42 // thing.
SplitUpModemString(std::string input)43 std::map<std::string, std::string> SplitUpModemString(std::string input) {
44   auto delimStart = std::string(kKeyDelimiterStart);
45   auto delimEnd = std::string(kKeyDelimiterEnd);
46 
47   std::map<std::string, std::string> result;
48 
49   std::vector<std::string> pairs = base::SplitString(input, delimStart);
50   for (auto it = pairs.begin(); it != pairs.end(); it++) {
51     std::vector<std::string> pair = base::SplitString(*it, delimEnd);
52     if (pair.size() >= 2) {
53       result.insert({pair[0], pair[1]});
54     }
55   }
56 
57   return result;
58 }
59 
60 }  // namespace
61 
PixelModemParser(TraceProcessorContext * context)62 PixelModemParser::PixelModemParser(TraceProcessorContext* context)
63     : context_(context),
64       detokenizer_(pigweed::CreateNullDetokenizer()),
65       template_id_(context->storage->InternString("raw_template")),
66       token_id_(context->storage->InternString("token_id")),
67       token_id_hex_(context->storage->InternString("token_id_hex")),
68       packet_timestamp_id_(context->storage->InternString("packet_ts")) {}
69 
70 PixelModemParser::~PixelModemParser() = default;
71 
SetDatabase(protozero::ConstBytes blob)72 base::Status PixelModemParser::SetDatabase(protozero::ConstBytes blob) {
73   ASSIGN_OR_RETURN(detokenizer_, pigweed::CreateDetokenizer(blob));
74   return base::OkStatus();
75 }
76 
ParseEvent(int64_t ts,uint64_t trace_packet_ts,protozero::ConstBytes blob)77 base::Status PixelModemParser::ParseEvent(int64_t ts,
78                                           uint64_t trace_packet_ts,
79                                           protozero::ConstBytes blob) {
80   ASSIGN_OR_RETURN(pigweed::DetokenizedString detokenized_str,
81                    detokenizer_.Detokenize(blob));
82 
83   std::string event = detokenized_str.Format();
84 
85   auto map = SplitUpModemString(event);
86   auto domain = map.find(std::string(kKeyDomain));
87   auto format = map.find(std::string(kKeyFormat));
88 
89   std::string track_name = domain == map.end()
90                                ? std::string(kModemName)
91                                : std::string(kModemNamePrefix) + domain->second;
92   std::string slice_name = format == map.end() ? event : format->second;
93 
94   StringId track_name_id = context_->storage->InternString(track_name.c_str());
95   StringId slice_name_id = context_->storage->InternString(slice_name.c_str());
96   auto set_id =
97       context_->async_track_set_tracker->InternGlobalTrackSet(track_name_id);
98   TrackId id = context_->async_track_set_tracker->Scoped(set_id, ts, 0);
99 
100   context_->slice_tracker->Scoped(
101       ts, id, kNullStringId, slice_name_id, 0,
102       [this, &detokenized_str,
103        trace_packet_ts](ArgsTracker::BoundInserter* inserter) {
104         inserter->AddArg(template_id_,
105                          Variadic::String(context_->storage->InternString(
106                              detokenized_str.template_str().c_str())));
107         uint32_t token = detokenized_str.token();
108         inserter->AddArg(token_id_, Variadic::Integer(token));
109         inserter->AddArg(token_id_hex_,
110                          Variadic::String(context_->storage->InternString(
111                              base::IntToHexString(token).c_str())));
112         inserter->AddArg(packet_timestamp_id_,
113                          Variadic::UnsignedInteger(trace_packet_ts));
114         auto pw_args = detokenized_str.args();
115         for (size_t i = 0; i < pw_args.size(); i++) {
116           StringId arg_name = context_->storage->InternString(
117               ("pw_token_" + std::to_string(token) + ".arg_" +
118                std::to_string(i))
119                   .c_str());
120           auto arg = pw_args[i];
121           if (int64_t* int_arg = std::get_if<int64_t>(&arg)) {
122             inserter->AddArg(arg_name, Variadic::Integer(*int_arg));
123           } else if (uint64_t* uint_arg = std::get_if<uint64_t>(&arg)) {
124             inserter->AddArg(arg_name, Variadic::UnsignedInteger(*uint_arg));
125           } else {
126             inserter->AddArg(arg_name, Variadic::Real(std::get<double>(arg)));
127           }
128         }
129       });
130 
131   return base::OkStatus();
132 }
133 
134 }  // namespace perfetto::trace_processor
135