Merge "Add ProcessMemorySnapshot atom"
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