diff options
author | Dianne Hackborn <hackbod@google.com> | 2011-08-05 17:50:29 -0700 |
---|---|---|
committer | Dianne Hackborn <hackbod@google.com> | 2011-08-05 18:18:05 -0700 |
commit | b437e090ec03a2bab10bdfcb9484577a7f34e157 (patch) | |
tree | 86424e259db63fb8c7780a433b2eb808950fbc49 | |
parent | 284585aa835096111c7129b330f458b75ed27a8d (diff) | |
download | frameworks_base-b437e090ec03a2bab10bdfcb9484577a7f34e157.zip frameworks_base-b437e090ec03a2bab10bdfcb9484577a7f34e157.tar.gz frameworks_base-b437e090ec03a2bab10bdfcb9484577a7f34e157.tar.bz2 |
Improved memory use reporting.
Change-Id: I38e53e6228bba92a142bafeedb5af8df4e4e5724
-rw-r--r-- | api/current.txt | 1 | ||||
-rw-r--r-- | core/java/android/app/ActivityManagerNative.java | 22 | ||||
-rw-r--r-- | core/java/android/app/ActivityThread.java | 34 | ||||
-rw-r--r-- | core/java/android/app/ApplicationThreadNative.java | 9 | ||||
-rw-r--r-- | core/java/android/app/IActivityManager.java | 5 | ||||
-rw-r--r-- | core/java/android/app/IApplicationThread.java | 3 | ||||
-rw-r--r-- | core/java/android/os/Debug.java | 12 | ||||
-rw-r--r-- | core/jni/android_os_Debug.cpp | 37 | ||||
-rw-r--r-- | services/java/com/android/server/am/ActivityManagerService.java | 142 |
9 files changed, 214 insertions, 51 deletions
diff --git a/api/current.txt b/api/current.txt index 035da89..a70e8a2 100644 --- a/api/current.txt +++ b/api/current.txt @@ -14095,6 +14095,7 @@ package android.os { method public static long getNativeHeapAllocatedSize(); method public static long getNativeHeapFreeSize(); method public static long getNativeHeapSize(); + method public static long getPss(); method public static int getThreadAllocCount(); method public static int getThreadAllocSize(); method public static deprecated int getThreadExternalAllocCount(); diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index b7cd829..a73e10a 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -1523,6 +1523,15 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM return true; } + case GET_PROCESS_PSS_TRANSACTION: { + data.enforceInterface(IActivityManager.descriptor); + int[] pids = data.createIntArray(); + long[] pss = getProcessPss(pids); + reply.writeNoException(); + reply.writeLongArray(pss); + return true; + } + } return super.onTransact(code, data, reply, flags); @@ -3432,5 +3441,18 @@ class ActivityManagerProxy implements IActivityManager reply.recycle(); } + public long[] getProcessPss(int[] pids) throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + data.writeIntArray(pids); + mRemote.transact(GET_PROCESS_PSS_TRANSACTION, data, reply, 0); + reply.readException(); + long[] res = reply.createLongArray(); + data.recycle(); + reply.recycle(); + return res; + } + private IBinder mRemote; } diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index c566104..d5f630a 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -729,17 +729,19 @@ public final class ActivityThread { } @Override - public Debug.MemoryInfo dumpMemInfo(FileDescriptor fd, String[] args) { + public Debug.MemoryInfo dumpMemInfo(FileDescriptor fd, boolean checkin, + boolean all, String[] args) { FileOutputStream fout = new FileOutputStream(fd); PrintWriter pw = new PrintWriter(fout); try { - return dumpMemInfo(pw, args); + return dumpMemInfo(pw, checkin, all, args); } finally { pw.flush(); } } - private Debug.MemoryInfo dumpMemInfo(PrintWriter pw, String[] args) { + private Debug.MemoryInfo dumpMemInfo(PrintWriter pw, boolean checkin, boolean all, + String[] args) { long nativeMax = Debug.getNativeHeapSize() / 1024; long nativeAllocated = Debug.getNativeHeapAllocatedSize() / 1024; long nativeFree = Debug.getNativeHeapFreeSize() / 1024; @@ -747,6 +749,10 @@ public final class ActivityThread { Debug.MemoryInfo memInfo = new Debug.MemoryInfo(); Debug.getMemoryInfo(memInfo); + if (!all) { + return memInfo; + } + Runtime runtime = Runtime.getRuntime(); long dalvikMax = runtime.totalMemory() / 1024; @@ -765,16 +771,8 @@ public final class ActivityThread { long sqliteAllocated = SQLiteDebug.getHeapAllocatedSize() / 1024; SQLiteDebug.PagerStats stats = SQLiteDebug.getDatabaseInfo(); - // Check to see if we were called by checkin server. If so, print terse format. - boolean doCheckinFormat = false; - if (args != null) { - for (String arg : args) { - if ("-c".equals(arg)) doCheckinFormat = true; - } - } - // For checkin, we print one long comma-separated list of values - if (doCheckinFormat) { + if (checkin) { // NOTE: if you change anything significant below, also consider changing // ACTIVITY_THREAD_CHECKIN_VERSION. String processName = (mBoundApplication != null) @@ -841,13 +839,17 @@ public final class ActivityThread { pw.print(sqliteAllocated); pw.print(','); pw.print(stats.memoryUsed / 1024); pw.print(','); pw.print(stats.pageCacheOverflo / 1024); pw.print(','); - pw.print(stats.largestMemAlloc / 1024); pw.print(','); + pw.print(stats.largestMemAlloc / 1024); for (int i = 0; i < stats.dbStats.size(); i++) { DbStats dbStats = stats.dbStats.get(i); - printRow(pw, DB_INFO_FORMAT, dbStats.pageSize, dbStats.dbSize, - dbStats.lookaside, dbStats.cache, dbStats.dbName); - pw.print(','); + pw.print(','); pw.print(dbStats.dbName); + pw.print(','); pw.print(dbStats.pageSize); + pw.print(','); pw.print(dbStats.dbSize); + pw.print(','); pw.print(dbStats.lookaside); + pw.print(','); pw.print(dbStats.cache); + pw.print(','); pw.print(dbStats.cache); } + pw.println(); return memInfo; } diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java index 9a5b527..bea057e 100644 --- a/core/java/android/app/ApplicationThreadNative.java +++ b/core/java/android/app/ApplicationThreadNative.java @@ -491,11 +491,13 @@ public abstract class ApplicationThreadNative extends Binder { data.enforceInterface(IApplicationThread.descriptor); ParcelFileDescriptor fd = data.readFileDescriptor(); + boolean checkin = data.readInt() != 0; + boolean all = data.readInt() != 0; String[] args = data.readStringArray(); Debug.MemoryInfo mi = null; if (fd != null) { try { - mi = dumpMemInfo(fd.getFileDescriptor(), args); + mi = dumpMemInfo(fd.getFileDescriptor(), checkin, all, args); } finally { try { fd.close(); @@ -1049,11 +1051,14 @@ class ApplicationThreadProxy implements IApplicationThread { IBinder.FLAG_ONEWAY); } - public Debug.MemoryInfo dumpMemInfo(FileDescriptor fd, String[] args) throws RemoteException { + public Debug.MemoryInfo dumpMemInfo(FileDescriptor fd, boolean checkin, boolean all, + String[] args) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IApplicationThread.descriptor); data.writeFileDescriptor(fd); + data.writeInt(checkin ? 1 : 0); + data.writeInt(all ? 1 : 0); data.writeStringArray(args); mRemote.transact(DUMP_MEM_INFO_TRANSACTION, data, reply, 0); reply.readException(); diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index 64d77e8..b1b0583 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -364,7 +364,9 @@ public interface IActivityManager extends IInterface { public boolean isIntentSenderTargetedToPackage(IIntentSender sender) throws RemoteException; public void updatePersistentConfiguration(Configuration values) throws RemoteException; - + + public long[] getProcessPss(int[] pids) throws RemoteException; + /* * Private non-Binder interfaces */ @@ -593,4 +595,5 @@ public interface IActivityManager extends IInterface { int UNREGISTER_PROCESS_OBSERVER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+133; int IS_INTENT_SENDER_TARGETED_TO_PACKAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+134; int UPDATE_PERSISTENT_CONFIGURATION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+135; + int GET_PROCESS_PSS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+136; } diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java index d0607d0..3a8eb28 100644 --- a/core/java/android/app/IApplicationThread.java +++ b/core/java/android/app/IApplicationThread.java @@ -120,7 +120,8 @@ public interface IApplicationThread extends IInterface { void setCoreSettings(Bundle coreSettings) throws RemoteException; void updatePackageCompatibilityInfo(String pkg, CompatibilityInfo info) throws RemoteException; void scheduleTrimMemory(int level) throws RemoteException; - Debug.MemoryInfo dumpMemInfo(FileDescriptor fd, String[] args) throws RemoteException; + Debug.MemoryInfo dumpMemInfo(FileDescriptor fd, boolean checkin, boolean all, + String[] args) throws RemoteException; void dumpGfxInfo(FileDescriptor fd, String[] args) throws RemoteException; String descriptor = "android.app.IApplicationThread"; diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java index da2afb6..20a731e 100644 --- a/core/java/android/os/Debug.java +++ b/core/java/android/os/Debug.java @@ -818,6 +818,18 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo public static native void getMemoryInfo(int pid, MemoryInfo memoryInfo); /** + * Retrieves the PSS memory used by the process as given by the + * smaps. + */ + public static native long getPss(); + + /** + * Retrieves the PSS memory used by the process as given by the + * smaps. @hide + */ + public static native long getPss(int pid); + + /** * Establish an object allocation limit in the current thread. * This feature was never enabled in release builds. The * allocation limits feature was removed in Honeycomb. This diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp index 3a3f07e..85fac5f 100644 --- a/core/jni/android_os_Debug.cpp +++ b/core/jni/android_os_Debug.cpp @@ -279,6 +279,39 @@ static void android_os_Debug_getDirtyPages(JNIEnv *env, jobject clazz, jobject o android_os_Debug_getDirtyPagesPid(env, clazz, getpid(), object); } +static jlong android_os_Debug_getPssPid(JNIEnv *env, jobject clazz, jint pid) +{ + char line[1024]; + jlong pss = 0; + unsigned temp; + + char tmp[128]; + FILE *fp; + + sprintf(tmp, "/proc/%d/smaps", pid); + fp = fopen(tmp, "r"); + if (fp == 0) return 0; + + while (true) { + if (fgets(line, 1024, fp) == 0) { + break; + } + + if (sscanf(line, "Pss: %d kB", &temp) == 1) { + pss += temp; + } + } + + fclose(fp); + + return pss; +} + +static jlong android_os_Debug_getPss(JNIEnv *env, jobject clazz) +{ + return android_os_Debug_getPssPid(env, clazz, getpid()); +} + static jint read_binder_stat(const char* stat) { FILE* fp = fopen(BINDER_STATS, "r"); @@ -520,6 +553,10 @@ static JNINativeMethod gMethods[] = { (void*) android_os_Debug_getDirtyPages }, { "getMemoryInfo", "(ILandroid/os/Debug$MemoryInfo;)V", (void*) android_os_Debug_getDirtyPagesPid }, + { "getPss", "()J", + (void*) android_os_Debug_getPss }, + { "getPss", "(I)J", + (void*) android_os_Debug_getPssPid }, { "dumpNativeHeap", "(Ljava/io/FileDescriptor;)V", (void*) android_os_Debug_dumpNativeHeap }, { "getBinderSentTransactions", "()I", diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 14c6306..ba8b58b 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -3317,6 +3317,14 @@ public final class ActivityManagerService extends ActivityManagerNative return infos; } + public long[] getProcessPss(int[] pids) throws RemoteException { + long[] pss = new long[pids.length]; + for (int i=pids.length-1; i>=0; i--) { + pss[i] = Debug.getPss(pids[i]); + } + return pss; + } + public void killApplicationProcess(String processName, int uid) { if (processName == null) { return; @@ -8868,15 +8876,15 @@ public final class ActivityManagerService extends ActivityManagerNative } } - ArrayList<ProcessRecord> collectProcesses(PrintWriter pw, String[] args) { + ArrayList<ProcessRecord> collectProcesses(PrintWriter pw, int start, String[] args) { ArrayList<ProcessRecord> procs; synchronized (this) { - if (args != null && args.length > 0 - && args[0].charAt(0) != '-') { + if (args != null && args.length > start + && args[start].charAt(0) != '-') { procs = new ArrayList<ProcessRecord>(); int pid = -1; try { - pid = Integer.parseInt(args[0]); + pid = Integer.parseInt(args[start]); } catch (NumberFormatException e) { } @@ -8884,12 +8892,12 @@ public final class ActivityManagerService extends ActivityManagerNative ProcessRecord proc = mLruProcesses.get(i); if (proc.pid == pid) { procs.add(proc); - } else if (proc.processName.equals(args[0])) { + } else if (proc.processName.equals(args[start])) { procs.add(proc); } } if (procs.size() <= 0) { - pw.println("No process found for: " + args[0]); + pw.println("No process found for: " + args[start]); return null; } } else { @@ -8901,7 +8909,7 @@ public final class ActivityManagerService extends ActivityManagerNative final void dumpGraphicsHardwareUsage(FileDescriptor fd, PrintWriter pw, String[] args) { - ArrayList<ProcessRecord> procs = collectProcesses(pw, args); + ArrayList<ProcessRecord> procs = collectProcesses(pw, 0, args); if (procs == null) { return; } @@ -8945,18 +8953,21 @@ public final class ActivityManagerService extends ActivityManagerNative } } - final void dumpMemItems(PrintWriter pw, String prefix, ArrayList<MemItem> items) { - Collections.sort(items, new Comparator<MemItem>() { - @Override - public int compare(MemItem lhs, MemItem rhs) { - if (lhs.pss < rhs.pss) { - return 1; - } else if (lhs.pss > rhs.pss) { - return -1; + final void dumpMemItems(PrintWriter pw, String prefix, ArrayList<MemItem> items, + boolean sort) { + if (sort) { + Collections.sort(items, new Comparator<MemItem>() { + @Override + public int compare(MemItem lhs, MemItem rhs) { + if (lhs.pss < rhs.pss) { + return 1; + } else if (lhs.pss > rhs.pss) { + return -1; + } + return 0; } - return 0; - } - }); + }); + } for (int i=0; i<items.size(); i++) { MemItem mi = items.get(i); @@ -8966,7 +8977,29 @@ public final class ActivityManagerService extends ActivityManagerNative final void dumpApplicationMemoryUsage(FileDescriptor fd, PrintWriter pw, String prefix, String[] args) { - ArrayList<ProcessRecord> procs = collectProcesses(pw, args); + boolean dumpAll = false; + + int opti = 0; + while (opti < args.length) { + String opt = args[opti]; + if (opt == null || opt.length() <= 0 || opt.charAt(0) != '-') { + break; + } + opti++; + if ("-a".equals(opt)) { + dumpAll = true; + } else if ("-h".equals(opt)) { + pw.println("meminfo dump options: [-a] [process]"); + pw.println(" -a: include all available information for each process."); + pw.println("If [process] is specified it can be the name or "); + pw.println("pid of a specific process to dump."); + return; + } else { + pw.println("Unknown argument: " + opt + "; use -h for help"); + } + } + + ArrayList<ProcessRecord> procs = collectProcesses(pw, opti, args); if (procs == null) { return; } @@ -8974,7 +9007,11 @@ public final class ActivityManagerService extends ActivityManagerNative final boolean isCheckinRequest = scanArgs(args, "--checkin"); long uptime = SystemClock.uptimeMillis(); long realtime = SystemClock.elapsedRealtime(); - + + if (procs.size() == 1 || isCheckinRequest) { + dumpAll = true; + } + if (isCheckinRequest) { // short checkin version pw.println(uptime + "," + realtime); @@ -8984,29 +9021,53 @@ public final class ActivityManagerService extends ActivityManagerNative pw.println("Uptime: " + uptime + " Realtime: " + realtime); } + String[] innerArgs = new String[args.length-opti]; + System.arraycopy(args, opti, innerArgs, 0, args.length-opti); + ArrayList<MemItem> procMems = new ArrayList<MemItem>(); long nativePss=0, dalvikPss=0, otherPss=0; long[] miscPss = new long[Debug.MemoryInfo.NUM_OTHER_STATS]; + final int[] oomAdj = new int[] { + SYSTEM_ADJ, CORE_SERVER_ADJ, FOREGROUND_APP_ADJ, + VISIBLE_APP_ADJ, PERCEPTIBLE_APP_ADJ, HEAVY_WEIGHT_APP_ADJ, + BACKUP_APP_ADJ, SECONDARY_SERVER_ADJ, HOME_APP_ADJ, EMPTY_APP_ADJ + }; + final String[] oomLabel = new String[] { + "System", "Persistent", "Foreground", + "Visible", "Perceptible", "Heavy Weight", + "Backup", "Services", "Home", "Background" + }; + long oomPss[] = new long[oomLabel.length]; + + long totalPss = 0; + for (int i = procs.size() - 1 ; i >= 0 ; i--) { ProcessRecord r = procs.get(i); if (r.thread != null) { - if (!isCheckinRequest) { + if (!isCheckinRequest && dumpAll) { pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **"); pw.flush(); } Debug.MemoryInfo mi = null; - try { - mi = r.thread.dumpMemInfo(fd, args); - } catch (RemoteException e) { - if (!isCheckinRequest) { - pw.println("Got RemoteException!"); - pw.flush(); + if (dumpAll) { + try { + mi = r.thread.dumpMemInfo(fd, isCheckinRequest, dumpAll, innerArgs); + } catch (RemoteException e) { + if (!isCheckinRequest) { + pw.println("Got RemoteException!"); + pw.flush(); + } } + } else { + mi = new Debug.MemoryInfo(); + Debug.getMemoryInfo(r.pid, mi); } + if (!isCheckinRequest && mi != null) { - procMems.add(new MemItem(r.processName + " (pid " + r.pid + ")", - mi.getTotalPss())); + long myTotalPss = mi.getTotalPss(); + totalPss += myTotalPss; + procMems.add(new MemItem(r.processName + " (pid " + r.pid + ")", myTotalPss)); nativePss += mi.nativePss; dalvikPss += mi.dalvikPss; @@ -9016,6 +9077,13 @@ public final class ActivityManagerService extends ActivityManagerNative miscPss[j] += mem; otherPss -= mem; } + + for (int oomIndex=0; oomIndex<oomPss.length; oomIndex++) { + if (r.setAdj <= oomAdj[oomIndex] || oomIndex == (oomPss.length-1)) { + oomPss[oomIndex] += myTotalPss; + break; + } + } } } } @@ -9030,12 +9098,24 @@ public final class ActivityManagerService extends ActivityManagerNative catMems.add(new MemItem(Debug.MemoryInfo.getOtherLabel(j), miscPss[j])); } + ArrayList<MemItem> oomMems = new ArrayList<MemItem>(); + for (int j=0; j<oomPss.length; j++) { + if (oomPss[j] != 0) { + oomMems.add(new MemItem(oomLabel[j], oomPss[j])); + } + } + pw.println(); pw.println("Total PSS by process:"); - dumpMemItems(pw, " ", procMems); + dumpMemItems(pw, " ", procMems, true); + pw.println(); + pw.println("Total PSS by OOM adjustment:"); + dumpMemItems(pw, " ", oomMems, false); pw.println(); pw.println("Total PSS by category:"); - dumpMemItems(pw, " ", catMems); + dumpMemItems(pw, " ", catMems, true); + pw.println(); + pw.print("Total PSS: "); pw.print(totalPss); pw.println(" Kb"); } } |