1 /* 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 25 // Converts possibly cyclic graph of leaks to a DAG by combining 26 // strongly-connected components into a object, stored in the scc pointer 27 // of each node in the component. 28 void LeakFolding::ComputeDAG() { 29 SCCList<LeakInfo> scc_list{allocator_}; 30 Tarjan(leak_graph_, scc_list); 31 32 Allocator<SCCInfo> scc_allocator = allocator_; 33 34 for (auto& scc_nodes: scc_list) { 35 Allocator<SCCInfo>::unique_ptr leak_scc; 36 leak_scc = scc_allocator.make_unique(scc_allocator); 37 38 for (auto& node: scc_nodes) { 39 node->ptr->scc = leak_scc.get(); 40 leak_scc->count++; 41 leak_scc->size += node->ptr->range.size(); 42 } 43 44 leak_scc_.emplace_back(std::move(leak_scc)); 45 } 46 47 for (auto& it : leak_map_) { 48 LeakInfo& leak = it.second; 49 for (auto& ref: leak.node.references_out) { 50 if (leak.scc != ref->ptr->scc) { 51 leak.scc->node.Edge(&ref->ptr->scc->node); 52 } 53 } 54 } 55 } 56 57 void LeakFolding::AccumulateLeaks(SCCInfo* dominator) { 58 std::function<void(SCCInfo*)> walk(std::allocator_arg, allocator_, 59 [&](SCCInfo* scc) { 60 if (scc->accumulator != dominator) { 61 scc->accumulator = dominator; 62 dominator->cuumulative_size += scc->size; 63 dominator->cuumulative_count += scc->count; 64 scc->node.Foreach([&](SCCInfo* ref) { 65 walk(ref); 66 }); 67 } 68 }); 69 walk(dominator); 70 } 71 72 bool LeakFolding::FoldLeaks() { 73 Allocator<LeakInfo> leak_allocator = allocator_; 74 75 // Find all leaked allocations insert them into leak_map_ and leak_graph_ 76 heap_walker_.ForEachAllocation( 77 [&](const Range& range, HeapWalker::AllocationInfo& allocation) { 78 if (!allocation.referenced_from_root) { 79 auto it = leak_map_.emplace(std::piecewise_construct, 80 std::forward_as_tuple(range), 81 std::forward_as_tuple(range, allocator_)); 82 LeakInfo& leak = it.first->second; 83 leak_graph_.push_back(&leak.node); 84 } 85 }); 86 87 // Find references between leaked allocations and connect them in leak_graph_ 88 for (auto& it : leak_map_) { 89 LeakInfo& leak = it.second; 90 heap_walker_.ForEachPtrInRange(leak.range, 91 [&](Range& ptr_range, HeapWalker::AllocationInfo* ptr_info) { 92 if (!ptr_info->referenced_from_root) { 93 LeakInfo* ptr_leak = &leak_map_.at(ptr_range); 94 leak.node.Edge(&ptr_leak->node); 95 } 96 }); 97 } 98 99 // Convert the cyclic graph to a DAG by grouping strongly connected components 100 ComputeDAG(); 101 102 // Compute dominators and cuumulative sizes 103 for (auto& scc : leak_scc_) { 104 if (scc->node.references_in.size() == 0) { 105 scc->dominator = true; 106 AccumulateLeaks(scc.get()); 107 } 108 } 109 110 return true; 111 } 112 113 bool LeakFolding::Leaked(allocator::vector<LeakFolding::Leak>& leaked, 114 size_t* num_leaks_out, size_t* leak_bytes_out) { 115 size_t num_leaks = 0; 116 size_t leak_bytes = 0; 117 for (auto& it : leak_map_) { 118 const LeakInfo& leak = it.second; 119 num_leaks++; 120 leak_bytes += leak.range.size(); 121 } 122 123 for (auto& it : leak_map_) { 124 const LeakInfo& leak = it.second; 125 if (leak.scc->dominator) { 126 leaked.emplace_back(Leak{leak.range, 127 leak.scc->cuumulative_count - 1, 128 leak.scc->cuumulative_size - leak.range.size()}); 129 } 130 } 131 132 if (num_leaks_out) { 133 *num_leaks_out = num_leaks; 134 } 135 if (leak_bytes_out) { 136 *leak_bytes_out = leak_bytes; 137 } 138 139 return true; 140 } 141