1 /* 2 * Copyright (C) 2018 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 android.util.imagepool; 18 19 import java.lang.management.GarbageCollectorMXBean; 20 import java.lang.management.ManagementFactory; 21 import java.util.HashMap; 22 import java.util.Map; 23 24 import com.google.common.collect.HashMultiset; 25 import com.google.common.collect.Multiset; 26 27 /** 28 * Useful impl for debugging reproable error. 29 */ 30 public class ImagePoolStatsDebugImpl extends ImagePoolStatsProdImpl { 31 32 private static String PACKAGE_NAME = ImagePoolStats.class.getPackage().getName(); 33 34 // Used for deugging purposes only. 35 private final Map<Integer, String> mCallStack = new HashMap<>(); 36 private long mRequestedTotalBytes = 0; 37 private long mAllocatedOutsidePoolBytes = 0; 38 39 // Used for gc-related stats. 40 private long mPreviousGcCollection = 0; 41 private long mPreviousGcTime = 0; 42 43 /** Used for policy */ 44 @Override recordBucketCreation(int widthBucket, int heightBucket)45 public void recordBucketCreation(int widthBucket, int heightBucket) { 46 super.recordBucketCreation(widthBucket, heightBucket); 47 } 48 49 @Override fitsMaxCacheSize(int width, int height, long maxCacheSize)50 public boolean fitsMaxCacheSize(int width, int height, long maxCacheSize) { 51 return super.fitsMaxCacheSize(width, height, maxCacheSize); 52 } 53 54 @Override clear()55 public void clear() { 56 super.clear(); 57 58 mRequestedTotalBytes = 0; 59 mAllocatedOutsidePoolBytes = 0; 60 mTooBigForPoolCount = 0; 61 mCallStack.clear(); 62 } 63 64 @Override tooBigForCache()65 public void tooBigForCache() { 66 super.tooBigForCache(); 67 } 68 69 /** Used for Debugging only */ 70 @Override recordBucketRequest(int w, int h)71 public void recordBucketRequest(int w, int h) { 72 mRequestedTotalBytes += (w * h * ESTIMATED_PIXEL_BYTES); 73 } 74 75 @Override recordAllocOutsidePool(int width, int height)76 public void recordAllocOutsidePool(int width, int height) { 77 mAllocatedOutsidePoolBytes += (width * height * ESTIMATED_PIXEL_BYTES); 78 } 79 80 @Override acquiredImage(Integer imageHash)81 public void acquiredImage(Integer imageHash) { 82 for (int i = 1; i < Thread.currentThread().getStackTrace().length; i++) { 83 StackTraceElement element = Thread.currentThread().getStackTrace()[i]; 84 String str = element.toString(); 85 86 if (!str.contains(PACKAGE_NAME)) { 87 mCallStack.put(imageHash, str); 88 break; 89 } 90 } 91 } 92 93 @Override disposeImage(Integer imageHash)94 public void disposeImage(Integer imageHash) { 95 mCallStack.remove(imageHash); 96 } 97 98 @Override start()99 public void start() { 100 long totalGarbageCollections = 0; 101 long garbageCollectionTime = 0; 102 for (GarbageCollectorMXBean gc : ManagementFactory.getGarbageCollectorMXBeans()) { 103 long count = gc.getCollectionCount(); 104 if (count >= 0) { 105 totalGarbageCollections += count; 106 } 107 long time = gc.getCollectionTime(); 108 if (time >= 0) { 109 garbageCollectionTime += time; 110 } 111 } 112 mPreviousGcCollection = totalGarbageCollections; 113 mPreviousGcTime = garbageCollectionTime; 114 } 115 calculateGcStatAndReturn()116 private String calculateGcStatAndReturn() { 117 long totalGarbageCollections = 0; 118 long garbageCollectionTime = 0; 119 for (GarbageCollectorMXBean gc : ManagementFactory.getGarbageCollectorMXBeans()) { 120 long count = gc.getCollectionCount(); 121 if (count > 0) { 122 totalGarbageCollections += count; 123 } 124 long time = gc.getCollectionTime(); 125 if(time > 0) { 126 garbageCollectionTime += time; 127 } 128 } 129 totalGarbageCollections -= mPreviousGcCollection; 130 garbageCollectionTime -= mPreviousGcTime; 131 132 StringBuilder builder = new StringBuilder(); 133 builder.append("Total Garbage Collections: "); 134 builder.append(totalGarbageCollections); 135 builder.append("\n"); 136 137 builder.append("Total Garbage Collection Time (ms): "); 138 builder.append(garbageCollectionTime); 139 builder.append("\n"); 140 141 return builder.toString(); 142 } 143 144 @Override getStatistic()145 public String getStatistic() { 146 StringBuilder builder = new StringBuilder(); 147 148 builder.append(calculateGcStatAndReturn()); 149 builder.append("Memory\n"); 150 builder.append(" requested total : "); 151 builder.append(mRequestedTotalBytes / 1_000_000); 152 builder.append(" MB\n"); 153 builder.append(" allocated (in pool) : "); 154 builder.append(mAllocateTotalBytes / 1_000_000); 155 builder.append(" MB\n"); 156 builder.append(" allocated (out of pool) : "); 157 builder.append(mAllocatedOutsidePoolBytes / 1_000_000); 158 builder.append(" MB\n"); 159 160 double percent = (1.0 - (double) mRequestedTotalBytes / (mAllocateTotalBytes + 161 mAllocatedOutsidePoolBytes)); 162 if (percent < 0.0) { 163 builder.append(" saved : "); 164 builder.append(-1.0 * percent); 165 builder.append("%\n"); 166 } else { 167 builder.append(" wasting : "); 168 builder.append(percent); 169 builder.append("%\n"); 170 } 171 172 builder.append("Undispose images\n"); 173 Multiset<String> countSet = HashMultiset.create(); 174 for (String callsite : mCallStack.values()) { 175 countSet.add(callsite); 176 } 177 178 for (Multiset.Entry<String> entry : countSet.entrySet()) { 179 builder.append(" - "); 180 builder.append(entry.getElement()); 181 builder.append(" - missed dispose : "); 182 builder.append(entry.getCount()); 183 builder.append(" times\n"); 184 } 185 186 builder.append("Number of times requested image didn't fit the pool : "); 187 builder.append(mTooBigForPoolCount); 188 builder.append("\n"); 189 190 return builder.toString(); 191 } 192 } 193