• 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 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