diff options
| author | 2019-09-13 11:50:27 +0100 | |
|---|---|---|
| committer | 2019-09-17 09:57:50 +0000 | |
| commit | 196532a01e6f69657d6e8804f1637b82b9698656 (patch) | |
| tree | 42a155bf8272b4248e9f4c2baad2ccb2ccce8afb | |
| parent | e33dcad81a4bc5f528f93e675c0319104b66f2e7 (diff) | |
Move RSS HWM stats reading code under stats
The RSS high-water mark stats are used only by telemetry and should not
be a part of am package.
Modifications:
- avoid null, use empty string instead
- use assertThat from Truth
Bug: 140986627
Test: atest MemoryStatUtilTest
Test: atest ProcfsMemoryUtilTest
Test: statsd_testdrive for RSS HWM atom
Change-Id: I60140c085f1a47d71505955d79f545f52a4c4423
5 files changed, 169 insertions, 38 deletions
diff --git a/services/core/java/com/android/server/am/MemoryStatUtil.java b/services/core/java/com/android/server/am/MemoryStatUtil.java index e73abd17cc07..fd64df9e86e0 100644 --- a/services/core/java/com/android/server/am/MemoryStatUtil.java +++ b/services/core/java/com/android/server/am/MemoryStatUtil.java @@ -63,8 +63,6 @@ public final class MemoryStatUtil { private static final Pattern CACHE_IN_BYTES = Pattern.compile("total_cache (\\d+)"); private static final Pattern SWAP_IN_BYTES = Pattern.compile("total_swap (\\d+)"); - private static final Pattern RSS_HIGH_WATERMARK_IN_KILOBYTES = - Pattern.compile("VmHWM:\\s*(\\d+)\\s*kB"); private static final Pattern PROCFS_RSS_IN_KILOBYTES = Pattern.compile("VmRSS:\\s*(\\d+)\\s*kB"); private static final Pattern PROCFS_ANON_RSS_IN_KILOBYTES = @@ -113,15 +111,6 @@ public final class MemoryStatUtil { } /** - * Reads RSS high-water mark of a process from procfs. Returns value of the VmHWM field in - * /proc/PID/status in kilobytes or 0 if not available. - */ - public static int readRssHighWaterMarkFromProcfs(int pid) { - final String statusPath = String.format(Locale.US, PROC_STATUS_FILE_FMT, pid); - return parseVmHWMFromProcfs(readFileContents(statusPath)); - } - - /** * Reads cmdline of a process from procfs. * * Returns content of /proc/pid/cmdline (e.g. /system/bin/statsd) or an empty string @@ -204,19 +193,6 @@ public final class MemoryStatUtil { } /** - * Parses RSS high-water mark out from the contents of the /proc/pid/status file in procfs. The - * returned value is in kilobytes. - */ - @VisibleForTesting - static int parseVmHWMFromProcfs(String procStatusContents) { - if (procStatusContents == null || procStatusContents.isEmpty()) { - return 0; - } - return (int) tryParseLong(RSS_HIGH_WATERMARK_IN_KILOBYTES, procStatusContents); - } - - - /** * Parses cmdline out of the contents of the /proc/pid/cmdline file in procfs. * * Parsing is required to strip anything after first null byte. diff --git a/services/core/java/com/android/server/stats/ProcfsMemoryUtil.java b/services/core/java/com/android/server/stats/ProcfsMemoryUtil.java new file mode 100644 index 000000000000..3076284a80ed --- /dev/null +++ b/services/core/java/com/android/server/stats/ProcfsMemoryUtil.java @@ -0,0 +1,75 @@ +/* + * 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.server.stats; + +import android.os.FileUtils; +import android.util.Slog; + +import com.android.internal.annotations.VisibleForTesting; + +import java.io.File; +import java.io.IOException; +import java.util.Locale; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +final class ProcfsMemoryUtil { + private static final String TAG = "ProcfsMemoryUtil"; + + /** Path to procfs status file: /proc/pid/status. */ + private static final String STATUS_FILE_FMT = "/proc/%d/status"; + + private static final Pattern RSS_HIGH_WATER_MARK_IN_KILOBYTES = + Pattern.compile("VmHWM:\\s*(\\d+)\\s*kB"); + + private ProcfsMemoryUtil() {} + + /** + * Reads RSS high-water mark of a process from procfs. Returns value of the VmHWM field in + * /proc/PID/status in kilobytes or 0 if not available. + */ + static int readRssHighWaterMarkFromProcfs(int pid) { + final String statusPath = String.format(Locale.US, STATUS_FILE_FMT, pid); + return parseVmHWMFromStatus(readFile(statusPath)); + } + + /** + * Parses RSS high-water mark out from the contents of the /proc/pid/status file in procfs. The + * returned value is in kilobytes. + */ + @VisibleForTesting + static int parseVmHWMFromStatus(String contents) { + if (contents.isEmpty()) { + return 0; + } + final Matcher matcher = RSS_HIGH_WATER_MARK_IN_KILOBYTES.matcher(contents); + try { + return matcher.find() ? Integer.parseInt(matcher.group(1)) : 0; + } catch (NumberFormatException e) { + Slog.e(TAG, "Failed to parse value", e); + return 0; + } + } + + private static String readFile(String path) { + try { + final File file = new File(path); + return FileUtils.readTextFile(file, 0 /* max */, null /* ellipsis */); + } catch (IOException e) { + return ""; + } + } +} diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java index e92abfddac8f..19b80556a779 100644 --- a/services/core/java/com/android/server/stats/StatsCompanionService.java +++ b/services/core/java/com/android/server/stats/StatsCompanionService.java @@ -27,9 +27,9 @@ import static com.android.internal.util.Preconditions.checkNotNull; import static com.android.server.am.MemoryStatUtil.readCmdlineFromProcfs; import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem; import static com.android.server.am.MemoryStatUtil.readMemoryStatFromProcfs; -import static com.android.server.am.MemoryStatUtil.readRssHighWaterMarkFromProcfs; import static com.android.server.stats.IonMemoryUtil.readProcessSystemIonHeapSizesFromDebugfs; import static com.android.server.stats.IonMemoryUtil.readSystemIonHeapSizeFromDebugfs; +import static com.android.server.stats.ProcfsMemoryUtil.readRssHighWaterMarkFromProcfs; import android.annotation.NonNull; import android.annotation.Nullable; diff --git a/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java b/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java index 6a0d7f192adb..9e3b54d1ca96 100644 --- a/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java +++ b/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java @@ -22,7 +22,6 @@ import static com.android.server.am.MemoryStatUtil.MemoryStat; import static com.android.server.am.MemoryStatUtil.parseCmdlineFromProcfs; import static com.android.server.am.MemoryStatUtil.parseMemoryStatFromMemcg; import static com.android.server.am.MemoryStatUtil.parseMemoryStatFromProcfs; -import static com.android.server.am.MemoryStatUtil.parseVmHWMFromProcfs; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; @@ -230,18 +229,6 @@ public class MemoryStatUtilTest { } @Test - public void testParseVmHWMFromProcfs_parsesCorrectValue() { - assertEquals(137668, parseVmHWMFromProcfs(PROC_STATUS_CONTENTS)); - } - - @Test - public void testParseVmHWMFromProcfs_emptyContents() { - assertEquals(0, parseVmHWMFromProcfs("")); - - assertEquals(0, parseVmHWMFromProcfs(null)); - } - - @Test public void testParseCmdlineFromProcfs_invalidValue() { byte[] nothing = new byte[] {0x00, 0x74, 0x65, 0x73, 0x74}; // \0test diff --git a/services/tests/servicestests/src/com/android/server/stats/ProcfsMemoryUtilTest.java b/services/tests/servicestests/src/com/android/server/stats/ProcfsMemoryUtilTest.java new file mode 100644 index 000000000000..4fb533f726b2 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/stats/ProcfsMemoryUtilTest.java @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2019 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.server.stats; + +import static com.android.server.stats.ProcfsMemoryUtil.parseVmHWMFromStatus; + +import static com.google.common.truth.Truth.assertThat; + +import androidx.test.filters.SmallTest; + +import org.junit.Test; + +/** + * Build/Install/Run: + * atest FrameworksServicesTests:ProcfsMemoryUtilTest + */ +@SmallTest +public class ProcfsMemoryUtilTest { + private static final String STATUS_CONTENTS = "Name:\tandroid.youtube\n" + + "State:\tS (sleeping)\n" + + "Tgid:\t12088\n" + + "Pid:\t12088\n" + + "PPid:\t723\n" + + "TracerPid:\t0\n" + + "Uid:\t10083\t10083\t10083\t10083\n" + + "Gid:\t10083\t10083\t10083\t10083\n" + + "Ngid:\t0\n" + + "FDSize:\t128\n" + + "Groups:\t3003 9997 20083 50083 \n" + + "VmPeak:\t 4546844 kB\n" + + "VmSize:\t 4542636 kB\n" + + "VmLck:\t 0 kB\n" + + "VmPin:\t 0 kB\n" + + "VmHWM:\t 137668 kB\n" // RSS high-water mark + + "VmRSS:\t 126776 kB\n" // RSS + + "RssAnon:\t 37860 kB\n" + + "RssFile:\t 88764 kB\n" + + "RssShmem:\t 152 kB\n" + + "VmData:\t 4125112 kB\n" + + "VmStk:\t 8192 kB\n" + + "VmExe:\t 24 kB\n" + + "VmLib:\t 102432 kB\n" + + "VmPTE:\t 1300 kB\n" + + "VmPMD:\t 36 kB\n" + + "VmSwap:\t 22 kB\n" // Swap + + "Threads:\t95\n" + + "SigQ:\t0/13641\n" + + "SigPnd:\t0000000000000000\n" + + "ShdPnd:\t0000000000000000\n" + + "SigBlk:\t0000000000001204\n" + + "SigIgn:\t0000000000000001\n" + + "SigCgt:\t00000006400084f8\n" + + "CapInh:\t0000000000000000\n" + + "CapPrm:\t0000000000000000\n" + + "CapEff:\t0000000000000000\n" + + "CapBnd:\t0000000000000000\n" + + "CapAmb:\t0000000000000000\n" + + "Seccomp:\t2\n" + + "Cpus_allowed:\tff\n" + + "Cpus_allowed_list:\t0-7\n" + + "Mems_allowed:\t1\n" + + "Mems_allowed_list:\t0\n" + + "voluntary_ctxt_switches:\t903\n" + + "nonvoluntary_ctxt_switches:\t104\n"; + + @Test + public void testParseVmHWMFromStatus_parsesCorrectValue() { + assertThat(parseVmHWMFromStatus(STATUS_CONTENTS)).isEqualTo(137668); + } + + @Test + public void testParseVmHWMFromStatus_invalidValue() { + assertThat(parseVmHWMFromStatus("test\nVmHWM: x0x0x\ntest")).isEqualTo(0); + } + + @Test + public void testParseVmHWMFromStatus_emptyContents() { + assertThat(parseVmHWMFromStatus("")).isEqualTo(0); + } +} |