diff options
| author | Dianne Hackborn <hackbod@google.com> | 2013-09-10 19:06:15 -0700 |
|---|---|---|
| committer | Dianne Hackborn <hackbod@google.com> | 2013-09-13 16:02:01 -0700 |
| commit | 8e69257a9c7e9c1781e1f53d8856358ada38921d (patch) | |
| tree | 69c9e07b9ed81d9ef8fb03769370b60d03e75f70 /core | |
| parent | 9210bc85545f31973c957b5179e6a82d05f473c6 (diff) | |
| download | frameworks_base-8e69257a9c7e9c1781e1f53d8856358ada38921d.zip frameworks_base-8e69257a9c7e9c1781e1f53d8856358ada38921d.tar.gz frameworks_base-8e69257a9c7e9c1781e1f53d8856358ada38921d.tar.bz2 | |
Implement #10749688: Improve low memory reporting
This significantly reworks the logging we do when
all cached processes are killed:
- We now collect the list of processes in-place so we
have a snapshot of exactly when the low memory situation
happened.
- In that snapshot we include the key process state: oom
adj, proc state, adj reasons.
- The report then asynchronously collects pss information
for those processes.
- The ultimate data printed to the log looks like a mix
between the "dumpsys meminfo" and "dumpsys activity"
output. This code no longer uses "dumpsys meminfo"
itself, so some of that data is no longer included,
in particular pss organized by allocation type.
In doing this, I realized that the existing code that is
supposed to run "procstats" is not currently working. And
at that point I realized, really, when we are collecting
this pss data we'd really like to include all those native
processes using ghod-only-knows how much RAM. And guess
what, we have a list of processes available in
ProcessCpuTracker.
So we now also collect and print information for native
processes, and we also do this for "dumpsys meminfo" which
really seems like a good thing when we are printing summaries
of all pss and such.
I also improved the code for reading /proc/meminfo to be
able to load all the interesting fields from there, and
am now printing that as well.
Change-Id: I9e7d13e9c07a8249c7a7e12e5433973b2c0fdc11
Diffstat (limited to 'core')
| -rw-r--r-- | core/java/android/os/Debug.java | 22 | ||||
| -rw-r--r-- | core/java/com/android/internal/os/ProcessCpuTracker.java | 26 | ||||
| -rw-r--r-- | core/java/com/android/internal/util/MemInfoReader.java | 34 | ||||
| -rw-r--r-- | core/jni/android_os_Debug.cpp | 83 |
4 files changed, 127 insertions, 38 deletions
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java index 8f68fc1..eb91238 100644 --- a/core/java/android/os/Debug.java +++ b/core/java/android/os/Debug.java @@ -1018,6 +1018,28 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo */ public static native long getPss(int pid, long[] outUss); + /** @hide */ + public static final int MEMINFO_TOTAL = 0; + /** @hide */ + public static final int MEMINFO_FREE = 1; + /** @hide */ + public static final int MEMINFO_BUFFERS = 2; + /** @hide */ + public static final int MEMINFO_CACHED = 3; + /** @hide */ + public static final int MEMINFO_SHMEM = 4; + /** @hide */ + public static final int MEMINFO_SLAB = 5; + /** @hide */ + public static final int MEMINFO_COUNT = 6; + + /** + * Retrieves /proc/meminfo. outSizes is filled with fields + * as defined by MEMINFO_* offsets. + * @hide + */ + public static native void getMemInfo(long[] outSizes); + /** * Establish an object allocation limit in the current thread. * This feature was never enabled in release builds. The diff --git a/core/java/com/android/internal/os/ProcessCpuTracker.java b/core/java/com/android/internal/os/ProcessCpuTracker.java index 30ca73e..58cd60d 100644 --- a/core/java/com/android/internal/os/ProcessCpuTracker.java +++ b/core/java/com/android/internal/os/ProcessCpuTracker.java @@ -49,12 +49,12 @@ public class ProcessCpuTracker { PROC_SPACE_TERM, PROC_SPACE_TERM, PROC_SPACE_TERM, - PROC_SPACE_TERM|PROC_OUT_LONG, // 9: minor faults + PROC_SPACE_TERM|PROC_OUT_LONG, // 10: minor faults PROC_SPACE_TERM, - PROC_SPACE_TERM|PROC_OUT_LONG, // 11: major faults + PROC_SPACE_TERM|PROC_OUT_LONG, // 12: major faults PROC_SPACE_TERM, - PROC_SPACE_TERM|PROC_OUT_LONG, // 13: utime - PROC_SPACE_TERM|PROC_OUT_LONG // 14: stime + PROC_SPACE_TERM|PROC_OUT_LONG, // 14: utime + PROC_SPACE_TERM|PROC_OUT_LONG, // 15: stime }; static final int PROCESS_STAT_MINOR_FAULTS = 0; @@ -69,7 +69,7 @@ public class ProcessCpuTracker { private static final int[] PROCESS_FULL_STATS_FORMAT = new int[] { PROC_SPACE_TERM, - PROC_SPACE_TERM|PROC_PARENS|PROC_OUT_STRING, // 1: name + PROC_SPACE_TERM|PROC_PARENS|PROC_OUT_STRING, // 2: name PROC_SPACE_TERM, PROC_SPACE_TERM, PROC_SPACE_TERM, @@ -77,19 +77,20 @@ public class ProcessCpuTracker { PROC_SPACE_TERM, PROC_SPACE_TERM, PROC_SPACE_TERM, - PROC_SPACE_TERM|PROC_OUT_LONG, // 9: minor faults + PROC_SPACE_TERM|PROC_OUT_LONG, // 10: minor faults PROC_SPACE_TERM, - PROC_SPACE_TERM|PROC_OUT_LONG, // 11: major faults + PROC_SPACE_TERM|PROC_OUT_LONG, // 12: major faults PROC_SPACE_TERM, - PROC_SPACE_TERM|PROC_OUT_LONG, // 13: utime - PROC_SPACE_TERM|PROC_OUT_LONG, // 14: stime + PROC_SPACE_TERM|PROC_OUT_LONG, // 14: utime + PROC_SPACE_TERM|PROC_OUT_LONG, // 15: stime PROC_SPACE_TERM, PROC_SPACE_TERM, PROC_SPACE_TERM, PROC_SPACE_TERM, PROC_SPACE_TERM, PROC_SPACE_TERM, - PROC_SPACE_TERM|PROC_OUT_LONG, // 21: vsize + PROC_SPACE_TERM, + PROC_SPACE_TERM|PROC_OUT_LONG, // 23: vsize }; static final int PROCESS_FULL_STAT_MINOR_FAULTS = 1; @@ -190,6 +191,10 @@ public class ProcessCpuTracker { public String name; public int nameWidth; + // vsize capture when process first detected; can be used to + // filter out kernel processes. + public long vsize; + public long base_uptime; public long rel_uptime; @@ -444,6 +449,7 @@ public class ProcessCpuTracker { // are actually kernel threads... do we want to? Some // of them do use CPU, but there can be a *lot* that are // not doing anything. + st.vsize = procStats[PROCESS_FULL_STAT_VSIZE]; if (true || procStats[PROCESS_FULL_STAT_VSIZE] != 0) { st.interesting = true; st.baseName = procStatsString[0]; diff --git a/core/java/com/android/internal/util/MemInfoReader.java b/core/java/com/android/internal/util/MemInfoReader.java index 850e1f0..ad65433 100644 --- a/core/java/com/android/internal/util/MemInfoReader.java +++ b/core/java/com/android/internal/util/MemInfoReader.java @@ -18,6 +18,7 @@ package com.android.internal.util; import java.io.FileInputStream; +import android.os.Debug; import android.os.StrictMode; public class MemInfoReader { @@ -63,34 +64,11 @@ public class MemInfoReader { // /proc/ and /sys/ files perhaps? StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads(); try { - mTotalSize = 0; - mFreeSize = 0; - mCachedSize = 0; - FileInputStream is = new FileInputStream("/proc/meminfo"); - int len = is.read(mBuffer); - is.close(); - final int BUFLEN = mBuffer.length; - int count = 0; - for (int i=0; i<len && count < 3; i++) { - if (matchText(mBuffer, i, "MemTotal")) { - i += 8; - mTotalSize = extractMemValue(mBuffer, i); - count++; - } else if (matchText(mBuffer, i, "MemFree")) { - i += 7; - mFreeSize = extractMemValue(mBuffer, i); - count++; - } else if (matchText(mBuffer, i, "Cached")) { - i += 6; - mCachedSize = extractMemValue(mBuffer, i); - count++; - } - while (i < BUFLEN && mBuffer[i] != '\n') { - i++; - } - } - } catch (java.io.FileNotFoundException e) { - } catch (java.io.IOException e) { + long[] infos = new long[Debug.MEMINFO_COUNT]; + Debug.getMemInfo(infos); + mTotalSize = infos[Debug.MEMINFO_TOTAL] * 1024; + mFreeSize = infos[Debug.MEMINFO_FREE] * 1024; + mCachedSize = infos[Debug.MEMINFO_CACHED] * 1024; } finally { StrictMode.setThreadPolicy(savedPolicy); } diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp index 1779c9f..60540f4 100644 --- a/core/jni/android_os_Debug.cpp +++ b/core/jni/android_os_Debug.cpp @@ -516,6 +516,87 @@ static jlong android_os_Debug_getPss(JNIEnv *env, jobject clazz) return android_os_Debug_getPssPid(env, clazz, getpid(), NULL); } +static void android_os_Debug_getMemInfo(JNIEnv *env, jobject clazz, jlongArray out) +{ + char buffer[1024]; + int numFound = 0; + + if (out == NULL) { + jniThrowNullPointerException(env, "out == null"); + return; + } + + int fd = open("/proc/meminfo", O_RDONLY); + + if (fd < 0) { + printf("Unable to open /proc/meminfo: %s\n", strerror(errno)); + return; + } + + const int len = read(fd, buffer, sizeof(buffer)-1); + close(fd); + + if (len < 0) { + printf("Empty /proc/meminfo"); + return; + } + buffer[len] = 0; + + static const char* const tags[] = { + "MemTotal:", + "MemFree:", + "Buffers:", + "Cached:", + "Shmem:", + "Slab:", + NULL + }; + static const int tagsLen[] = { + 9, + 8, + 8, + 7, + 6, + 5, + 0 + }; + long mem[] = { 0, 0, 0, 0, 0, 0 }; + + char* p = buffer; + while (*p && numFound < 6) { + int i = 0; + while (tags[i]) { + if (strncmp(p, tags[i], tagsLen[i]) == 0) { + p += tagsLen[i]; + while (*p == ' ') p++; + char* num = p; + while (*p >= '0' && *p <= '9') p++; + if (*p != 0) { + *p = 0; + p++; + } + mem[i] = atoll(num); + numFound++; + break; + } + i++; + } + while (*p && *p != '\n') { + p++; + } + if (*p) p++; + } + + int maxNum = env->GetArrayLength(out); + jlong* outArray = env->GetLongArrayElements(out, 0); + if (outArray != NULL) { + for (int i=0; i<maxNum && tags[i]; i++) { + outArray[i] = mem[i]; + } + } + env->ReleaseLongArrayElements(out, outArray, 0); +} + static jint read_binder_stat(const char* stat) { FILE* fp = fopen(BINDER_STATS, "r"); @@ -790,6 +871,8 @@ static JNINativeMethod gMethods[] = { (void*) android_os_Debug_getPss }, { "getPss", "(I[J)J", (void*) android_os_Debug_getPssPid }, + { "getMemInfo", "([J)V", + (void*) android_os_Debug_getMemInfo }, { "dumpNativeHeap", "(Ljava/io/FileDescriptor;)V", (void*) android_os_Debug_dumpNativeHeap }, { "getBinderSentTransactions", "()I", |
