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/etm/virtual_address_space.h"
18
19 #include <cstdint>
20 #include <limits>
21 #include <optional>
22 #include <set>
23 #include <utility>
24 #include <vector>
25
26 #include "perfetto/base/logging.h"
27 #include "perfetto/trace_processor/trace_blob_view.h"
28 #include "src/trace_processor/importers/common/address_range.h"
29 #include "src/trace_processor/importers/etm/file_tracker.h"
30 #include "src/trace_processor/importers/etm/mapping_version.h"
31 #include "src/trace_processor/storage/trace_storage.h"
32 #include "src/trace_processor/tables/perf_tables_py.h"
33 #include "src/trace_processor/tables/profiler_tables_py.h"
34 #include "src/trace_processor/types/trace_processor_context.h"
35
36 namespace perfetto::trace_processor::etm {
AddMapping(tables::MmapRecordTable::ConstRowReference mmap)37 void VirtualAddressSpace::Builder::AddMapping(
38 tables::MmapRecordTable::ConstRowReference mmap) {
39 const auto mapping =
40 *context_->storage->stack_profile_mapping_table().FindById(
41 mmap.mapping_id());
42 if (static_cast<uint64_t>(mapping.start()) >=
43 static_cast<uint64_t>(mapping.end())) {
44 return;
45 }
46
47 AddressRange range(static_cast<uint64_t>(mapping.start()),
48 static_cast<uint64_t>(mapping.end()));
49
50 std::optional<TraceBlobView> content;
51 if (mmap.file_id()) {
52 content = FileTracker::GetOrCreate(context_)->GetContent(*mmap.file_id());
53 auto file_range = AddressRange::FromStartAndSize(0, content->size());
54 auto required_file_range = AddressRange::FromStartAndSize(
55 static_cast<uint64_t>(mapping.exact_offset()), range.size());
56
57 PERFETTO_CHECK(file_range.Contains(required_file_range));
58
59 content = content->slice_off(required_file_range.start(),
60 required_file_range.length());
61 }
62
63 auto [it, success] = mappings_.insert(
64 MappingVersion(mmap.mapping_id(), mmap.ts(), range, std::move(content)));
65 PERFETTO_CHECK(success);
66 vertices_.insert(it->start());
67 vertices_.insert(it->end());
68 }
69
Build()70 VirtualAddressSpace VirtualAddressSpace::Builder::Build() && {
71 std::vector<MappingVersion> slabs;
72 // Go over the mappins and process each vertex.
73 while (!mappings_.empty()) {
74 auto node = mappings_.extract(mappings_.begin());
75 auto end = vertices_.begin();
76 // Mapping starts at the vertex, noting to do.
77 while (*end <= node.value().start()) {
78 end = vertices_.erase(end);
79 }
80 // The mapping ends at this vertex, no need to split it.
81 if (node.value().end() == *end) {
82 slabs.push_back(std::move(node.value()));
83 }
84 // Split needed
85 else {
86 slabs.push_back(node.value().SplitFront(*end));
87 mappings_.insert(std::move(node));
88 }
89 }
90
91 return VirtualAddressSpace(std::move(slabs));
92 }
93
FindMapping(int64_t ts,uint64_t address) const94 const MappingVersion* VirtualAddressSpace::FindMapping(int64_t ts,
95 uint64_t address) const {
96 if (address == std::numeric_limits<uint64_t>::max()) {
97 return nullptr;
98 }
99
100 auto it = std::lower_bound(mappings_.begin(), mappings_.end(),
101 LookupKey{address, ts}, Lookup());
102
103 if (it == mappings_.end() || address < it->start()) {
104 return nullptr;
105 }
106 return &*it;
107 }
108
109 } // namespace perfetto::trace_processor::etm
110