blob: 69f320cc7cb3bf309c440b73cc7f57d301f113c9 [file] [log] [blame]
Colin Cross8e8f34c2016-03-02 17:53:39 -08001/*
2 * Copyright (C) 2016 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 <inttypes.h>
18
19#include "Allocator.h"
20#include "HeapWalker.h"
21#include "LeakFolding.h"
22#include "Tarjan.h"
23#include "log.h"
24
Colin Crossa9939e92017-06-21 13:13:00 -070025namespace android {
26
Colin Cross8e8f34c2016-03-02 17:53:39 -080027// Converts possibly cyclic graph of leaks to a DAG by combining
28// strongly-connected components into a object, stored in the scc pointer
29// of each node in the component.
30void LeakFolding::ComputeDAG() {
31 SCCList<LeakInfo> scc_list{allocator_};
32 Tarjan(leak_graph_, scc_list);
33
34 Allocator<SCCInfo> scc_allocator = allocator_;
35
Colin Crossa83881e2017-06-22 10:50:05 -070036 for (auto& scc_nodes : scc_list) {
Colin Cross8e8f34c2016-03-02 17:53:39 -080037 Allocator<SCCInfo>::unique_ptr leak_scc;
38 leak_scc = scc_allocator.make_unique(scc_allocator);
39
Colin Crossa83881e2017-06-22 10:50:05 -070040 for (auto& node : scc_nodes) {
Colin Cross8e8f34c2016-03-02 17:53:39 -080041 node->ptr->scc = leak_scc.get();
42 leak_scc->count++;
43 leak_scc->size += node->ptr->range.size();
44 }
45
46 leak_scc_.emplace_back(std::move(leak_scc));
47 }
48
49 for (auto& it : leak_map_) {
50 LeakInfo& leak = it.second;
Colin Crossa83881e2017-06-22 10:50:05 -070051 for (auto& ref : leak.node.references_out) {
Colin Cross8e8f34c2016-03-02 17:53:39 -080052 if (leak.scc != ref->ptr->scc) {
53 leak.scc->node.Edge(&ref->ptr->scc->node);
54 }
55 }
56 }
57}
58
59void LeakFolding::AccumulateLeaks(SCCInfo* dominator) {
Colin Crossa83881e2017-06-22 10:50:05 -070060 std::function<void(SCCInfo*)> walk(std::allocator_arg, allocator_, [&](SCCInfo* scc) {
61 if (scc->accumulator != dominator) {
62 scc->accumulator = dominator;
63 dominator->cuumulative_size += scc->size;
64 dominator->cuumulative_count += scc->count;
65 scc->node.Foreach([&](SCCInfo* ref) { walk(ref); });
66 }
67 });
Colin Cross8e8f34c2016-03-02 17:53:39 -080068 walk(dominator);
69}
70
71bool LeakFolding::FoldLeaks() {
72 Allocator<LeakInfo> leak_allocator = allocator_;
73
74 // Find all leaked allocations insert them into leak_map_ and leak_graph_
Colin Crossa83881e2017-06-22 10:50:05 -070075 heap_walker_.ForEachAllocation([&](const Range& range, HeapWalker::AllocationInfo& allocation) {
76 if (!allocation.referenced_from_root) {
77 auto it = leak_map_.emplace(std::piecewise_construct, std::forward_as_tuple(range),
78 std::forward_as_tuple(range, allocator_));
79 LeakInfo& leak = it.first->second;
80 leak_graph_.push_back(&leak.node);
81 }
82 });
Colin Cross8e8f34c2016-03-02 17:53:39 -080083
84 // Find references between leaked allocations and connect them in leak_graph_
85 for (auto& it : leak_map_) {
86 LeakInfo& leak = it.second;
87 heap_walker_.ForEachPtrInRange(leak.range,
Colin Crossa83881e2017-06-22 10:50:05 -070088 [&](Range& ptr_range, HeapWalker::AllocationInfo* ptr_info) {
89 if (!ptr_info->referenced_from_root) {
90 LeakInfo* ptr_leak = &leak_map_.at(ptr_range);
91 leak.node.Edge(&ptr_leak->node);
92 }
93 });
Colin Cross8e8f34c2016-03-02 17:53:39 -080094 }
95
96 // Convert the cyclic graph to a DAG by grouping strongly connected components
97 ComputeDAG();
98
99 // Compute dominators and cuumulative sizes
100 for (auto& scc : leak_scc_) {
101 if (scc->node.references_in.size() == 0) {
102 scc->dominator = true;
103 AccumulateLeaks(scc.get());
104 }
105 }
106
107 return true;
108}
109
Colin Crossa83881e2017-06-22 10:50:05 -0700110bool LeakFolding::Leaked(allocator::vector<LeakFolding::Leak>& leaked, size_t* num_leaks_out,
111 size_t* leak_bytes_out) {
Colin Cross8e8f34c2016-03-02 17:53:39 -0800112 size_t num_leaks = 0;
113 size_t leak_bytes = 0;
114 for (auto& it : leak_map_) {
115 const LeakInfo& leak = it.second;
116 num_leaks++;
117 leak_bytes += leak.range.size();
118 }
119
Colin Cross8e8f34c2016-03-02 17:53:39 -0800120 for (auto& it : leak_map_) {
121 const LeakInfo& leak = it.second;
122 if (leak.scc->dominator) {
Colin Crossa83881e2017-06-22 10:50:05 -0700123 leaked.emplace_back(Leak{leak.range, leak.scc->cuumulative_count - 1,
124 leak.scc->cuumulative_size - leak.range.size()});
Colin Cross8e8f34c2016-03-02 17:53:39 -0800125 }
126 }
127
128 if (num_leaks_out) {
129 *num_leaks_out = num_leaks;
130 }
131 if (leak_bytes_out) {
132 *leak_bytes_out = leak_bytes;
133 }
134
135 return true;
136}
Colin Crossa9939e92017-06-21 13:13:00 -0700137
138} // namespace android