From 5911b9ef0a4e28cd2f3921681f5da4afd32e443a Mon Sep 17 00:00:00 2001 From: Suren Baghdasaryan Date: Mon, 25 Nov 2019 19:24:46 -0800 Subject: [PATCH 1/3] Add JNI API to query sizes of ION heaps, pools and mapped part of the heaps Provide means for system_server to query ION memory usage. The new API allows to get total size of ION heaps, pools and part of ION heaps that is mapped into user space. Bug: 138148041 Test: dumpsys meminfo Change-Id: I6d76d534bbab5ee1646e8e3e3fe5210dcf76bc23 Merged-In: I6d76d534bbab5ee1646e8e3e3fe5210dcf76bc23 Signed-off-by: Suren Baghdasaryan --- core/java/android/os/Debug.java | 23 +++++++++++++ core/jni/Android.bp | 1 + core/jni/android_os_Debug.cpp | 60 +++++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+) diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java index bf26a41c536af..422761c4dca58 100644 --- a/core/java/android/os/Debug.java +++ b/core/java/android/os/Debug.java @@ -2503,4 +2503,27 @@ public final class Debug * @hide */ public static native long getZramFreeKb(); + + /** + * Return memory size in kilobytes allocated for ION heaps. + * + * @hide + */ + public static native long getIonHeapsSizeKb(); + + /** + * Return memory size in kilobytes allocated for ION pools. + * + * @hide + */ + public static native long getIonPoolsSizeKb(); + + /** + * Return ION memory mapped by processes in kB. + * Notes: + * * Warning: Might impact performance as it reads /proc//maps files for each process. + * + * @hide + */ + public static native long getIonMappedSizeKb(); } diff --git a/core/jni/Android.bp b/core/jni/Android.bp index 49c029cb75451..f68fd5799cfcf 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -233,6 +233,7 @@ cc_library_shared { static_libs: [ "libasync_safe", + "libdmabufinfo", "libgif", "libseccomp_policy", "libgrallocusage", diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp index 6aed1e8ffe606..1ff28feb67386 100644 --- a/core/jni/android_os_Debug.cpp +++ b/core/jni/android_os_Debug.cpp @@ -43,6 +43,7 @@ #include #include #include "jni.h" +#include #include #include #include @@ -779,6 +780,59 @@ static jlong android_os_Debug_getFreeZramKb(JNIEnv* env, jobject clazz) { return zramFreeKb; } +static jlong android_os_Debug_getIonHeapsSizeKb(JNIEnv* env, jobject clazz) { + jlong heapsSizeKb = 0; + uint64_t size; + + if (meminfo::ReadIonHeapsSizeKb(&size)) { + heapsSizeKb = size; + } + + return heapsSizeKb; +} + +static jlong android_os_Debug_getIonPoolsSizeKb(JNIEnv* env, jobject clazz) { + jlong poolsSizeKb = 0; + uint64_t size; + + if (meminfo::ReadIonPoolsSizeKb(&size)) { + poolsSizeKb = size; + } + + return poolsSizeKb; +} + +static jlong android_os_Debug_getIonMappedSizeKb(JNIEnv* env, jobject clazz) { + jlong ionPss = 0; + std::vector dmabufs; + + std::unique_ptr dir(opendir("/proc"), closedir); + if (!dir) { + LOG(ERROR) << "Failed to open /proc directory"; + return false; + } + + struct dirent* dent; + while ((dent = readdir(dir.get()))) { + if (dent->d_type != DT_DIR) continue; + + int pid = atoi(dent->d_name); + if (pid == 0) { + continue; + } + + if (!AppendDmaBufInfo(pid, &dmabufs, false)) { + LOG(ERROR) << "Failed to read maps for pid " << pid; + } + } + + for (dmabufinfo::DmaBuffer buf : dmabufs) { + ionPss += buf.size() / 1024; + } + + return ionPss; +} + /* * JNI registration. */ @@ -822,6 +876,12 @@ static const JNINativeMethod gMethods[] = { (void*)android_os_Debug_getUnreachableMemory }, { "getZramFreeKb", "()J", (void*)android_os_Debug_getFreeZramKb }, + { "getIonHeapsSizeKb", "()J", + (void*)android_os_Debug_getIonHeapsSizeKb }, + { "getIonPoolsSizeKb", "()J", + (void*)android_os_Debug_getIonPoolsSizeKb }, + { "getIonMappedSizeKb", "()J", + (void*)android_os_Debug_getIonMappedSizeKb }, }; int register_android_os_Debug(JNIEnv *env) From 40899ad1e693a94ea0abb24d34c350dfaf36979f Mon Sep 17 00:00:00 2001 From: Suren Baghdasaryan Date: Mon, 25 Nov 2019 19:30:29 -0800 Subject: [PATCH 2/3] Improve cached kernel memory accounting using meminfo KReclaimable field KReclaimable field from /proc/meminfo is designed to represent total amount of memory that kernel can reclaim when needed. This includes reclaimable memory consumed by slab and reported in SReclaimable field as well as ION pools. By using KReclaimable instead of SReclaimable we will account for ION pools currently reported under "Lost RAM" category in dumpsys meminfo report. Bug: 138148041 Test: dumpsys meminfo Change-Id: Ifdea234d05639db93074ab598b81db5ff5b43612 Signed-off-by: Suren Baghdasaryan --- core/java/com/android/internal/util/MemInfoReader.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/core/java/com/android/internal/util/MemInfoReader.java b/core/java/com/android/internal/util/MemInfoReader.java index c1d129b66e7af..362bc92e40ad2 100644 --- a/core/java/com/android/internal/util/MemInfoReader.java +++ b/core/java/com/android/internal/util/MemInfoReader.java @@ -91,7 +91,15 @@ public final class MemInfoReader { * that are mapped in to processes. */ public long getCachedSizeKb() { - return mInfos[Debug.MEMINFO_BUFFERS] + mInfos[Debug.MEMINFO_SLAB_RECLAIMABLE] + long kReclaimable = mInfos[Debug.MEMINFO_KRECLAIMABLE]; + + // Note: MEMINFO_KRECLAIMABLE includes MEMINFO_SLAB_RECLAIMABLE and ION pools. + // Fall back to using MEMINFO_SLAB_RECLAIMABLE in case of older kernels that do + // not include KReclaimable meminfo field. + if (kReclaimable == 0) { + kReclaimable = mInfos[Debug.MEMINFO_SLAB_RECLAIMABLE]; + } + return mInfos[Debug.MEMINFO_BUFFERS] + kReclaimable + mInfos[Debug.MEMINFO_CACHED] - mInfos[Debug.MEMINFO_MAPPED]; } From da5a9dd5ff58b38baff98a0446781f169eac06a7 Mon Sep 17 00:00:00 2001 From: Suren Baghdasaryan Date: Mon, 25 Nov 2019 19:43:44 -0800 Subject: [PATCH 3/3] Add ION usage into dumpsys report and account ION pools as kernel cache Report ION pools, ION mapped and unmapped heap sizes. Account ION pools as kernel reclaimable memory which removes them from the "Lost RAM" category. Bug: 138148041 Test: dumpsys meminfo Change-Id: Ica3e1c3f73656b1b937f2fc58c18e0157e02bf57 Signed-off-by: Suren Baghdasaryan --- .../server/am/ActivityManagerService.java | 40 ++++++++++++++++--- 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 35774ed3ca6f9..1c4f1e3ed5bf1 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -12799,14 +12799,31 @@ public class ActivityManagerService extends IActivityManager.Stub pw.println(totalPss - cachedPss); } } - long lostRAM = memInfo.getTotalSizeKb() - (totalPss - totalSwapPss) + long kernelUsed = memInfo.getKernelUsedSizeKb(); + final long ionHeap = Debug.getIonHeapsSizeKb(); + if (ionHeap > 0) { + final long ionMapped = Debug.getIonMappedSizeKb(); + final long ionUnmapped = ionHeap - ionMapped; + final long ionPool = Debug.getIonPoolsSizeKb(); + pw.print(" ION: "); + pw.print(stringifyKBSize(ionHeap + ionPool)); + pw.print(" ("); + pw.print(stringifyKBSize(ionMapped)); + pw.print(" mapped + "); + pw.print(stringifyKBSize(ionUnmapped)); + pw.print(" unmapped + "); + pw.print(stringifyKBSize(ionPool)); + pw.println(" pools)"); + kernelUsed += ionUnmapped; + } + final long lostRAM = memInfo.getTotalSizeKb() - (totalPss - totalSwapPss) - memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb() - - memInfo.getKernelUsedSizeKb() - memInfo.getZramTotalSizeKb(); + - kernelUsed - memInfo.getZramTotalSizeKb(); if (!opts.isCompact) { pw.print(" Used RAM: "); pw.print(stringifyKBSize(totalPss - cachedPss - + memInfo.getKernelUsedSizeKb())); pw.print(" ("); + + kernelUsed)); pw.print(" ("); pw.print(stringifyKBSize(totalPss - cachedPss)); pw.print(" used pss + "); - pw.print(stringifyKBSize(memInfo.getKernelUsedSizeKb())); pw.print(" kernel)\n"); + pw.print(stringifyKBSize(kernelUsed)); pw.print(" kernel)\n"); pw.print(" Lost RAM: "); pw.println(stringifyKBSize(lostRAM)); } else { pw.print("lostram,"); pw.println(lostRAM); @@ -13525,14 +13542,25 @@ public class ActivityManagerService extends IActivityManager.Stub memInfoBuilder.append(stringifyKBSize(cachedPss + memInfo.getCachedSizeKb() + memInfo.getFreeSizeKb())); memInfoBuilder.append("\n"); + long kernelUsed = memInfo.getKernelUsedSizeKb(); + final long ionHeap = Debug.getIonHeapsSizeKb(); + if (ionHeap > 0) { + final long ionMapped = Debug.getIonMappedSizeKb(); + final long ionUnmapped = ionHeap - ionMapped; + final long ionPool = Debug.getIonPoolsSizeKb(); + memInfoBuilder.append(" ION: "); + memInfoBuilder.append(stringifyKBSize(ionHeap + ionPool)); + memInfoBuilder.append("\n"); + kernelUsed += ionUnmapped; + } memInfoBuilder.append(" Used RAM: "); memInfoBuilder.append(stringifyKBSize( - totalPss - cachedPss + memInfo.getKernelUsedSizeKb())); + totalPss - cachedPss + kernelUsed)); memInfoBuilder.append("\n"); memInfoBuilder.append(" Lost RAM: "); memInfoBuilder.append(stringifyKBSize(memInfo.getTotalSizeKb() - (totalPss - totalSwapPss) - memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb() - - memInfo.getKernelUsedSizeKb() - memInfo.getZramTotalSizeKb())); + - kernelUsed - memInfo.getZramTotalSizeKb())); memInfoBuilder.append("\n"); Slog.i(TAG, "Low on memory:"); Slog.i(TAG, shortNativeBuilder.toString());