Add ProcessMemorySnapshot atom
Introduce new atom to replace existing ProcessMemoryState and NativeProcessMemoryState ones for telemetry purposes. This change is the first step to decouple memory stats from the framework internals. Follow-up CLs will remove the telemetry parts from the existing atoms. Test: atest ProcfsMemoryUtilTest Test: statsd_testdrive 10064 Change-Id: I7959c6e473201c10e7da17fa49d864bb03a2403c
This commit is contained in:
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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)}},
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user