blob: 3dce2dccfef52c08eaedccdd27c5810d73c2a494 [file] [log] [blame]
Richard Uhler35244722015-09-10 16:45:54 -07001/*
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
17package com.android.ahat;
18
Richard Uhlercda4f2e2016-09-09 09:56:20 +010019import com.android.ahat.heapdump.AhatClassObj;
20import com.android.ahat.heapdump.AhatInstance;
21import com.android.ahat.heapdump.AhatSnapshot;
Richard Uhlerf629cfd2016-12-12 13:11:26 +000022import com.android.ahat.heapdump.Diff;
Richard Uhlercda4f2e2016-09-09 09:56:20 +010023import com.android.ahat.heapdump.FieldValue;
24import com.android.ahat.heapdump.Value;
Richard Uhlerec78c782016-05-13 14:19:37 -070025import com.android.tools.perflib.heap.ProguardMap;
Richard Uhler35244722015-09-10 16:45:54 -070026import java.io.File;
27import java.io.IOException;
Richard Uhlerec78c782016-05-13 14:19:37 -070028import java.text.ParseException;
Richard Uhler35244722015-09-10 16:45:54 -070029
30/**
31 * The TestDump class is used to get an AhatSnapshot for the test-dump
32 * program.
33 */
34public class TestDump {
35 // It can take on the order of a second to parse and process the test-dump
36 // hprof. To avoid repeating this overhead for each test case, we cache the
37 // loaded instance of TestDump and reuse it when possible. In theory the
38 // test cases should not be able to modify the cached snapshot in a way that
39 // is visible to other test cases.
40 private static TestDump mCachedTestDump = null;
41
Richard Uhlerf629cfd2016-12-12 13:11:26 +000042 // If the test dump fails to load the first time, it will likely fail every
43 // other test we try. Rather than having to wait a potentially very long
44 // time for test dump loading to fail over and over again, record when it
45 // fails and don't try to load it again.
46 private static boolean mTestDumpFailed = false;
47
Richard Uhler35244722015-09-10 16:45:54 -070048 private AhatSnapshot mSnapshot = null;
Richard Uhlerf629cfd2016-12-12 13:11:26 +000049 private AhatSnapshot mBaseline = null;
Richard Uhler35244722015-09-10 16:45:54 -070050
51 /**
Richard Uhlerf629cfd2016-12-12 13:11:26 +000052 * Load the test-dump.hprof and test-dump-base.hprof files.
53 * The location of the files are read from the system properties
54 * "ahat.test.dump.hprof" and "ahat.test.dump.base.hprof", which is expected
55 * to be set on the command line.
56 * The location of the proguard map for both hprof files is read from the
57 * system property "ahat.test.dump.map". For example:
58 * java -Dahat.test.dump.hprof=test-dump.hprof \
59 * -Dahat.test.dump.base.hprof=test-dump-base.hprof \
60 * -Dahat.test.dump.map=proguard.map \
61 * -jar ahat-tests.jar
Richard Uhler35244722015-09-10 16:45:54 -070062 *
Richard Uhlerf629cfd2016-12-12 13:11:26 +000063 * An IOException is thrown if there is a failure reading the hprof files or
Richard Uhlerec78c782016-05-13 14:19:37 -070064 * the proguard map.
Richard Uhler35244722015-09-10 16:45:54 -070065 */
66 private TestDump() throws IOException {
Richard Uhlerf629cfd2016-12-12 13:11:26 +000067 // TODO: Make use of the baseline hprof for tests.
68 String hprof = System.getProperty("ahat.test.dump.hprof");
69 String hprofBase = System.getProperty("ahat.test.dump.base.hprof");
Richard Uhlerec78c782016-05-13 14:19:37 -070070
Richard Uhlerf629cfd2016-12-12 13:11:26 +000071 String mapfile = System.getProperty("ahat.test.dump.map");
72 ProguardMap map = new ProguardMap();
73 try {
74 map.readFromFile(new File(mapfile));
75 } catch (ParseException e) {
76 throw new IOException("Unable to load proguard map", e);
77 }
Richard Uhlerec78c782016-05-13 14:19:37 -070078
Richard Uhlerf629cfd2016-12-12 13:11:26 +000079 mSnapshot = AhatSnapshot.fromHprof(new File(hprof), map);
80 mBaseline = AhatSnapshot.fromHprof(new File(hprofBase), map);
81 Diff.snapshots(mSnapshot, mBaseline);
Richard Uhler35244722015-09-10 16:45:54 -070082 }
83
84 /**
85 * Get the AhatSnapshot for the test dump program.
86 */
87 public AhatSnapshot getAhatSnapshot() {
88 return mSnapshot;
89 }
90
91 /**
Richard Uhlerf629cfd2016-12-12 13:11:26 +000092 * Get the baseline AhatSnapshot for the test dump program.
93 */
94 public AhatSnapshot getBaselineAhatSnapshot() {
95 return mBaseline;
96 }
97
98 /**
Richard Uhlercda4f2e2016-09-09 09:56:20 +010099 * Returns the value of a field in the DumpedStuff instance in the
Richard Uhler35244722015-09-10 16:45:54 -0700100 * snapshot for the test-dump program.
101 */
Richard Uhlercda4f2e2016-09-09 09:56:20 +0100102 public Value getDumpedValue(String name) {
Richard Uhlerf629cfd2016-12-12 13:11:26 +0000103 return getDumpedValue(name, mSnapshot);
104 }
105
106 /**
107 * Returns the value of a field in the DumpedStuff instance in the
108 * baseline snapshot for the test-dump program.
109 */
110 public Value getBaselineDumpedValue(String name) {
111 return getDumpedValue(name, mBaseline);
112 }
113
114 /**
115 * Returns the value of a field in the DumpedStuff instance in the
116 * given snapshot for the test-dump program.
117 */
118 private Value getDumpedValue(String name, AhatSnapshot snapshot) {
119 AhatClassObj main = snapshot.findClass("Main");
Richard Uhlercda4f2e2016-09-09 09:56:20 +0100120 AhatInstance stuff = null;
Richard Uhlerd6918e32017-06-14 16:42:44 +0100121 for (FieldValue field : main.getStaticFieldValues()) {
122 if ("stuff".equals(field.name)) {
123 stuff = field.value.asAhatInstance();
Richard Uhler35244722015-09-10 16:45:54 -0700124 }
125 }
Richard Uhlercda4f2e2016-09-09 09:56:20 +0100126 return stuff.getField(name);
127 }
128
129 /**
130 * Returns the value of a non-primitive field in the DumpedStuff instance in
131 * the snapshot for the test-dump program.
132 */
133 public AhatInstance getDumpedAhatInstance(String name) {
134 Value value = getDumpedValue(name);
135 return value == null ? null : value.asAhatInstance();
Richard Uhler35244722015-09-10 16:45:54 -0700136 }
137
138 /**
Richard Uhlerf629cfd2016-12-12 13:11:26 +0000139 * Returns the value of a non-primitive field in the DumpedStuff instance in
140 * the baseline snapshot for the test-dump program.
141 */
142 public AhatInstance getBaselineDumpedAhatInstance(String name) {
143 Value value = getBaselineDumpedValue(name);
144 return value == null ? null : value.asAhatInstance();
145 }
146
147 /**
Richard Uhler35244722015-09-10 16:45:54 -0700148 * Get the test dump.
149 * An IOException is thrown if there is an error reading the test dump hprof
150 * file.
151 * To improve performance, this returns a cached instance of the TestDump
152 * when possible.
153 */
154 public static synchronized TestDump getTestDump() throws IOException {
Richard Uhlerf629cfd2016-12-12 13:11:26 +0000155 if (mTestDumpFailed) {
156 throw new RuntimeException("Test dump failed before, assuming it will again");
157 }
158
Richard Uhler35244722015-09-10 16:45:54 -0700159 if (mCachedTestDump == null) {
Richard Uhlerf629cfd2016-12-12 13:11:26 +0000160 mTestDumpFailed = true;
Richard Uhler35244722015-09-10 16:45:54 -0700161 mCachedTestDump = new TestDump();
Richard Uhlerf629cfd2016-12-12 13:11:26 +0000162 mTestDumpFailed = false;
Richard Uhler35244722015-09-10 16:45:54 -0700163 }
164 return mCachedTestDump;
165 }
166}