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_HEAP_PROFILE_TRACKER_H_ 18 #define SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_HEAP_PROFILE_TRACKER_H_ 19 20 #include <set> 21 #include <unordered_map> 22 23 #include "perfetto/ext/base/optional.h" 24 #include "src/trace_processor/importers/proto/stack_profile_tracker.h" 25 #include "src/trace_processor/storage/trace_storage.h" 26 27 namespace perfetto { 28 namespace trace_processor { 29 30 class TraceProcessorContext; 31 32 class HeapProfileTracker { 33 public: 34 struct SourceAllocation { 35 uint64_t pid = 0; 36 // This is int64_t, because we get this from the TraceSorter which also 37 // converts this for us. 38 int64_t timestamp = 0; 39 StringPool::Id heap_name; 40 SequenceStackProfileTracker::SourceCallstackId callstack_id = 0; 41 uint64_t self_allocated = 0; 42 uint64_t self_freed = 0; 43 uint64_t alloc_count = 0; 44 uint64_t free_count = 0; 45 }; 46 47 void SetProfilePacketIndex(uint32_t seq_id, uint64_t id); 48 49 explicit HeapProfileTracker(TraceProcessorContext* context); 50 51 void StoreAllocation(uint32_t seq_id, SourceAllocation); 52 53 // Call after the last profile packet of a dump to commit the allocations 54 // that had been stored using StoreAllocation and clear internal indices 55 // for that dump. 56 void FinalizeProfile( 57 uint32_t seq_id, 58 SequenceStackProfileTracker* sequence_stack_profile_tracker, 59 const SequenceStackProfileTracker::InternLookup* lookup); 60 61 // Only commit the allocations that had been stored using StoreAllocations. 62 // This is only needed in tests, use FinalizeProfile instead. 63 void CommitAllocations( 64 uint32_t seq_id, 65 SequenceStackProfileTracker* sequence_stack_profile_tracker, 66 const SequenceStackProfileTracker::InternLookup* lookup); 67 68 void NotifyEndOfFile(); 69 70 ~HeapProfileTracker(); 71 72 private: 73 void AddAllocation( 74 uint32_t seq_id, 75 SequenceStackProfileTracker* sequence_stack_profile_tracker, 76 const SourceAllocation&, 77 const SequenceStackProfileTracker::InternLookup* intern_lookup = nullptr); 78 struct SourceAllocationIndex { 79 UniquePid upid; 80 SequenceStackProfileTracker::SourceCallstackId src_callstack_id; 81 StringPool::Id heap_name; 82 bool operator<(const SourceAllocationIndex& o) const { 83 return std::tie(upid, src_callstack_id, heap_name) < 84 std::tie(o.upid, o.src_callstack_id, o.heap_name); 85 } 86 }; 87 struct SequenceState { 88 std::vector<SourceAllocation> pending_allocs; 89 90 std::unordered_map<std::pair<UniquePid, CallsiteId>, 91 tables::HeapProfileAllocationTable::Row> 92 prev_alloc; 93 std::unordered_map<std::pair<UniquePid, CallsiteId>, 94 tables::HeapProfileAllocationTable::Row> 95 prev_free; 96 97 // For continuous dumps, we only store the delta in the data-base. To do 98 // this, we subtract the previous dump's value. Sometimes, we should not 99 // do that subtraction, because heapprofd garbage collects stacks that 100 // have no unfreed allocations. If the application then allocations again 101 // at that stack, it gets recreated and initialized to zero. 102 // 103 // To correct for this, we add the previous' stacks value to the current 104 // one, and then handle it as normal. If it is the first time we see a 105 // SourceCallstackId for a CallsiteId, we put the previous value into 106 // the correction maps below. 107 std::map<SourceAllocationIndex, std::set<CallsiteId>> seen_callstacks; 108 std::map<SequenceStackProfileTracker::SourceCallstackId, 109 tables::HeapProfileAllocationTable::Row> 110 alloc_correction; 111 std::map<SequenceStackProfileTracker::SourceCallstackId, 112 tables::HeapProfileAllocationTable::Row> 113 free_correction; 114 115 base::Optional<uint64_t> prev_index; 116 }; 117 std::map<uint32_t, SequenceState> sequence_state_; 118 TraceProcessorContext* const context_; 119 const StringId empty_; 120 const StringId art_heap_; 121 }; 122 123 } // namespace trace_processor 124 } // namespace perfetto 125 126 #endif // SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_HEAP_PROFILE_TRACKER_H_ 127