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