Merge "Add ProcessMemorySnapshot atom"

This commit is contained in:
Rafal Slawik
2019-09-23 18:43:22 +00:00
committed by Android (Google) Code Review
5 changed files with 171 additions and 11 deletions

View File

@@ -340,7 +340,7 @@ message Atom {
}
// Pulled events will start at field 10000.
// Next: 10064
// Next: 10065
oneof pulled {
WifiBytesTransfer wifi_bytes_transfer = 10000;
WifiBytesTransferByFgBg wifi_bytes_transfer_by_fg_bg = 10001;
@@ -406,6 +406,7 @@ message Atom {
ProcessSystemIonHeapSize process_system_ion_heap_size = 10061;
SurfaceflingerStatsGlobalInfo surfaceflinger_stats_global_info = 10062;
SurfaceflingerStatsLayerInfo surfaceflinger_stats_layer_info = 10063;
ProcessMemorySnapshot process_memory_snapshot = 10064;
}
// DO NOT USE field numbers above 100,000 in AOSP.
@@ -4107,6 +4108,46 @@ message ProcessMemoryHighWaterMark {
optional int32 rss_high_water_mark_in_kilobytes = 4;
}
/*
* Logs the memory stats for a process.
*
* Pulled from StatsCompanionService for all managed processes (from ActivityManagerService)
* and for selected native processes.
*/
message ProcessMemorySnapshot {
// The uid if available. -1 means not available.
optional int32 uid = 1 [(is_uid) = true];
// The process name.
// Usually package name or process cmdline.
// Provided by ActivityManagerService or read from /proc/PID/cmdline.
optional string process_name = 2;
// The pid of the process.
// Allows to disambiguate instances of the process.
optional int32 pid = 3;
// The current OOM score adjustment value.
// Read from ProcessRecord for managed processes.
// Placeholder -1001 (OOM_SCORE_ADJ_MIN - 1, outside of allowed range) for native ones.
optional int32 oom_score_adj = 4;
// The current RSS of the process.
// VmRSS from /proc/pid/status.
optional int32 rss_in_kilobytes = 5;
// The current anon RSS of the process.
// RssAnon from /proc/pid/status.
optional int32 anon_rss_in_kilobytes = 6;
// The current swap size of the process.
// VmSwap from /proc/pid/status.
optional int32 swap_in_kilobytes = 7;
// The sum of rss_in_kilobytes and swap_in_kilobytes.
optional int32 anon_rss_and_swap_in_kilobytes = 8;
}
/*
* Elapsed real time from SystemClock.
*/

View File

@@ -153,6 +153,9 @@ std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = {
{.additiveFields = {3},
.puller =
new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_HIGH_WATER_MARK)}},
// process_memory_snapshot
{android::util::PROCESS_MEMORY_SNAPSHOT,
{.puller = new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_SNAPSHOT)}},
// system_ion_heap_size
{android::util::SYSTEM_ION_HEAP_SIZE,
{.puller = new StatsCompanionServicePuller(android::util::SYSTEM_ION_HEAP_SIZE)}},

View File

@@ -34,6 +34,12 @@ final class ProcfsMemoryUtil {
private static final Pattern RSS_HIGH_WATER_MARK_IN_KILOBYTES =
Pattern.compile("VmHWM:\\s*(\\d+)\\s*kB");
private static final Pattern RSS_IN_KILOBYTES =
Pattern.compile("VmRSS:\\s*(\\d+)\\s*kB");
private static final Pattern ANON_RSS_IN_KILOBYTES =
Pattern.compile("RssAnon:\\s*(\\d+)\\s*kB");
private static final Pattern SWAP_IN_KILOBYTES =
Pattern.compile("VmSwap:\\s*(\\d+)\\s*kB");
private ProcfsMemoryUtil() {}
@@ -52,16 +58,25 @@ final class ProcfsMemoryUtil {
*/
@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;
}
return tryParseInt(contents, RSS_HIGH_WATER_MARK_IN_KILOBYTES);
}
/**
* Reads memory stat of a process from procfs. Returns values of the VmRss, AnonRSS, VmSwap
* fields in /proc/pid/status in kilobytes or 0 if not available.
*/
static MemorySnapshot readMemorySnapshotFromProcfs(int pid) {
final String statusPath = String.format(Locale.US, STATUS_FILE_FMT, pid);
return parseMemorySnapshotFromStatus(readFile(statusPath));
}
@VisibleForTesting
static MemorySnapshot parseMemorySnapshotFromStatus(String contents) {
final MemorySnapshot snapshot = new MemorySnapshot();
snapshot.rssInKilobytes = tryParseInt(contents, RSS_IN_KILOBYTES);
snapshot.anonRssInKilobytes = tryParseInt(contents, ANON_RSS_IN_KILOBYTES);
snapshot.swapInKilobytes = tryParseInt(contents, SWAP_IN_KILOBYTES);
return snapshot;
}
private static String readFile(String path) {
@@ -72,4 +87,27 @@ final class ProcfsMemoryUtil {
return "";
}
}
private static int tryParseInt(String contents, Pattern pattern) {
if (contents.isEmpty()) {
return 0;
}
final Matcher matcher = pattern.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;
}
}
static final class MemorySnapshot {
public int rssInKilobytes;
public int anonRssInKilobytes;
public int swapInKilobytes;
boolean isEmpty() {
return (anonRssInKilobytes + swapInKilobytes) == 0;
}
}
}

View File

