1 /* 2 * Copyright (C) 2017 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 libcore.heapmetrics; 18 19 import com.android.ahat.heapdump.AhatHeap; 20 import com.android.ahat.heapdump.AhatInstance; 21 import com.android.ahat.heapdump.AhatSnapshot; 22 import com.android.ahat.heapdump.Size; 23 import com.android.tradefed.device.DeviceNotAvailableException; 24 import com.android.tradefed.device.ITestDevice; 25 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; 26 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner.TestLogData; 27 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner.TestMetrics; 28 import com.android.tradefed.testtype.IDeviceTest; 29 30 import org.junit.Before; 31 import org.junit.Rule; 32 import org.junit.Test; 33 import org.junit.runner.RunWith; 34 35 import java.util.EnumMap; 36 import java.util.Map; 37 import libcore.heapmetrics.HeapCategorization.HeapCategory; 38 39 /** 40 * Tests that gather metrics about zygote+image heap and about the impact of core library calls on 41 * app heap. 42 */ 43 @RunWith(DeviceJUnit4ClassRunner.class) 44 public class LibcoreHeapMetricsTest implements IDeviceTest { 45 46 @Rule public TestMetrics metrics = new TestMetrics(); 47 @Rule public TestLogData logs = new TestLogData(); 48 49 private ITestDevice testDevice; 50 private MetricsRunner metricsRunner; 51 52 @Override setDevice(ITestDevice device)53 public void setDevice(ITestDevice device) { 54 testDevice = device; 55 } 56 57 @Override getDevice()58 public ITestDevice getDevice() { 59 return testDevice; 60 } 61 62 @Before initializeHeapDumperRunner()63 public void initializeHeapDumperRunner() throws DeviceNotAvailableException { 64 metricsRunner = MetricsRunner.create(testDevice, logs); 65 } 66 67 @Test measureNoop()68 public void measureNoop() throws Exception { 69 MetricsRunner.Result result = metricsRunner.runAllInstrumentations("NOOP"); 70 AhatSnapshot beforeDump = result.getBeforeDump(); 71 AhatSnapshot afterDump = result.getAfterDump(); 72 recordHeapMetrics(beforeDump, "zygoteSize", "zygote"); 73 recordHeapMetrics(beforeDump, "imageSize", "image"); 74 Map<HeapCategory, Size> zygoteAndImageSizesByCategory = HeapCategorization 75 .of(beforeDump, beforeDump.getHeap("zygote"), beforeDump.getHeap("image")) 76 .sizesByCategory(); 77 for (Map.Entry<HeapCategory, Size> entry : zygoteAndImageSizesByCategory.entrySet()) { 78 recordSizeMetric(entry.getKey().metricName("zygoteAndImage_"), entry.getValue()); 79 } 80 recordBeforeAndAfterAppHeapMetrics(beforeDump, afterDump); 81 recordBytesMetric("beforeTotalPss", result.getBeforeTotalPssKb() * 1024L); 82 recordBytesMetric( 83 "deltaTotalPss", 84 (result.getAfterTotalPssKb() - result.getBeforeTotalPssKb()) * 1024L); 85 } 86 87 @Test measureCollatorRootLocale()88 public void measureCollatorRootLocale() throws Exception { 89 MetricsRunner.Result result = metricsRunner.runAllInstrumentations("COLLATOR_ROOT_LOCALE"); 90 recordBeforeAndAfterAppHeapMetrics(result.getBeforeDump(), result.getAfterDump()); 91 } 92 93 @Test measureCollatorEnUsLocale()94 public void measureCollatorEnUsLocale() throws Exception { 95 MetricsRunner.Result result = metricsRunner.runAllInstrumentations("COLLATOR_EN_US_LOCALE"); 96 recordBeforeAndAfterAppHeapMetrics(result.getBeforeDump(), result.getAfterDump()); 97 } 98 99 @Test measureCollatorKoreanLocale()100 public void measureCollatorKoreanLocale() throws Exception { 101 MetricsRunner.Result result = 102 metricsRunner.runAllInstrumentations("COLLATOR_KOREAN_LOCALE"); 103 recordBeforeAndAfterAppHeapMetrics(result.getBeforeDump(), result.getAfterDump()); 104 } 105 106 @Test measureRegexes()107 public void measureRegexes() throws Exception { 108 MetricsRunner.Result result = metricsRunner.runAllInstrumentations("REGEX"); 109 recordBeforeAndAfterAppHeapMetrics(result.getBeforeDump(), result.getAfterDump()); 110 } 111 recordHeapMetrics(AhatSnapshot dump, String metricPrefix, String heapName)112 private void recordHeapMetrics(AhatSnapshot dump, String metricPrefix, String heapName) { 113 AhatHeap heap = dump.getHeap(heapName); 114 recordSizeMetric(metricPrefix, heap.getSize()); 115 Map<Reachability, Size> sizesByReachability = sizesByReachability(dump, heap); 116 for (Reachability reachability : Reachability.values()) { 117 recordSizeMetric( 118 reachability.metricName(metricPrefix), sizesByReachability.get(reachability)); 119 } 120 } 121 recordBeforeAndAfterAppHeapMetrics( AhatSnapshot beforeDump, AhatSnapshot afterDump)122 private void recordBeforeAndAfterAppHeapMetrics( 123 AhatSnapshot beforeDump, 124 AhatSnapshot afterDump) { 125 AhatHeap beforeHeap = beforeDump.getHeap("app"); 126 AhatHeap afterHeap = afterDump.getHeap("app"); 127 recordSizeMetric("beforeAppSize", beforeHeap.getSize()); 128 recordSizeDeltaMetric("deltaAppSize", beforeHeap.getSize(), afterHeap.getSize()); 129 Map<Reachability, Size> beforeSizesByReachability = 130 sizesByReachability(beforeDump, beforeHeap); 131 Map<Reachability, Size> afterSizesByReachability = sizesByReachability(afterDump, afterHeap); 132 for (Reachability reachability : Reachability.values()) { 133 recordSizeMetric( 134 reachability.metricName("beforeAppSize"), 135 beforeSizesByReachability.get(reachability)); 136 recordSizeDeltaMetric( 137 reachability.metricName("deltaAppSize"), 138 beforeSizesByReachability.get(reachability), 139 afterSizesByReachability.get(reachability)); 140 } 141 } 142 recordSizeMetric(String name, Size size)143 private void recordSizeMetric(String name, Size size) { 144 recordBytesMetric(name, size.getSize()); 145 } 146 recordSizeDeltaMetric(String name, Size before, Size after)147 private void recordSizeDeltaMetric(String name, Size before, Size after) { 148 recordBytesMetric(name, after.getSize() - before.getSize()); 149 } 150 recordBytesMetric(String name, long bytes)151 private void recordBytesMetric(String name, long bytes) { 152 metrics.addTestMetric(name, Long.toString(bytes)); 153 } 154 sizesByReachability(AhatSnapshot dump, AhatHeap heap)155 private static Map<Reachability, Size> sizesByReachability(AhatSnapshot dump, AhatHeap heap) { 156 EnumMap<Reachability, Size> map = new EnumMap<>(Reachability.class); 157 for (Reachability reachability : Reachability.values()) { 158 map.put(reachability, Size.ZERO); 159 } 160 for (AhatInstance instance : dump.getRooted()) { 161 Reachability reachability = Reachability.ofInstance(instance); 162 Size size = instance.getRetainedSize(heap); 163 map.put(reachability, map.get(reachability).plus(size)); 164 } 165 return map; 166 } 167 } 168