xref: /aosp_15_r20/external/perfetto/src/trace_processor/importers/instruments/row_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/instruments/row_parser.h"
18 
19 #include "perfetto/ext/base/flat_hash_map.h"
20 #include "perfetto/ext/base/string_view.h"
21 #include "src/trace_processor/importers/common/mapping_tracker.h"
22 #include "src/trace_processor/importers/common/process_tracker.h"
23 #include "src/trace_processor/importers/common/stack_profile_tracker.h"
24 #include "src/trace_processor/importers/instruments/row.h"
25 #include "src/trace_processor/importers/instruments/row_data_tracker.h"
26 
27 #if !PERFETTO_BUILDFLAG(PERFETTO_TP_INSTRUMENTS)
28 #error \
29     "This file should not be built when enable_perfetto_trace_processor_mac_instruments=false"
30 #endif
31 
32 namespace perfetto::trace_processor::instruments_importer {
33 
RowParser(TraceProcessorContext * context)34 RowParser::RowParser(TraceProcessorContext* context)
35     : context_(context), data_(RowDataTracker::GetOrCreate(context)) {}
36 
ParseInstrumentsRow(int64_t ts,instruments_importer::Row row)37 void RowParser::ParseInstrumentsRow(int64_t ts, instruments_importer::Row row) {
38   if (!row.backtrace) {
39     return;
40   }
41 
42   Thread* thread = data_.GetThread(row.thread);
43   Process* process = data_.GetProcess(thread->process);
44   uint32_t tid = static_cast<uint32_t>(thread->tid);
45   uint32_t pid = static_cast<uint32_t>(process->pid);
46 
47   UniqueTid utid = context_->process_tracker->UpdateThread(tid, pid);
48   UniquePid upid = context_->process_tracker->GetOrCreateProcess(pid);
49 
50   // TODO(leszeks): Avoid setting thread/process name if we've already seen this
51   // Thread* / Process*.
52   context_->process_tracker->UpdateThreadNameByUtid(utid, thread->fmt,
53                                                     ThreadNamePriority::kOther);
54   context_->process_tracker->SetProcessNameIfUnset(upid, process->fmt);
55 
56   auto& stack_profile_tracker = *context_->stack_profile_tracker;
57 
58   Backtrace* backtrace = data_.GetBacktrace(row.backtrace);
59   std::optional<CallsiteId> parent;
60   uint32_t depth = 0;
61   auto leaf = backtrace->frames.rend() - 1;
62   for (auto it = backtrace->frames.rbegin(); it != backtrace->frames.rend();
63        ++it) {
64     Frame* frame = data_.GetFrame(*it);
65     Binary* binary = data_.GetBinary(frame->binary);
66 
67     uint64_t rel_pc = static_cast<uint64_t>(frame->addr);
68     if (frame->binary) {
69       rel_pc -= static_cast<uint64_t>(binary->load_addr);
70     }
71 
72     // For non-leaf functions, the pc will be after the end of the call. Adjust
73     // it to be within the call instruction.
74     if (rel_pc != 0 && it != leaf) {
75       --rel_pc;
76     }
77 
78     auto frame_inserted = frame_to_frame_id_.Insert(*it, FrameId{0});
79     if (frame_inserted.second) {
80       auto mapping_inserted = binary_to_mapping_.Insert(frame->binary, nullptr);
81       if (mapping_inserted.second) {
82         if (binary == nullptr) {
83           *mapping_inserted.first = GetDummyMapping(upid);
84         } else {
85           BuildId build_id = binary->uuid;
86           *mapping_inserted.first =
87               &context_->mapping_tracker->CreateUserMemoryMapping(
88                   upid, {AddressRange(static_cast<uint64_t>(binary->load_addr),
89                                       static_cast<uint64_t>(binary->max_addr)),
90                          0, 0, 0, binary->path, build_id});
91         }
92       }
93       VirtualMemoryMapping* mapping = *mapping_inserted.first;
94 
95       // Intern the frame with no function name -- the symbolizer will annotate
96       // frames later.
97       *frame_inserted.first =
98           mapping->InternFrame(rel_pc, base::StringView(""));
99     }
100     FrameId frame_id = *frame_inserted.first;
101 
102     parent = stack_profile_tracker.InternCallsite(parent, frame_id, depth);
103     depth++;
104   }
105 
106   context_->storage->mutable_instruments_sample_table()->Insert(
107       {ts, utid, row.core_id, parent});
108 }
109 
GetDummyMapping(UniquePid upid)110 DummyMemoryMapping* RowParser::GetDummyMapping(UniquePid upid) {
111   if (auto it = dummy_mappings_.Find(upid); it) {
112     return *it;
113   }
114 
115   DummyMemoryMapping* mapping =
116       &context_->mapping_tracker->CreateDummyMapping("");
117   dummy_mappings_.Insert(upid, mapping);
118   return mapping;
119 }
120 
121 }  // namespace perfetto::trace_processor::instruments_importer
122