1*6dbdd20aSAndroid Build Coastguard Worker /*
2*6dbdd20aSAndroid Build Coastguard Worker * Copyright (C) 2020 The Android Open Source Project
3*6dbdd20aSAndroid Build Coastguard Worker *
4*6dbdd20aSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*6dbdd20aSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*6dbdd20aSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*6dbdd20aSAndroid Build Coastguard Worker *
8*6dbdd20aSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*6dbdd20aSAndroid Build Coastguard Worker *
10*6dbdd20aSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*6dbdd20aSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*6dbdd20aSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*6dbdd20aSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*6dbdd20aSAndroid Build Coastguard Worker * limitations under the License.
15*6dbdd20aSAndroid Build Coastguard Worker */
16*6dbdd20aSAndroid Build Coastguard Worker
17*6dbdd20aSAndroid Build Coastguard Worker #include "src/profiling/common/interning_output.h"
18*6dbdd20aSAndroid Build Coastguard Worker
19*6dbdd20aSAndroid Build Coastguard Worker #include "protos/perfetto/trace/interned_data/interned_data.pbzero.h"
20*6dbdd20aSAndroid Build Coastguard Worker #include "protos/perfetto/trace/profiling/profile_common.pbzero.h"
21*6dbdd20aSAndroid Build Coastguard Worker #include "protos/perfetto/trace/profiling/profile_packet.pbzero.h"
22*6dbdd20aSAndroid Build Coastguard Worker #include "protos/perfetto/trace/trace_packet.pbzero.h"
23*6dbdd20aSAndroid Build Coastguard Worker
24*6dbdd20aSAndroid Build Coastguard Worker namespace {
25*6dbdd20aSAndroid Build Coastguard Worker // Flags used to distinguish distinct types of interned strings.
26*6dbdd20aSAndroid Build Coastguard Worker constexpr int kDumpedBuildID = 1 << 0;
27*6dbdd20aSAndroid Build Coastguard Worker constexpr int kDumpedMappingPath = 1 << 1;
28*6dbdd20aSAndroid Build Coastguard Worker constexpr int kDumpedFunctionName = 1 << 2;
29*6dbdd20aSAndroid Build Coastguard Worker } // namespace
30*6dbdd20aSAndroid Build Coastguard Worker
31*6dbdd20aSAndroid Build Coastguard Worker namespace perfetto {
32*6dbdd20aSAndroid Build Coastguard Worker namespace profiling {
33*6dbdd20aSAndroid Build Coastguard Worker
34*6dbdd20aSAndroid Build Coastguard Worker // static
WriteFixedInterningsPacket(TraceWriter * trace_writer,uint32_t sequence_flags)35*6dbdd20aSAndroid Build Coastguard Worker void InterningOutputTracker::WriteFixedInterningsPacket(
36*6dbdd20aSAndroid Build Coastguard Worker TraceWriter* trace_writer,
37*6dbdd20aSAndroid Build Coastguard Worker uint32_t sequence_flags) {
38*6dbdd20aSAndroid Build Coastguard Worker constexpr const uint8_t kEmptyString[] = "";
39*6dbdd20aSAndroid Build Coastguard Worker // Explicitly reserve intern ID 0 for the empty string, so unset string
40*6dbdd20aSAndroid Build Coastguard Worker // fields get mapped to this.
41*6dbdd20aSAndroid Build Coastguard Worker auto packet = trace_writer->NewTracePacket();
42*6dbdd20aSAndroid Build Coastguard Worker auto* interned_data = packet->set_interned_data();
43*6dbdd20aSAndroid Build Coastguard Worker auto* interned_string = interned_data->add_build_ids();
44*6dbdd20aSAndroid Build Coastguard Worker interned_string->set_iid(0);
45*6dbdd20aSAndroid Build Coastguard Worker interned_string->set_str(kEmptyString, 0);
46*6dbdd20aSAndroid Build Coastguard Worker
47*6dbdd20aSAndroid Build Coastguard Worker interned_string = interned_data->add_mapping_paths();
48*6dbdd20aSAndroid Build Coastguard Worker interned_string->set_iid(0);
49*6dbdd20aSAndroid Build Coastguard Worker interned_string->set_str(kEmptyString, 0);
50*6dbdd20aSAndroid Build Coastguard Worker
51*6dbdd20aSAndroid Build Coastguard Worker interned_string = interned_data->add_function_names();
52*6dbdd20aSAndroid Build Coastguard Worker interned_string->set_iid(0);
53*6dbdd20aSAndroid Build Coastguard Worker interned_string->set_str(kEmptyString, 0);
54*6dbdd20aSAndroid Build Coastguard Worker
55*6dbdd20aSAndroid Build Coastguard Worker if (sequence_flags) {
56*6dbdd20aSAndroid Build Coastguard Worker packet->set_sequence_flags(sequence_flags);
57*6dbdd20aSAndroid Build Coastguard Worker }
58*6dbdd20aSAndroid Build Coastguard Worker }
59*6dbdd20aSAndroid Build Coastguard Worker
WriteMap(const Interned<Mapping> map,protos::pbzero::InternedData * out)60*6dbdd20aSAndroid Build Coastguard Worker void InterningOutputTracker::WriteMap(const Interned<Mapping> map,
61*6dbdd20aSAndroid Build Coastguard Worker protos::pbzero::InternedData* out) {
62*6dbdd20aSAndroid Build Coastguard Worker auto map_it_and_inserted = dumped_mappings_.emplace(map.id());
63*6dbdd20aSAndroid Build Coastguard Worker if (map_it_and_inserted.second) {
64*6dbdd20aSAndroid Build Coastguard Worker for (const Interned<std::string>& str : map->path_components)
65*6dbdd20aSAndroid Build Coastguard Worker WriteMappingPathString(str, out);
66*6dbdd20aSAndroid Build Coastguard Worker
67*6dbdd20aSAndroid Build Coastguard Worker WriteBuildIDString(map->build_id, out);
68*6dbdd20aSAndroid Build Coastguard Worker
69*6dbdd20aSAndroid Build Coastguard Worker protos::pbzero::Mapping* mapping = out->add_mappings();
70*6dbdd20aSAndroid Build Coastguard Worker mapping->set_iid(map.id());
71*6dbdd20aSAndroid Build Coastguard Worker mapping->set_exact_offset(map->exact_offset);
72*6dbdd20aSAndroid Build Coastguard Worker mapping->set_start_offset(map->start_offset);
73*6dbdd20aSAndroid Build Coastguard Worker mapping->set_start(map->start);
74*6dbdd20aSAndroid Build Coastguard Worker mapping->set_end(map->end);
75*6dbdd20aSAndroid Build Coastguard Worker mapping->set_load_bias(map->load_bias);
76*6dbdd20aSAndroid Build Coastguard Worker mapping->set_build_id(map->build_id.id());
77*6dbdd20aSAndroid Build Coastguard Worker for (const Interned<std::string>& str : map->path_components)
78*6dbdd20aSAndroid Build Coastguard Worker mapping->add_path_string_ids(str.id());
79*6dbdd20aSAndroid Build Coastguard Worker }
80*6dbdd20aSAndroid Build Coastguard Worker }
81*6dbdd20aSAndroid Build Coastguard Worker
WriteFrame(Interned<Frame> frame,protos::pbzero::InternedData * out)82*6dbdd20aSAndroid Build Coastguard Worker void InterningOutputTracker::WriteFrame(Interned<Frame> frame,
83*6dbdd20aSAndroid Build Coastguard Worker protos::pbzero::InternedData* out) {
84*6dbdd20aSAndroid Build Coastguard Worker // Trace processor depends on the map being written before the
85*6dbdd20aSAndroid Build Coastguard Worker // frame. See StackProfileTracker::AddFrame.
86*6dbdd20aSAndroid Build Coastguard Worker WriteMap(frame->mapping, out);
87*6dbdd20aSAndroid Build Coastguard Worker WriteFunctionNameString(frame->function_name, out);
88*6dbdd20aSAndroid Build Coastguard Worker bool inserted;
89*6dbdd20aSAndroid Build Coastguard Worker std::tie(std::ignore, inserted) = dumped_frames_.emplace(frame.id());
90*6dbdd20aSAndroid Build Coastguard Worker if (inserted) {
91*6dbdd20aSAndroid Build Coastguard Worker protos::pbzero::Frame* frame_proto = out->add_frames();
92*6dbdd20aSAndroid Build Coastguard Worker frame_proto->set_iid(frame.id());
93*6dbdd20aSAndroid Build Coastguard Worker frame_proto->set_function_name_id(frame->function_name.id());
94*6dbdd20aSAndroid Build Coastguard Worker frame_proto->set_mapping_id(frame->mapping.id());
95*6dbdd20aSAndroid Build Coastguard Worker frame_proto->set_rel_pc(frame->rel_pc);
96*6dbdd20aSAndroid Build Coastguard Worker }
97*6dbdd20aSAndroid Build Coastguard Worker }
98*6dbdd20aSAndroid Build Coastguard Worker
WriteBuildIDString(const Interned<std::string> & str,protos::pbzero::InternedData * out)99*6dbdd20aSAndroid Build Coastguard Worker void InterningOutputTracker::WriteBuildIDString(
100*6dbdd20aSAndroid Build Coastguard Worker const Interned<std::string>& str,
101*6dbdd20aSAndroid Build Coastguard Worker protos::pbzero::InternedData* out) {
102*6dbdd20aSAndroid Build Coastguard Worker auto it_and_inserted = dumped_strings_.emplace(str.id(), 0);
103*6dbdd20aSAndroid Build Coastguard Worker auto it = it_and_inserted.first;
104*6dbdd20aSAndroid Build Coastguard Worker // This is for the rare case that the same string is used as two different
105*6dbdd20aSAndroid Build Coastguard Worker // types (e.g. a function name that matches a path segment). In that case
106*6dbdd20aSAndroid Build Coastguard Worker // we need to emit the string as all of its types.
107*6dbdd20aSAndroid Build Coastguard Worker if ((it->second & kDumpedBuildID) == 0) {
108*6dbdd20aSAndroid Build Coastguard Worker protos::pbzero::InternedString* interned_string = out->add_build_ids();
109*6dbdd20aSAndroid Build Coastguard Worker interned_string->set_iid(str.id());
110*6dbdd20aSAndroid Build Coastguard Worker interned_string->set_str(str.data());
111*6dbdd20aSAndroid Build Coastguard Worker it->second |= kDumpedBuildID;
112*6dbdd20aSAndroid Build Coastguard Worker }
113*6dbdd20aSAndroid Build Coastguard Worker }
114*6dbdd20aSAndroid Build Coastguard Worker
WriteMappingPathString(const Interned<std::string> & str,protos::pbzero::InternedData * out)115*6dbdd20aSAndroid Build Coastguard Worker void InterningOutputTracker::WriteMappingPathString(
116*6dbdd20aSAndroid Build Coastguard Worker const Interned<std::string>& str,
117*6dbdd20aSAndroid Build Coastguard Worker protos::pbzero::InternedData* out) {
118*6dbdd20aSAndroid Build Coastguard Worker auto it_and_inserted = dumped_strings_.emplace(str.id(), 0);
119*6dbdd20aSAndroid Build Coastguard Worker auto it = it_and_inserted.first;
120*6dbdd20aSAndroid Build Coastguard Worker // This is for the rare case that the same string is used as two different
121*6dbdd20aSAndroid Build Coastguard Worker // types (e.g. a function name that matches a path segment). In that case
122*6dbdd20aSAndroid Build Coastguard Worker // we need to emit the string as all of its types.
123*6dbdd20aSAndroid Build Coastguard Worker if ((it->second & kDumpedMappingPath) == 0) {
124*6dbdd20aSAndroid Build Coastguard Worker protos::pbzero::InternedString* interned_string = out->add_mapping_paths();
125*6dbdd20aSAndroid Build Coastguard Worker interned_string->set_iid(str.id());
126*6dbdd20aSAndroid Build Coastguard Worker interned_string->set_str(str.data());
127*6dbdd20aSAndroid Build Coastguard Worker it->second |= kDumpedMappingPath;
128*6dbdd20aSAndroid Build Coastguard Worker }
129*6dbdd20aSAndroid Build Coastguard Worker }
130*6dbdd20aSAndroid Build Coastguard Worker
WriteFunctionNameString(const Interned<std::string> & str,protos::pbzero::InternedData * out)131*6dbdd20aSAndroid Build Coastguard Worker void InterningOutputTracker::WriteFunctionNameString(
132*6dbdd20aSAndroid Build Coastguard Worker const Interned<std::string>& str,
133*6dbdd20aSAndroid Build Coastguard Worker protos::pbzero::InternedData* out) {
134*6dbdd20aSAndroid Build Coastguard Worker auto it_and_inserted = dumped_strings_.emplace(str.id(), 0);
135*6dbdd20aSAndroid Build Coastguard Worker auto it = it_and_inserted.first;
136*6dbdd20aSAndroid Build Coastguard Worker // This is for the rare case that the same string is used as two different
137*6dbdd20aSAndroid Build Coastguard Worker // types (e.g. a function name that matches a path segment). In that case
138*6dbdd20aSAndroid Build Coastguard Worker // we need to emit the string as all of its types.
139*6dbdd20aSAndroid Build Coastguard Worker if ((it->second & kDumpedFunctionName) == 0) {
140*6dbdd20aSAndroid Build Coastguard Worker protos::pbzero::InternedString* interned_string = out->add_function_names();
141*6dbdd20aSAndroid Build Coastguard Worker interned_string->set_iid(str.id());
142*6dbdd20aSAndroid Build Coastguard Worker interned_string->set_str(str.data());
143*6dbdd20aSAndroid Build Coastguard Worker it->second |= kDumpedFunctionName;
144*6dbdd20aSAndroid Build Coastguard Worker }
145*6dbdd20aSAndroid Build Coastguard Worker }
146*6dbdd20aSAndroid Build Coastguard Worker
WriteCallstack(GlobalCallstackTrie::Node * node,GlobalCallstackTrie * trie,protos::pbzero::InternedData * out)147*6dbdd20aSAndroid Build Coastguard Worker void InterningOutputTracker::WriteCallstack(GlobalCallstackTrie::Node* node,
148*6dbdd20aSAndroid Build Coastguard Worker GlobalCallstackTrie* trie,
149*6dbdd20aSAndroid Build Coastguard Worker protos::pbzero::InternedData* out) {
150*6dbdd20aSAndroid Build Coastguard Worker bool inserted;
151*6dbdd20aSAndroid Build Coastguard Worker std::tie(std::ignore, inserted) = dumped_callstacks_.emplace(node->id());
152*6dbdd20aSAndroid Build Coastguard Worker if (inserted) {
153*6dbdd20aSAndroid Build Coastguard Worker // There need to be two separate loops over built_callstack because
154*6dbdd20aSAndroid Build Coastguard Worker // protozero cannot interleave different messages.
155*6dbdd20aSAndroid Build Coastguard Worker auto built_callstack = trie->BuildInverseCallstack(node);
156*6dbdd20aSAndroid Build Coastguard Worker for (const Interned<Frame>& frame : built_callstack)
157*6dbdd20aSAndroid Build Coastguard Worker WriteFrame(frame, out);
158*6dbdd20aSAndroid Build Coastguard Worker
159*6dbdd20aSAndroid Build Coastguard Worker protos::pbzero::Callstack* callstack = out->add_callstacks();
160*6dbdd20aSAndroid Build Coastguard Worker callstack->set_iid(node->id());
161*6dbdd20aSAndroid Build Coastguard Worker for (auto frame_it = built_callstack.crbegin();
162*6dbdd20aSAndroid Build Coastguard Worker frame_it != built_callstack.crend(); ++frame_it) {
163*6dbdd20aSAndroid Build Coastguard Worker const Interned<Frame>& frame = *frame_it;
164*6dbdd20aSAndroid Build Coastguard Worker callstack->add_frame_ids(frame.id());
165*6dbdd20aSAndroid Build Coastguard Worker }
166*6dbdd20aSAndroid Build Coastguard Worker }
167*6dbdd20aSAndroid Build Coastguard Worker }
168*6dbdd20aSAndroid Build Coastguard Worker
ClearHistory()169*6dbdd20aSAndroid Build Coastguard Worker void InterningOutputTracker::ClearHistory() {
170*6dbdd20aSAndroid Build Coastguard Worker dumped_strings_.clear();
171*6dbdd20aSAndroid Build Coastguard Worker dumped_frames_.clear();
172*6dbdd20aSAndroid Build Coastguard Worker dumped_mappings_.clear();
173*6dbdd20aSAndroid Build Coastguard Worker dumped_callstacks_.clear();
174*6dbdd20aSAndroid Build Coastguard Worker }
175*6dbdd20aSAndroid Build Coastguard Worker
176*6dbdd20aSAndroid Build Coastguard Worker } // namespace profiling
177*6dbdd20aSAndroid Build Coastguard Worker } // namespace perfetto
178