1 /* 2 * Copyright (C) 2019 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 #ifndef SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PROFILE_PACKET_SEQUENCE_STATE_H_ 18 #define SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PROFILE_PACKET_SEQUENCE_STATE_H_ 19 20 #include <cstdint> 21 #include "perfetto/base/flat_set.h" 22 #include "perfetto/ext/base/flat_hash_map.h" 23 24 #include "perfetto/ext/base/hash.h" 25 #include "perfetto/ext/base/string_view.h" 26 #include "src/trace_processor/importers/proto/packet_sequence_state_generation.h" 27 #include "src/trace_processor/importers/proto/stack_profile_sequence_state.h" 28 #include "src/trace_processor/storage/trace_storage.h" 29 30 namespace perfetto { 31 namespace trace_processor { 32 33 class VirtualMemoryMapping; 34 35 // Keeps sequence specific state for profile packets. 36 class ProfilePacketSequenceState final 37 : public PacketSequenceStateGeneration::CustomState { 38 public: 39 using SourceStringId = uint64_t; 40 41 struct SourceMapping { 42 SourceStringId build_id = 0; 43 uint64_t exact_offset = 0; 44 uint64_t start_offset = 0; 45 uint64_t start = 0; 46 uint64_t end = 0; 47 uint64_t load_bias = 0; 48 std::vector<SourceStringId> name_ids; 49 }; 50 using SourceMappingId = uint64_t; 51 52 struct SourceFrame { 53 SourceStringId name_id = 0; 54 SourceMappingId mapping_id = 0; 55 uint64_t rel_pc = 0; 56 }; 57 using SourceFrameId = uint64_t; 58 59 using SourceCallstack = std::vector<SourceFrameId>; 60 using SourceCallstackId = uint64_t; 61 struct SourceAllocation { 62 uint64_t pid = 0; 63 // This is int64_t, because we get this from the TraceSorter which also 64 // converts this for us. 65 int64_t timestamp = 0; 66 StringId heap_name; 67 uint64_t callstack_id = 0; 68 uint64_t self_allocated = 0; 69 uint64_t self_freed = 0; 70 uint64_t alloc_count = 0; 71 uint64_t free_count = 0; 72 }; 73 74 explicit ProfilePacketSequenceState(TraceProcessorContext* context); 75 virtual ~ProfilePacketSequenceState() override; 76 77 // Profile packets keep track of a index to detect packet loss. Call this 78 // method to update this index with the latest seen value. 79 void SetProfilePacketIndex(uint64_t index); 80 81 // In Android version Q we did not intern Mappings, Frames nor Callstacks, 82 // instead the profile packed "interned these". The following methods are used 83 // to support this old use case. They add the given object to a sequence local 84 // index for them to be retrieved later (see Find* Lookup* methods). 85 void AddString(SourceStringId id, base::StringView str); 86 void AddMapping(SourceMappingId id, const SourceMapping& mapping); 87 void AddFrame(SourceFrameId id, const SourceFrame& frame); 88 void AddCallstack(SourceCallstackId id, const SourceCallstack& callstack); 89 90 void StoreAllocation(const SourceAllocation& allocation); 91 void FinalizeProfile(); 92 void CommitAllocations(); 93 94 FrameId GetDatabaseFrameIdForTesting(SourceFrameId); 95 96 private: 97 struct SourceAllocationIndex { 98 UniquePid upid; 99 SourceCallstackId src_callstack_id; 100 StringPool::Id heap_name; 101 bool operator==(const SourceAllocationIndex& o) const { 102 return std::tie(upid, src_callstack_id, heap_name) == 103 std::tie(o.upid, o.src_callstack_id, o.heap_name); 104 } 105 struct Hasher { operatorSourceAllocationIndex::Hasher106 size_t operator()(const SourceAllocationIndex& o) const { 107 return static_cast<size_t>(base::Hasher::Combine( 108 o.upid, o.src_callstack_id, o.heap_name.raw_id())); 109 } 110 }; 111 }; 112 113 void AddAllocation(const SourceAllocation& alloc); 114 115 // The following methods deal with interned data. In Android version Q we did 116 // not intern Mappings, Frames nor Callstacks, instead the profile packed 117 // "interned these" and this class keeps those ina sequence local index. In 118 // newer versions, these objects are in InternedData (see 119 // protos/perfetto/trace/interned_data) and are shared across multiple 120 // ProfilePackets. For backwards compatibility, the following methods first 121 // look up interned data in the private sequence local index (for values added 122 // via the Add* methods), and then, if this lookup fails, in the InternedData 123 // instead. 124 std::optional<MappingId> FindOrInsertMapping(uint64_t iid); 125 std::optional<CallsiteId> FindOrInsertCallstack(UniquePid upid, uint64_t iid); 126 127 TraceProcessorContext* const context_; 128 129 base::FlatHashMap<SourceStringId, std::string> strings_; 130 base::FlatHashMap<SourceMappingId, VirtualMemoryMapping*> mappings_; 131 base::FlatHashMap<SourceFrameId, FrameId> frames_; 132 base::FlatHashMap<SourceCallstackId, CallsiteId> callstacks_; 133 134 std::vector<SourceAllocation> pending_allocs_; 135 136 struct Hasher { operatorHasher137 size_t operator()(const std::pair<UniquePid, CallsiteId>& p) const { 138 return static_cast<size_t>( 139 base::Hasher::Combine(p.first, p.second.value)); 140 } 141 }; 142 base::FlatHashMap<std::pair<UniquePid, CallsiteId>, 143 tables::HeapProfileAllocationTable::Row, 144 Hasher> 145 prev_alloc_; 146 base::FlatHashMap<std::pair<UniquePid, CallsiteId>, 147 tables::HeapProfileAllocationTable::Row, 148 Hasher> 149 prev_free_; 150 151 // For continuous dumps, we only store the delta in the data-base. To do 152 // this, we subtract the previous dump's value. Sometimes, we should not 153 // do that subtraction, because heapprofd garbage collects stacks that 154 // have no unfreed allocations. If the application then allocations again 155 // at that stack, it gets recreated and initialized to zero. 156 // 157 // To correct for this, we add the previous' stacks value to the current 158 // one, and then handle it as normal. If it is the first time we see a 159 // SourceCallstackId for a CallsiteId, we put the previous value into 160 // the correction maps below. 161 base::FlatHashMap<SourceAllocationIndex, 162 base::FlatSet<CallsiteId>, 163 SourceAllocationIndex::Hasher> 164 seen_callstacks_; 165 base::FlatHashMap<SourceCallstackId, tables::HeapProfileAllocationTable::Row> 166 alloc_correction_; 167 base::FlatHashMap<SourceCallstackId, tables::HeapProfileAllocationTable::Row> 168 free_correction_; 169 170 std::optional<uint64_t> prev_index; 171 }; 172 173 } // namespace trace_processor 174 } // namespace perfetto 175 176 #endif // SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PROFILE_PACKET_SEQUENCE_STATE_H_ 177