1 /* 2 * Copyright (C) 2015 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 package com.android.ahat.heapdump; 18 19 import java.util.ArrayList; 20 import java.util.Arrays; 21 import java.util.Comparator; 22 import java.util.Iterator; 23 import java.util.List; 24 25 /** 26 * Provides Comparators and helper functions for sorting Instances, Sites, and 27 * other things. 28 * <p> 29 * Note: The Comparators defined here impose orderings that are inconsistent 30 * with equals. They should not be used for element lookup or search. They 31 * should only be used for showing elements to the user in different orders. 32 */ 33 public class Sort { 34 /** 35 * Compares sizes by their total size. 36 * This sorts sizes from smaller total size to larger total size. 37 */ 38 public static final Comparator<Size> SIZE_BY_SIZE = new Comparator<Size>() { 39 @Override 40 public int compare(Size a, Size b) { 41 return Long.compare(a.getSize(), b.getSize()); 42 } 43 }; 44 45 /** 46 * Compares instances by their total retained size. 47 * Different instances with the same total retained size are considered 48 * equal for the purposes of comparison. 49 * This sorts instances from larger retained size to smaller retained size. 50 */ 51 public static final Comparator<AhatInstance> INSTANCE_BY_TOTAL_RETAINED_SIZE 52 = new Comparator<AhatInstance>() { 53 @Override 54 public int compare(AhatInstance a, AhatInstance b) { 55 return SIZE_BY_SIZE.compare(b.getTotalRetainedSize(), a.getTotalRetainedSize()); 56 } 57 }; 58 59 /** 60 * Compares instances by their retained size for a given heap index. 61 * Different instances with the same total retained size are considered 62 * equal for the purposes of comparison. 63 * This sorts instances from larger retained size to smaller retained size. 64 */ 65 private static class InstanceByHeapRetainedSize implements Comparator<AhatInstance> { 66 private AhatHeap mHeap; 67 InstanceByHeapRetainedSize(AhatHeap heap)68 public InstanceByHeapRetainedSize(AhatHeap heap) { 69 mHeap = heap; 70 } 71 72 @Override compare(AhatInstance a, AhatInstance b)73 public int compare(AhatInstance a, AhatInstance b) { 74 return SIZE_BY_SIZE.compare(b.getRetainedSize(mHeap), a.getRetainedSize(mHeap)); 75 } 76 } 77 78 /** 79 * Compares objects based on a list of comparators, giving priority to the 80 * earlier comparators in the list. 81 */ 82 private static class WithPriority<T> implements Comparator<T> { 83 private List<Comparator<T>> mComparators; 84 85 /** 86 * Constructs a comparator giving sort priority to earlier comparators in 87 * the list. 88 * 89 * @param comparators the list of comparators to use for sorting 90 */ WithPriority(Comparator<T>.... comparators)91 public WithPriority(Comparator<T>... comparators) { 92 mComparators = Arrays.asList(comparators); 93 } 94 95 /** 96 * Constructs a comparator giving sort priority to earlier comparators in 97 * the list. 98 * 99 * @param comparators the list of comparators to use for sorting 100 */ WithPriority(List<Comparator<T>> comparators)101 public WithPriority(List<Comparator<T>> comparators) { 102 mComparators = comparators; 103 } 104 105 @Override compare(T a, T b)106 public int compare(T a, T b) { 107 int res = 0; 108 Iterator<Comparator<T>> iter = mComparators.iterator(); 109 while (res == 0 && iter.hasNext()) { 110 res = iter.next().compare(a, b); 111 } 112 return res; 113 } 114 } 115 116 /** 117 * Returns a comparator that gives sort priority to earlier comparators in 118 * the list. 119 * 120 * @param <T> the type of object being sorted 121 * @param comparators the list of comparators to use for sorting 122 * @return the composite comparator 123 */ withPriority(Comparator<T>.... comparators)124 public static <T> Comparator<T> withPriority(Comparator<T>... comparators) { 125 return new WithPriority(comparators); 126 } 127 128 /** 129 * Returns a comparator that gives a default instance sort for the given 130 * snapshot. 131 * Objects are sorted by retained size, with priority given to the "app" 132 * heap if present. 133 * 134 * @param snapshot the snapshot to use the comparator with 135 * @return the default instance comparator 136 */ defaultInstanceCompare(AhatSnapshot snapshot)137 public static Comparator<AhatInstance> defaultInstanceCompare(AhatSnapshot snapshot) { 138 List<Comparator<AhatInstance>> comparators = new ArrayList<Comparator<AhatInstance>>(); 139 140 // Priority goes to the app heap, if we can find one. 141 AhatHeap appHeap = snapshot.getHeap("app"); 142 if (appHeap != null) { 143 comparators.add(new InstanceByHeapRetainedSize(appHeap)); 144 } 145 146 // Next is by total retained size. 147 comparators.add(INSTANCE_BY_TOTAL_RETAINED_SIZE); 148 return new WithPriority<AhatInstance>(comparators); 149 } 150 151 /** 152 * Compares Sites by the size of objects allocated on a given heap. 153 * Different object infos with the same size on the given heap are 154 * considered equal for the purposes of comparison. 155 * This sorts sites from larger size to smaller size. 156 */ 157 private static class SiteByHeapSize implements Comparator<Site> { 158 AhatHeap mHeap; 159 160 /** 161 * Constructs a SiteByHeapSize comparator. 162 * 163 * @param heap the heap to use when comparing sizes 164 */ SiteByHeapSize(AhatHeap heap)165 public SiteByHeapSize(AhatHeap heap) { 166 mHeap = heap; 167 } 168 169 @Override compare(Site a, Site b)170 public int compare(Site a, Site b) { 171 return SIZE_BY_SIZE.compare(b.getSize(mHeap), a.getSize(mHeap)); 172 } 173 } 174 175 /** 176 * Compares Sites by the total size of objects allocated. 177 * This sorts sites from larger size to smaller size. 178 */ 179 public static final Comparator<Site> SITE_BY_TOTAL_SIZE = new Comparator<Site>() { 180 @Override 181 public int compare(Site a, Site b) { 182 return SIZE_BY_SIZE.compare(b.getTotalSize(), a.getTotalSize()); 183 } 184 }; 185 186 /** 187 * Compares Sites using a default comparison order. 188 * This sorts sites from larger size to smaller size, giving preference to 189 * sites with more allocation on the "app" heap, if present. 190 * 191 * @param snapshot the snapshot to use the comparator with 192 * @return the default site comparator 193 */ defaultSiteCompare(AhatSnapshot snapshot)194 public static Comparator<Site> defaultSiteCompare(AhatSnapshot snapshot) { 195 List<Comparator<Site>> comparators = new ArrayList<Comparator<Site>>(); 196 197 // Priority goes to the app heap, if we can find one. 198 AhatHeap appHeap = snapshot.getHeap("app"); 199 if (appHeap != null) { 200 comparators.add(new SiteByHeapSize(appHeap)); 201 } 202 203 // Next is by total size. 204 comparators.add(SITE_BY_TOTAL_SIZE); 205 return new WithPriority<Site>(comparators); 206 } 207 208 /** 209 * Compare Site.ObjectsInfo by their size. 210 * Different object infos with the same total retained size are considered 211 * equal for the purposes of comparison. 212 * This sorts object infos from larger retained size to smaller size. 213 */ 214 public static final Comparator<Site.ObjectsInfo> OBJECTS_INFO_BY_SIZE 215 = new Comparator<Site.ObjectsInfo>() { 216 @Override 217 public int compare(Site.ObjectsInfo a, Site.ObjectsInfo b) { 218 return SIZE_BY_SIZE.compare(b.numBytes, a.numBytes); 219 } 220 }; 221 222 /** 223 * Compares Site.ObjectsInfo by heap name. 224 * Different object infos with the same heap name are considered equal for 225 * the purposes of comparison. 226 */ 227 public static final Comparator<Site.ObjectsInfo> OBJECTS_INFO_BY_HEAP_NAME 228 = new Comparator<Site.ObjectsInfo>() { 229 @Override 230 public int compare(Site.ObjectsInfo a, Site.ObjectsInfo b) { 231 return a.heap.getName().compareTo(b.heap.getName()); 232 } 233 }; 234 235 /** 236 * Compares Site.ObjectsInfo by class name. 237 * Different object infos with the same class name are considered equal for 238 * the purposes of comparison. 239 */ 240 public static final Comparator<Site.ObjectsInfo> OBJECTS_INFO_BY_CLASS_NAME 241 = new Comparator<Site.ObjectsInfo>() { 242 @Override 243 public int compare(Site.ObjectsInfo a, Site.ObjectsInfo b) { 244 String aName = a.getClassName(); 245 String bName = b.getClassName(); 246 return aName.compareTo(bName); 247 } 248 }; 249 250 /** 251 * Compares FieldValue by field name. 252 */ 253 public static final Comparator<FieldValue> FIELD_VALUE_BY_NAME 254 = new Comparator<FieldValue>() { 255 @Override 256 public int compare(FieldValue a, FieldValue b) { 257 return a.name.compareTo(b.name); 258 } 259 }; 260 261 /** 262 * Compares FieldValue by type name. 263 */ 264 public static final Comparator<FieldValue> FIELD_VALUE_BY_TYPE 265 = new Comparator<FieldValue>() { 266 @Override 267 public int compare(FieldValue a, FieldValue b) { 268 return a.type.compareTo(b.type); 269 } 270 }; 271 } 272 273