summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorandroid-build-team Robot <android-build-team-robot@google.com>2018-01-30 08:24:40 +0000
committerandroid-build-team Robot <android-build-team-robot@google.com>2018-01-30 08:24:40 +0000
commit48d8d2addf0b005309233807eb907ff9429573f4 (patch)
tree6446b02c27675c591c358ac580ee73c441c784cc
parenta6ab6fe117aee83abb267a4aae3d98492209ea9b (diff)
parent6a5ccaef7a4bd6ff3b2d8f02ae2fc33d80af9698 (diff)
downloadloganalysis-48d8d2addf0b005309233807eb907ff9429573f4.tar.gz
Snap for 4574286 from 6a5ccaef7a4bd6ff3b2d8f02ae2fc33d80af9698 to pi-release
Change-Id: Ic4b72ec2be80e675f7b5fd41646f7328ba2609e5
-rw-r--r--src/com/android/loganalysis/item/DumpsysProcessMeminfoItem.java119
-rw-r--r--src/com/android/loganalysis/parser/DumpsysProcessMeminfoParser.java100
-rw-r--r--tests/src/com/android/loganalysis/UnitTests.java2
-rw-r--r--tests/src/com/android/loganalysis/parser/DumpsysProcessMeminfoParserTest.java104
4 files changed, 325 insertions, 0 deletions
diff --git a/src/com/android/loganalysis/item/DumpsysProcessMeminfoItem.java b/src/com/android/loganalysis/item/DumpsysProcessMeminfoItem.java
new file mode 100644
index 0000000..3abfd40
--- /dev/null
+++ b/src/com/android/loganalysis/item/DumpsysProcessMeminfoItem.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2018 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.loganalysis.item;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * An {@link IItem} used to store output from `dumpsys meminfo --checkin PROCESS` where PROCESS is
+ * from the output of `dumpsys meminfo`. Data is stored as a map of categories to a map of
+ * measurement types to values.
+ */
+public class DumpsysProcessMeminfoItem extends GenericMapItem<Map<String, Long>> {
+ // Should match value from ActivityThread
+ public static final int ACTIVITY_THREAD_CHECKIN_VERSION = 4;
+
+ // Default Categories
+ public static final String NATIVE = "NATIVE";
+ public static final String DALVIK = "DALVIK";
+ public static final String OTHER = "OTHER";
+ public static final String TOTAL = "TOTAL";
+
+ // Memory Measurement Types
+ public static final String PSS = "PSS";
+ public static final String SWAPPABLE_PSS = "SWAPPABLE_PSS";
+ public static final String SHARED_DIRTY = "SHARED_DIRTY";
+ public static final String SHARED_CLEAN = "SHARED_CLEAN";
+ public static final String PRIVATE_DIRTY = "PRIVATE_DIRTY";
+ public static final String PRIVATE_CLEAN = "PRIVATE_CLEAN";
+ public static final String SWAPPED_OUT = "SWAPPED_OUT";
+ public static final String SWAPPED_OUT_PSS = "SWAPPED_OUT_PSS";
+ // NATIVE, DALVIK, TOTAL only
+ public static final String MAX = "MAX";
+ public static final String ALLOCATED = "ALLOCATED";
+ public static final String FREE = "FREE";
+
+ public static final String[] MAIN_OUTPUT_ORDER = {
+ MAX,
+ ALLOCATED,
+ FREE,
+ PSS,
+ SWAPPABLE_PSS,
+ SHARED_DIRTY,
+ SHARED_CLEAN,
+ PRIVATE_DIRTY,
+ PRIVATE_CLEAN,
+ SWAPPED_OUT,
+ SWAPPED_OUT_PSS
+ };
+ public static final String[] OTHER_OUTPUT_ORDER = {
+ PSS,
+ SWAPPABLE_PSS,
+ SHARED_DIRTY,
+ SHARED_CLEAN,
+ PRIVATE_DIRTY,
+ PRIVATE_CLEAN,
+ SWAPPED_OUT,
+ SWAPPED_OUT_PSS
+ };
+
+ private int mPid;
+ private String mProcessName;
+
+ public DumpsysProcessMeminfoItem() {
+ this.put(NATIVE, new HashMap<>());
+ this.put(DALVIK, new HashMap<>());
+ this.put(OTHER, new HashMap<>());
+ this.put(TOTAL, new HashMap<>());
+ }
+
+ /** Get the pid */
+ public int getPid() {
+ return mPid;
+ }
+
+ /** Set the pid */
+ public void setPid(int pid) {
+ mPid = pid;
+ }
+
+ /** Get the process name */
+ public String getProcessName() {
+ return mProcessName;
+ }
+
+ /** Set the process name */
+ public void setProcessName(String processName) {
+ mProcessName = processName;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public JSONObject toJson() {
+ JSONObject result = super.toJson();
+ try {
+ result.put("pid", mPid);
+ result.put("process_name", mProcessName);
+ } catch (JSONException e) {
+ //ignore
+ }
+ return result;
+ }
+}
diff --git a/src/com/android/loganalysis/parser/DumpsysProcessMeminfoParser.java b/src/com/android/loganalysis/parser/DumpsysProcessMeminfoParser.java
new file mode 100644
index 0000000..119bab6
--- /dev/null
+++ b/src/com/android/loganalysis/parser/DumpsysProcessMeminfoParser.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2018 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.loganalysis.parser;
+
+import com.android.loganalysis.item.DumpsysProcessMeminfoItem;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * An {@link IParser} used to parse output from `dumpsys meminfo --checkin PROCESS` where PROCESS is
+ * from the output of `dumpsys meminfo`. Data is stored as a map of categories to a map of
+ * measurement types to values. Format is from {@link android.app.ActivityThread#dumpMemInfoTable}.
+ */
+public class DumpsysProcessMeminfoParser implements IParser {
+
+ // Order is VERSION,PID,NAME,[native,dalvik,other,total]{11},[name,val{8}]*
+ private static final Pattern MEMINFO_OUTPUT =
+ Pattern.compile("(\\d+),(\\d+),([^,]+),((?:(?:N/A|\\d+),){44})(.*)");
+ // Matches the ending [name,val{8}]
+ private static final Pattern MEMINFO_ADDITIONAL_OUTPUT =
+ Pattern.compile("([^,]+),((?:(?:N/A|\\d+),){8})");
+ // Matches a value with comma
+ private static final Pattern MEMINFO_VALUE = Pattern.compile("(N/A|\\d+),");
+
+ @Override
+ public DumpsysProcessMeminfoItem parse(List<String> lines) {
+ DumpsysProcessMeminfoItem item = new DumpsysProcessMeminfoItem();
+ for (String line : lines) {
+ Matcher m = MEMINFO_OUTPUT.matcher(line);
+ if (!m.matches()) continue;
+ try {
+ item.setPid(Integer.parseInt(m.group(2)));
+ } catch (NumberFormatException e) {
+ // skip
+ }
+ item.setProcessName(m.group(3));
+ // parse memory info main areas
+ String mainValues = m.group(4);
+ Matcher mainMatcher = MEMINFO_VALUE.matcher(mainValues);
+ Map<String, Long> nativeData = item.get(DumpsysProcessMeminfoItem.NATIVE);
+ Map<String, Long> dalvikData = item.get(DumpsysProcessMeminfoItem.DALVIK);
+ Map<String, Long> otherData = item.get(DumpsysProcessMeminfoItem.OTHER);
+ Map<String, Long> totalData = item.get(DumpsysProcessMeminfoItem.TOTAL);
+ for (int i = 0; i < DumpsysProcessMeminfoItem.MAIN_OUTPUT_ORDER.length; i++) {
+ String curMeasurement = DumpsysProcessMeminfoItem.MAIN_OUTPUT_ORDER[i];
+ parseNextValue(mainMatcher, nativeData, curMeasurement);
+ parseNextValue(mainMatcher, dalvikData, curMeasurement);
+ parseNextValue(mainMatcher, otherData, curMeasurement);
+ parseNextValue(mainMatcher, totalData, curMeasurement);
+ }
+ String additionalData = m.group(5);
+ Matcher additionalMatcher = MEMINFO_ADDITIONAL_OUTPUT.matcher(additionalData);
+ // parse memory info other areas
+ while (additionalMatcher.find()) {
+ try {
+ String curLabel = additionalMatcher.group(1);
+ Matcher additionalValueMatcher =
+ MEMINFO_VALUE.matcher(additionalMatcher.group(2));
+ Map<String, Long> curData = new HashMap<>();
+ for (int i = 0; i < DumpsysProcessMeminfoItem.OTHER_OUTPUT_ORDER.length; i++) {
+ String curMeasurement = DumpsysProcessMeminfoItem.OTHER_OUTPUT_ORDER[i];
+ parseNextValue(additionalValueMatcher, curData, curMeasurement);
+ }
+ item.put(curLabel, curData);
+ } catch (ArrayIndexOutOfBoundsException e) {
+ break;
+ }
+ }
+ }
+ return item;
+ }
+
+ private void parseNextValue(Matcher m, Map<String, Long> output, String key) {
+ if (!m.find()) return;
+ String value = m.group(1);
+ if ("N/A".equals(value)) return;
+ try {
+ output.put(key, Long.parseLong(value));
+ } catch (NumberFormatException e) {
+ // skip
+ }
+ }
+}
diff --git a/tests/src/com/android/loganalysis/UnitTests.java b/tests/src/com/android/loganalysis/UnitTests.java
index ac35a8a..68d5bf6 100644
--- a/tests/src/com/android/loganalysis/UnitTests.java
+++ b/tests/src/com/android/loganalysis/UnitTests.java
@@ -45,6 +45,7 @@ import com.android.loganalysis.parser.DumpsysBatteryStatsParserTest;
import com.android.loganalysis.parser.DumpsysPackageStatsParserTest;
import com.android.loganalysis.parser.DumpsysParserTest;
import com.android.loganalysis.parser.DumpsysProcStatsParserTest;
+import com.android.loganalysis.parser.DumpsysProcessMeminfoParserTest;
import com.android.loganalysis.parser.DumpsysWifiStatsParserTest;
import com.android.loganalysis.parser.DvmLockSampleParserTest;
import com.android.loganalysis.parser.EventsLogParserTest;
@@ -130,6 +131,7 @@ import org.junit.runners.Suite.SuiteClasses;
DumpsysBatteryStatsParserTest.class,
DumpsysPackageStatsParserTest.class,
DumpsysParserTest.class,
+ DumpsysProcessMeminfoParserTest.class,
DumpsysProcStatsParserTest.class,
DumpsysWifiStatsParserTest.class,
DvmLockSampleParserTest.class,
diff --git a/tests/src/com/android/loganalysis/parser/DumpsysProcessMeminfoParserTest.java b/tests/src/com/android/loganalysis/parser/DumpsysProcessMeminfoParserTest.java
new file mode 100644
index 0000000..b7042d3
--- /dev/null
+++ b/tests/src/com/android/loganalysis/parser/DumpsysProcessMeminfoParserTest.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2018 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.loganalysis.parser;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import com.android.loganalysis.item.DumpsysProcessMeminfoItem;
+
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.List;
+
+/** Unit tests for {@link DumpsysProcessMeminfoParser} */
+public class DumpsysProcessMeminfoParserTest {
+ private static final String TEST_INPUT =
+ "time,28506638,177086152\n"
+ + "4,938,system_server,11,22,N/A,44,0,0,N/A,0,0,0,N/A,0,27613,14013,176602,"
+ + "218228,0,0,122860,122860,1512,1412,5740,8664,0,0,154924,154924,27568,"
+ + "13972,11916,53456,0,0,123008,123008,0,0,0,0,0,0,0,0,Dalvik Other,3662,0,"
+ + "104,0,3660,0,0,0,Stack,1576,0,8,0,1576,0,0,0,Cursor,0,0,0,0,0,0,0,0,"
+ + "Ashmem,156,0,20,0,148,0,0,0,Gfx dev,100,0,48,0,76,0,0,0,Other dev,116,0,"
+ + "164,0,0,96,0,0,.so mmap,7500,2680,3984,21864,904,2680,0,0,.jar mmap,0,0,0,"
+ + "0,0,0,0,0,.apk mmap,72398,71448,0,11736,0,71448,0,0,.ttf mmap,0,0,0,0,0,0,"
+ + "0,0,.dex mmap,76874,46000,0,83644,40,46000,0,0,.oat mmap,8127,2684,64,"
+ + "26652,0,2684,0,0,.art mmap,1991,48,972,10004,1544,48,0,0,Other mmap,137,0,"
+ + "44,1024,4,52,0,0,EGL mtrack,0,0,0,0,0,0,0,0,GL mtrack,111,222,333,444,555,"
+ + "666,777,888,";
+
+ private static final String INVALID_TEST_INPUT = "RANDOM,TEST,DATA\n234235345345";
+
+ // Test that normal input is parsed
+ @Test
+ public void testDumpsysProcessMeminfoParser() {
+ List<String> inputBlock = Arrays.asList(TEST_INPUT.split("\n"));
+ DumpsysProcessMeminfoItem dump = new DumpsysProcessMeminfoParser().parse(inputBlock);
+ assertEquals(938, dump.getPid());
+ assertEquals("system_server", dump.getProcessName());
+ assertEquals(
+ Long.valueOf(11L),
+ dump.get(DumpsysProcessMeminfoItem.NATIVE).get(DumpsysProcessMeminfoItem.MAX));
+ assertEquals(
+ Long.valueOf(22L),
+ dump.get(DumpsysProcessMeminfoItem.DALVIK).get(DumpsysProcessMeminfoItem.MAX));
+ assertFalse(
+ dump.get(DumpsysProcessMeminfoItem.OTHER)
+ .containsKey(DumpsysProcessMeminfoItem.MAX));
+ assertEquals(
+ Long.valueOf(44L),
+ dump.get(DumpsysProcessMeminfoItem.TOTAL).get(DumpsysProcessMeminfoItem.MAX));
+ assertEquals(
+ Long.valueOf(218228L),
+ dump.get(DumpsysProcessMeminfoItem.TOTAL).get(DumpsysProcessMeminfoItem.PSS));
+ assertEquals(
+ Long.valueOf(3662L), dump.get("Dalvik Other").get(DumpsysProcessMeminfoItem.PSS));
+ assertEquals(Long.valueOf(111L), dump.get("GL mtrack").get(DumpsysProcessMeminfoItem.PSS));
+ assertEquals(
+ Long.valueOf(222L),
+ dump.get("GL mtrack").get(DumpsysProcessMeminfoItem.SWAPPABLE_PSS));
+ assertEquals(
+ Long.valueOf(333L),
+ dump.get("GL mtrack").get(DumpsysProcessMeminfoItem.SHARED_DIRTY));
+ assertEquals(
+ Long.valueOf(444L),
+ dump.get("GL mtrack").get(DumpsysProcessMeminfoItem.SHARED_CLEAN));
+ assertEquals(
+ Long.valueOf(555L),
+ dump.get("GL mtrack").get(DumpsysProcessMeminfoItem.PRIVATE_DIRTY));
+ assertEquals(
+ Long.valueOf(666L),
+ dump.get("GL mtrack").get(DumpsysProcessMeminfoItem.PRIVATE_CLEAN));
+ assertEquals(
+ Long.valueOf(777L),
+ dump.get("GL mtrack").get(DumpsysProcessMeminfoItem.SWAPPED_OUT));
+ assertEquals(
+ Long.valueOf(888L),
+ dump.get("GL mtrack").get(DumpsysProcessMeminfoItem.SWAPPED_OUT_PSS));
+ }
+
+ // Test that the parser does not crash on invalid input and returns empty data
+ @Test
+ public void testDumpsysProcessMeminfoParserInvalid() {
+ List<String> inputBlock = Arrays.asList(INVALID_TEST_INPUT.split("\n"));
+ DumpsysProcessMeminfoItem dump = new DumpsysProcessMeminfoParser().parse(inputBlock);
+ assertNull(dump.getProcessName());
+ assertTrue(dump.get(DumpsysProcessMeminfoItem.TOTAL).isEmpty());
+ }
+}