@@ -29,6 +29,7 @@ import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem;
import static com.android.server.am.MemoryStatUtil.readMemoryStatFromProcfs;
import static com.android.server.stats.IonMemoryUtil.readProcessSystemIonHeapSizesFromDebugfs;
import static com.android.server.stats.IonMemoryUtil.readSystemIonHeapSizeFromDebugfs;
import static com.android.server.stats.ProcfsMemoryUtil.readMemorySnapshotFromProcfs;
import static com.android.server.stats.ProcfsMemoryUtil.readRssHighWaterMarkFromProcfs;
import android.annotation.NonNull;
@@ -141,6 +142,7 @@ import com.android.server.SystemServiceManager;
import com.android.server.am.MemoryStatUtil.MemoryStat;
import com.android.server.role.RoleManagerInternal;
import com.android.server.stats.IonMemoryUtil.IonAllocations;
import com.android.server.stats.ProcfsMemoryUtil.MemorySnapshot;
import com.android.server.storage.DiskStatsFileLogger;
import com.android.server.storage.DiskStatsLoggingService;
@@ -1270,6 +1272,47 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
SystemProperties.set("sys.rss_hwm_reset.on", "1");
}
private void pullProcessMemorySnapshot(
int tagId, long elapsedNanos, long wallClockNanos,
List<StatsLogEventWrapper> pulledData) {
List<ProcessMemoryState> managedProcessList =
LocalServices.getService(
ActivityManagerInternal.class).getMemoryStateForProcesses();
for (ProcessMemoryState managedProcess : managedProcessList) {
StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
e.writeInt(managedProcess.uid);
e.writeString(managedProcess.processName);
e.writeInt(managedProcess.pid);
e.writeInt(managedProcess.oomScore);
final MemorySnapshot snapshot = readMemorySnapshotFromProcfs(managedProcess.pid);
if (snapshot.isEmpty()) {
continue;
}
e.writeInt(snapshot.rssInKilobytes);
e.writeInt(snapshot.anonRssInKilobytes);
e.writeInt(snapshot.swapInKilobytes);
e.writeInt(snapshot.anonRssInKilobytes + snapshot.swapInKilobytes);
pulledData.add(e);
}
int[] pids = getPidsForCommands(MEMORY_INTERESTING_NATIVE_PROCESSES);
for (int pid : pids) {
StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
e.writeInt(getUidForPid(pid));
e.writeString(readCmdlineFromProcfs(pid));
e.writeInt(pid);
e.writeInt(-1001); // Placeholder for native processes, OOM_SCORE_ADJ_MIN - 1.
final MemorySnapshot snapshot = readMemorySnapshotFromProcfs(pid);
if (snapshot.isEmpty()) {
continue;
}
e.writeInt(snapshot.rssInKilobytes);
e.writeInt(snapshot.anonRssInKilobytes);
e.writeInt(snapshot.swapInKilobytes);
e.writeInt(snapshot.anonRssInKilobytes + snapshot.swapInKilobytes);
pulledData.add(e);
}
}
private void pullSystemIonHeapSize(
int tagId, long elapsedNanos, long wallClockNanos,
List<StatsLogEventWrapper> pulledData) {
@@ -2352,6 +2395,10 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
pullProcessMemoryHighWaterMark(tagId, elapsedNanos, wallClockNanos, ret);
break;
}
case StatsLog.PROCESS_MEMORY_SNAPSHOT: {
pullProcessMemorySnapshot(tagId, elapsedNanos, wallClockNanos, ret);
break;
}
case StatsLog.SYSTEM_ION_HEAP_SIZE: {
pullSystemIonHeapSize(tagId, elapsedNanos, wallClockNanos, ret);
break;

View File

@@ -15,12 +15,15 @@
*/
package com.android.server.stats;
import static com.android.server.stats.ProcfsMemoryUtil.parseMemorySnapshotFromStatus;
import static com.android.server.stats.ProcfsMemoryUtil.parseVmHWMFromStatus;
import static com.google.common.truth.Truth.assertThat;
import androidx.test.filters.SmallTest;
import com.android.server.stats.ProcfsMemoryUtil.MemorySnapshot;
import org.junit.Test;
/**
@@ -90,4 +93,32 @@ public class ProcfsMemoryUtilTest {
public void testParseVmHWMFromStatus_emptyContents() {
assertThat(parseVmHWMFromStatus("")).isEqualTo(0);
}
@Test
public void testParseMemorySnapshotFromStatus_parsesCorrectValue() {
MemorySnapshot snapshot = parseMemorySnapshotFromStatus(STATUS_CONTENTS);
assertThat(snapshot.rssInKilobytes).isEqualTo(126776);
assertThat(snapshot.anonRssInKilobytes).isEqualTo(37860);
assertThat(snapshot.swapInKilobytes).isEqualTo(22);
assertThat(snapshot.isEmpty()).isFalse();
}
@Test
public void testParseMemorySnapshotFromStatus_invalidValue() {
MemorySnapshot snapshot =
parseMemorySnapshotFromStatus("test\nVmRSS:\tx0x0x\nVmSwap:\t1 kB\ntest");
assertThat(snapshot.rssInKilobytes).isEqualTo(0);
assertThat(snapshot.anonRssInKilobytes).isEqualTo(0);
assertThat(snapshot.swapInKilobytes).isEqualTo(1);
assertThat(snapshot.isEmpty()).isFalse();
}
@Test
public void testParseMemorySnapshotFromStatus_emptyContents() {
MemorySnapshot snapshot = parseMemorySnapshotFromStatus("");
assertThat(snapshot.rssInKilobytes).isEqualTo(0);
assertThat(snapshot.anonRssInKilobytes).isEqualTo(0);
assertThat(snapshot.swapInKilobytes).isEqualTo(0);
assertThat(snapshot.isEmpty()).isTrue();
}
}