diff options
author | android-build-team Robot <android-build-team-robot@google.com> | 2017-06-23 07:09:36 +0000 |
---|---|---|
committer | android-build-team Robot <android-build-team-robot@google.com> | 2017-06-23 07:09:36 +0000 |
commit | deb028cdc52bae937841cf95866d1812c7f35328 (patch) | |
tree | c69ce3c488d83c8f9df742f2403d4b06b1a32903 | |
parent | 6d89ea629c4820229cc3c50762bdb5603c365088 (diff) | |
parent | 9cd6c25090e5d949325292a88b77f30049987271 (diff) | |
download | tradefederation-oreo-r3-release.tar.gz |
release-request-160c4b31-7fa0-4e2b-aabe-85380836a1ce-for-git_oc-release-4129081 snap-temp-L15300000077039010android-security-8.0.0_r54android-security-8.0.0_r53android-security-8.0.0_r52android-cts-8.0_r1android-8.0.0_r9android-8.0.0_r7android-8.0.0_r51android-8.0.0_r50android-8.0.0_r49android-8.0.0_r48android-8.0.0_r47android-8.0.0_r46android-8.0.0_r45android-8.0.0_r44android-8.0.0_r43android-8.0.0_r42android-8.0.0_r41android-8.0.0_r40android-8.0.0_r4android-8.0.0_r39android-8.0.0_r38android-8.0.0_r37android-8.0.0_r36android-8.0.0_r35android-8.0.0_r32android-8.0.0_r31android-8.0.0_r30android-8.0.0_r3android-8.0.0_r28android-8.0.0_r2android-8.0.0_r17android-8.0.0_r16android-8.0.0_r15android-8.0.0_r13android-8.0.0_r12android-8.0.0_r11android-8.0.0_r10android-8.0.0_r1security-oc-releaseoreo-security-releaseoreo-releaseoreo-r6-releaseoreo-r5-releaseoreo-r4-releaseoreo-r3-release
Change-Id: Iab70b7a9fa12e08062e41550abb59fbaa2702e80
4 files changed, 248 insertions, 7 deletions
diff --git a/src/com/android/tradefed/testtype/TfTestLauncher.java b/src/com/android/tradefed/testtype/TfTestLauncher.java index c5cc4eca7..87aae1f17 100644 --- a/src/com/android/tradefed/testtype/TfTestLauncher.java +++ b/src/com/android/tradefed/testtype/TfTestLauncher.java @@ -26,6 +26,7 @@ import com.android.tradefed.result.LogDataType; import com.android.tradefed.util.CommandResult; import com.android.tradefed.util.CommandStatus; import com.android.tradefed.util.FileUtil; +import com.android.tradefed.util.HprofAllocSiteParser; import com.android.tradefed.util.RunUtil; import com.android.tradefed.util.StreamUtil; @@ -209,13 +210,7 @@ public class TfTestLauncher extends SubprocessTfLauncher { } } if (mEnableHprof) { - InputStreamSource memory = null; - try { - memory = new FileInputStreamSource(mHprofFile); - listener.testLog("hprof", LogDataType.TEXT, memory); - } finally { - StreamUtil.cancel(memory); - } + logHprofResults(mHprofFile, listener); } if (mTmpDir != null) { @@ -359,4 +354,43 @@ public class TfTestLauncher extends SubprocessTfLauncher { listener.testEnded(tid, Collections.emptyMap()); listener.testRunEnded(0, Collections.emptyMap()); } + + /** + * Helper to log and report as metric the hprof data. + * + * @param hprofFile file containing the Hprof report + * @param listener the {@link ITestInvocationListener} where to report the test. + */ + private void logHprofResults(File hprofFile, ITestInvocationListener listener) { + if (hprofFile == null) { + CLog.w("Hprof file was null. Skipping parsing."); + return; + } + if (!hprofFile.exists()) { + CLog.w("Hprof file %s was not found. Skipping parsing.", hprofFile.getAbsolutePath()); + return; + } + InputStreamSource memory = null; + try { + memory = new FileInputStreamSource(hprofFile); + listener.testLog("hprof", LogDataType.TEXT, memory); + } finally { + StreamUtil.cancel(memory); + } + HprofAllocSiteParser parser = new HprofAllocSiteParser(); + try { + Map<String, String> results = parser.parse(hprofFile); + if (results.isEmpty()) { + CLog.d("No allocation site found from hprof file"); + return; + } + listener.testRunStarted("hprofAllocSites", 1); + TestIdentifier tid = new TestIdentifier("hprof", "allocationSites"); + listener.testStarted(tid); + listener.testEnded(tid, results); + listener.testRunEnded(0, Collections.emptyMap()); + } catch (IOException e) { + throw new RuntimeException(e); + } + } } diff --git a/src/com/android/tradefed/util/HprofAllocSiteParser.java b/src/com/android/tradefed/util/HprofAllocSiteParser.java new file mode 100644 index 000000000..53519b726 --- /dev/null +++ b/src/com/android/tradefed/util/HprofAllocSiteParser.java @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.tradefed.util; + +import com.android.tradefed.log.LogUtil.CLog; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** Helper class to parse info from an Allocation Sites section of hprof reports. */ +public class HprofAllocSiteParser { + + private static final String ALLOC_SITES_START_PATTERN = "SITES BEGIN"; + private static final String ALLOC_SITES_END_PATTERN = "SITES END"; + private boolean mHasAllocSiteStarted = false; + // format: + // percent live alloc'ed stack class + // rank self accum bytes objs bytes objs trace name + // 1 12.24% 12.24% 12441616 1 12441616 1 586322 byte[] + private static final Pattern RANK_PATTERN = + Pattern.compile( + "(\\s+)([0-9]*)(\\s+)([0-9]*\\.?[0-9]+%)(\\s+)([0-9]*\\.?[0-9]+%)(\\s+)" + + "([0-9]+)(\\s+)([0-9]+)(\\s+)([0-9]+)(\\s+)([0-9]+)(\\s+)([0-9]+)" + + "(\\s+)(.*)"); + + /** + * Parse a text hprof report. + * + * @param hprofReport file containing the hprof report. + * @return a Map containing the results + */ + public Map<String, String> parse(File hprofReport) throws IOException { + Map<String, String> results = new HashMap<>(); + if (hprofReport == null || !hprofReport.exists()) { + return results; + } + internalParse(hprofReport, results); + return results; + } + + /** + * Actual parsing line by line of the report to extract information. + * + * @param report the {@link File} containing the hprof report. + * @param currentRes the {@link Map} where the allocation sites will be stored. + */ + private void internalParse(File report, Map<String, String> currentRes) throws IOException { + try (BufferedReader br = new BufferedReader(new FileReader(report))) { + for (String line; (line = br.readLine()) != null; ) { + handleAllocSites(line, currentRes); + } + } + } + + /** Handles the allocation sites in the hprof report. */ + private void handleAllocSites(String line, Map<String, String> currentRes) { + if (line.startsWith(ALLOC_SITES_START_PATTERN)) { + mHasAllocSiteStarted = true; + } else if (line.startsWith(ALLOC_SITES_END_PATTERN)) { + mHasAllocSiteStarted = false; + } else if (mHasAllocSiteStarted) { + Matcher m = RANK_PATTERN.matcher(line); + if (m.find()) { + CLog.d( + "Rank %s-%s-%s-%s-%s-%s-%s-%s-%s", + m.group(2), + m.group(4), + m.group(6), + m.group(8), + m.group(10), + m.group(12), + m.group(14), + m.group(16), + m.group(18)); + currentRes.put(String.format("Rank%s", m.group(2)), m.group(12)); + } + } + } +} diff --git a/tests/src/com/android/tradefed/UnitTests.java b/tests/src/com/android/tradefed/UnitTests.java index a30198576..62ff47996 100644 --- a/tests/src/com/android/tradefed/UnitTests.java +++ b/tests/src/com/android/tradefed/UnitTests.java @@ -174,6 +174,7 @@ import com.android.tradefed.util.EmmaXmlReporterParserTest; import com.android.tradefed.util.FakeTestsZipFolderTest; import com.android.tradefed.util.FileUtilTest; import com.android.tradefed.util.FixedByteArrayOutputStreamTest; +import com.android.tradefed.util.HprofAllocSiteParserTest; import com.android.tradefed.util.JUnitXmlParserTest; import com.android.tradefed.util.KeyguardControllerStateTest; import com.android.tradefed.util.ListInstrumentationParserTest; @@ -418,6 +419,7 @@ import org.junit.runners.Suite.SuiteClasses; FakeTestsZipFolderTest.class, FileUtilTest.class, FixedByteArrayOutputStreamTest.class, + HprofAllocSiteParserTest.class, HttpHelperTest.class, HttpMultipartPostTest.class, JUnitXmlParserTest.class, diff --git a/tests/src/com/android/tradefed/util/HprofAllocSiteParserTest.java b/tests/src/com/android/tradefed/util/HprofAllocSiteParserTest.java new file mode 100644 index 000000000..829d76a03 --- /dev/null +++ b/tests/src/com/android/tradefed/util/HprofAllocSiteParserTest.java @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.tradefed.util; + +import static org.junit.Assert.*; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import java.io.File; +import java.util.Map; + +/** Unit tests for {@link HprofAllocSiteParser}. */ +@RunWith(JUnit4.class) +public class HprofAllocSiteParserTest { + + private static final String TEST_STRING = + "java.util.WeakHashMap$KeySet.iterator\n" + + " java.util.AbstractCollection.toArray(AbstractCollection.java:180)\n" + + " com.sun.imageio.stream.StreamCloser$1.run(StreamCloser.java:70)\n" + + " java.lang.Thread.run(Thread.java:745)\n" + + "SITES BEGIN (ordered by live bytes) Mon Jun 5 04:35:20 2017\n" + + " percent live alloc'ed stack class\n" + + " rank self accum bytes objs bytes objs trace name\n" + + " 1 12.24% 12.24% 12441616 1 12441616 1 586322 byte[]\n" + + " 2 6.87% 19.12% 6983280 145485 10509264 218943 977169 HeapChaBuffer\n" + + " 3 6.12% 25.24% 6220816 1 6220816 1 586500 byte[]\n" + + " 4 4.60% 29.84% 4676976 97437 6912816 144017 977186 HeapChaBuffer\n" + + " 5 3.44% 33.28% 3491640 145485 5254632 218943 977168 char[]\n" + + " 6 2.68% 35.96% 2727808 17547 2831208 18167 303028 char[]\n" + + " 7 2.30% 38.26% 2338488 97437 3456408 144017 977185 char[]\n" + + " 8 2.26% 40.52% 2294880 6 2294880 6 1069475 char[]\n" + + " 9 2.06% 42.59% 2097168 1 2097168 1 1063791 byte[]\n" + + " 10 1.82% 44.41% 1853888 33022 1881488 33455 303005 char[]\n" + + " 11 1.21% 45.62% 1227208 15226 2047424 33452 303003 char[]\n" + + " 12 1.11% 46.72% 1123248 1 1123248 1 1063811 byte[]\n" + + " 13 1.04% 47.76% 1056704 33022 1070560 33455 303051 OptionDef\n" + + " 14 1.03% 48.79% 1048592 1 1048592 1 970204 byte[]\n" + + " 15 1.03% 49.83% 1048592 1 2080976 13 975125 byte[]\n" + + "SITES END"; + + private HprofAllocSiteParser mParser; + + @Before + public void setUp() { + mParser = new HprofAllocSiteParser(); + } + + /** Test that {@link HprofAllocSiteParser#parse(File)} returns correctly a map of results. */ + @Test + public void testParse() throws Exception { + File f = FileUtil.createTempFile("hprof", ".test"); + try { + FileUtil.writeToFile(TEST_STRING, f); + Map<String, String> results = mParser.parse(f); + assertFalse(results.isEmpty()); + assertEquals(15, results.size()); + assertEquals("2294880", results.get("Rank8")); + } finally { + FileUtil.deleteFile(f); + } + } + + /** Test that when the parsing does not find any valid pattern, we return no results. */ + @Test + public void testParse_invalidContent() throws Exception { + File f = FileUtil.createTempFile("hprof", ".test"); + try { + FileUtil.writeToFile("SITES BEGIN\nugh, we are in big trouble", f); + Map<String, String> results = mParser.parse(f); + assertTrue(results.isEmpty()); + } finally { + FileUtil.deleteFile(f); + } + } + + /** Assert that if the file passed for parsing is null we return empty results. */ + @Test + public void testParse_noFile() throws Exception { + Map<String, String> results = mParser.parse(null); + assertNotNull(results); + assertTrue(results.isEmpty()); + } + + /** Assert that if the file passed for parsing does not exists we return empty results. */ + @Test + public void testParse_fileDoesNotExists() throws Exception { + Map<String, String> results = mParser.parse(new File("thisdoesnotexistsatall")); + assertNotNull(results); + assertTrue(results.isEmpty()); + } +} |