Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cc793ab6 authored by Ioannis Ilkos's avatar Ioannis Ilkos
Browse files

Read per-process GPU memory when pulling ProcessMemorySnapshot

This is an eBPF usermap read via libmeminfo. System server
already has permissions to do so (as it already does so for the
total GPU mem stats).

Change-Id: I9e3c4dc9144708c630215e309b7ff394abbdcd76
Test: manual, statsd_testdrive 10064
Bug: 208440056
parent df8f2a90
Loading
Loading
Loading
Loading
+18 −4
Original line number Diff line number Diff line
@@ -18,9 +18,9 @@ package com.android.internal.os;

import android.annotation.Nullable;

/** Wrapper around libdmabufinfo. */
public final class DmabufInfoReader {
    private DmabufInfoReader() {}
/** JNI wrapper around libmeminfo for kernel memory allocation stats (dmabufs, gpu driver). */
public final class KernelAllocationStats {
    private KernelAllocationStats() {}

    /** Process dma-buf stats. */
    public static final class ProcessDmabuf {
@@ -47,5 +47,19 @@ public final class DmabufInfoReader {
     * stats could not be read.
     */
    @Nullable
    public static native ProcessDmabuf getProcessStats(int pid);
    public static native ProcessDmabuf getDmabufAllocations(int pid);

    /** Pid to gpu memory size. */
    public static final class ProcessGpuMem {
        public final int pid;
        public final int gpuMemoryKb;

        ProcessGpuMem(int pid, int gpuMemoryKb) {
            this.pid = pid;
            this.gpuMemoryKb = gpuMemoryKb;
        }
    }

    /** Return list of pid to gpu memory size. */
    public static native ProcessGpuMem[] getGpuAllocations();
}
+1 −1
Original line number Diff line number Diff line
@@ -210,8 +210,8 @@ cc_library_shared {
                "com_android_internal_content_om_OverlayConfig.cpp",
                "com_android_internal_net_NetworkUtilsInternal.cpp",
                "com_android_internal_os_ClassLoaderFactory.cpp",
                "com_android_internal_os_DmabufInfoReader.cpp",
                "com_android_internal_os_FuseAppLoop.cpp",
                "com_android_internal_os_KernelAllocationStats.cpp",
                "com_android_internal_os_KernelCpuBpfTracking.cpp",
                "com_android_internal_os_KernelCpuTotalBpfMapReader.cpp",
                "com_android_internal_os_KernelCpuUidBpfMapReader.cpp",
+2 −2
Original line number Diff line number Diff line
@@ -197,8 +197,8 @@ extern int register_com_android_internal_content_NativeLibraryHelper(JNIEnv *env
extern int register_com_android_internal_content_om_OverlayConfig(JNIEnv *env);
extern int register_com_android_internal_net_NetworkUtilsInternal(JNIEnv* env);
extern int register_com_android_internal_os_ClassLoaderFactory(JNIEnv* env);
extern int register_com_android_internal_os_DmabufInfoReader(JNIEnv* env);
extern int register_com_android_internal_os_FuseAppLoop(JNIEnv* env);
extern int register_com_android_internal_os_KernelAllocationStats(JNIEnv* env);
extern int register_com_android_internal_os_KernelCpuBpfTracking(JNIEnv* env);
extern int register_com_android_internal_os_KernelCpuTotalBpfMapReader(JNIEnv* env);
extern int register_com_android_internal_os_KernelCpuUidBpfMapReader(JNIEnv *env);
@@ -1655,8 +1655,8 @@ static const RegJNIRec gRegJNI[] = {
        REG_JNI(register_android_security_Scrypt),
        REG_JNI(register_com_android_internal_content_F2fsUtils),
        REG_JNI(register_com_android_internal_content_NativeLibraryHelper),
        REG_JNI(register_com_android_internal_os_DmabufInfoReader),
        REG_JNI(register_com_android_internal_os_FuseAppLoop),
        REG_JNI(register_com_android_internal_os_KernelAllocationStats),
        REG_JNI(register_com_android_internal_os_KernelCpuBpfTracking),
        REG_JNI(register_com_android_internal_os_KernelCpuTotalBpfMapReader),
        REG_JNI(register_com_android_internal_os_KernelCpuUidBpfMapReader),
+97 −0
Original line number Diff line number Diff line
@@ -13,13 +13,22 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <dmabufinfo/dmabufinfo.h>
#include <jni.h>
#include <meminfo/sysmeminfo.h>

#include "core_jni_helpers.h"

namespace {
static jclass gProcessDmabufClazz;
static jmethodID gProcessDmabufCtor;
static jclass gProcessGpuMemClazz;
static jmethodID gProcessGpuMemCtor;
} // namespace

namespace android {

static jobject DmabufInfoReader_getProcessStats(JNIEnv *env, jobject, jint pid) {
static jobject KernelAllocationStats_getDmabufAllocations(JNIEnv *env, jobject, jint pid) {
    std::vector<dmabufinfo::DmaBuffer> buffers;
    if (!dmabufinfo::ReadDmaBufMapRefs(pid, &buffers)) {
        return nullptr;
@@ -41,20 +50,48 @@ static jobject DmabufInfoReader_getProcessStats(JNIEnv *env, jobject, jint pid)
        }
        retainedSize /= 1024;
    }
    return env->NewObject(gProcessDmabufClazz, gProcessDmabufCtor, retainedSize, retainedCount,
                          mappedSize, mappedCount);
}

    jclass clazz = FindClassOrDie(env, "com/android/internal/os/DmabufInfoReader$ProcessDmabuf");
    jmethodID constructID = GetMethodIDOrDie(env, clazz, "<init>", "(IIII)V");
    return env->NewObject(clazz, constructID, retainedSize, retainedCount, mappedSize, mappedCount);
static jobject KernelAllocationStats_getGpuAllocations(JNIEnv *env) {
    std::unordered_map<uint32_t, uint64_t> out;
    meminfo::ReadPerProcessGpuMem(&out);
    jobjectArray result = env->NewObjectArray(out.size(), gProcessGpuMemClazz, nullptr);
    if (result == NULL) {
        jniThrowRuntimeException(env, "Cannot create result array");
        return nullptr;
    }
    int idx = 0;
    for (const auto &entry : out) {
        jobject pidStats =
                env->NewObject(gProcessGpuMemClazz, gProcessGpuMemCtor, entry.first, entry.second);
        env->SetObjectArrayElement(result, idx, pidStats);
        env->DeleteLocalRef(pidStats);
        ++idx;
    }
    return result;
}

static const JNINativeMethod methods[] = {
        {"getProcessStats", "(I)Lcom/android/internal/os/DmabufInfoReader$ProcessDmabuf;",
         (void *)DmabufInfoReader_getProcessStats},
        {"getDmabufAllocations", "(I)Lcom/android/internal/os/KernelAllocationStats$ProcessDmabuf;",
         (void *)KernelAllocationStats_getDmabufAllocations},
        {"getGpuAllocations", "()[Lcom/android/internal/os/KernelAllocationStats$ProcessGpuMem;",
         (void *)KernelAllocationStats_getGpuAllocations},
};

int register_com_android_internal_os_DmabufInfoReader(JNIEnv *env) {
    return RegisterMethodsOrDie(env, "com/android/internal/os/DmabufInfoReader", methods,
int register_com_android_internal_os_KernelAllocationStats(JNIEnv *env) {
    int res = RegisterMethodsOrDie(env, "com/android/internal/os/KernelAllocationStats", methods,
                                   NELEM(methods));
    jclass clazz =
            FindClassOrDie(env, "com/android/internal/os/KernelAllocationStats$ProcessDmabuf");
    gProcessDmabufClazz = MakeGlobalRefOrDie(env, clazz);
    gProcessDmabufCtor = GetMethodIDOrDie(env, gProcessDmabufClazz, "<init>", "(IIII)V");

    clazz = FindClassOrDie(env, "com/android/internal/os/KernelAllocationStats$ProcessGpuMem");
    gProcessGpuMemClazz = MakeGlobalRefOrDie(env, clazz);
    gProcessGpuMemCtor = GetMethodIDOrDie(env, gProcessGpuMemClazz, "<init>", "(II)V");
    return res;
}

} // namespace android
+16 −9
Original line number Diff line number Diff line
@@ -166,6 +166,7 @@ import android.util.Log;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseIntArray;
import android.util.StatsEvent;
import android.util.proto.ProtoOutputStream;
import android.view.Display;
@@ -177,7 +178,7 @@ import com.android.internal.os.BackgroundThread;
import com.android.internal.os.BatterySipper;
import com.android.internal.os.BatteryStatsHelper;
import com.android.internal.os.BinderCallsStats.ExportedCallStat;
import com.android.internal.os.DmabufInfoReader;
import com.android.internal.os.KernelAllocationStats;
import com.android.internal.os.KernelCpuBpfTracking;
import com.android.internal.os.KernelCpuThreadReader;
import com.android.internal.os.KernelCpuThreadReaderDiff;
@@ -418,7 +419,6 @@ public class StatsPullAtomService extends SystemService {
    private final Object mSystemUptimeLock = new Object();
    private final Object mProcessMemoryStateLock = new Object();
    private final Object mProcessMemoryHighWaterMarkLock = new Object();
    private final Object mProcessMemorySnapshotLock = new Object();
    private final Object mSystemIonHeapSizeLock = new Object();
    private final Object mIonHeapSizeLock = new Object();
    private final Object mProcessSystemIonHeapSizeLock = new Object();
@@ -556,9 +556,7 @@ public class StatsPullAtomService extends SystemService {
                            return pullProcessMemoryHighWaterMarkLocked(atomTag, data);
                        }
                    case FrameworkStatsLog.PROCESS_MEMORY_SNAPSHOT:
                        synchronized (mProcessMemorySnapshotLock) {
                            return pullProcessMemorySnapshotLocked(atomTag, data);
                        }
                        return pullProcessMemorySnapshot(atomTag, data);
                    case FrameworkStatsLog.SYSTEM_ION_HEAP_SIZE:
                        synchronized (mSystemIonHeapSizeLock) {
                            return pullSystemIonHeapSizeLocked(atomTag, data);
@@ -2211,10 +2209,16 @@ public class StatsPullAtomService extends SystemService {
        );
    }

    int pullProcessMemorySnapshotLocked(int atomTag, List<StatsEvent> pulledData) {
    int pullProcessMemorySnapshot(int atomTag, List<StatsEvent> pulledData) {
        List<ProcessMemoryState> managedProcessList =
                LocalServices.getService(ActivityManagerInternal.class)
                        .getMemoryStateForProcesses();
        KernelAllocationStats.ProcessGpuMem[] gpuAllocations =
                KernelAllocationStats.getGpuAllocations();
        SparseIntArray gpuMemPerPid = new SparseIntArray(gpuAllocations.length);
        for (KernelAllocationStats.ProcessGpuMem processGpuMem : gpuAllocations) {
            gpuMemPerPid.put(processGpuMem.pid, processGpuMem.gpuMemoryKb);
        }
        for (ProcessMemoryState managedProcess : managedProcessList) {
            final MemorySnapshot snapshot = readMemorySnapshotFromProcfs(managedProcess.pid);
            if (snapshot == null) {
@@ -2223,7 +2227,8 @@ public class StatsPullAtomService extends SystemService {
            pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, managedProcess.uid,
                    managedProcess.processName, managedProcess.pid, managedProcess.oomScore,
                    snapshot.rssInKilobytes, snapshot.anonRssInKilobytes, snapshot.swapInKilobytes,
                    snapshot.anonRssInKilobytes + snapshot.swapInKilobytes));
                    snapshot.anonRssInKilobytes + snapshot.swapInKilobytes,
                    gpuMemPerPid.get(managedProcess.pid)));
        }
        // Complement the data with native system processes. Given these measurements can be taken
        // in response to LMKs happening, we want to first collect the managed app stats (to
@@ -2241,7 +2246,8 @@ public class StatsPullAtomService extends SystemService {
                    processCmdlines.valueAt(i), pid,
                    -1001 /*Placeholder for native processes, OOM_SCORE_ADJ_MIN - 1.*/,
                    snapshot.rssInKilobytes, snapshot.anonRssInKilobytes, snapshot.swapInKilobytes,
                    snapshot.anonRssInKilobytes + snapshot.swapInKilobytes));
                    snapshot.anonRssInKilobytes + snapshot.swapInKilobytes,
                    gpuMemPerPid.get(pid)));
        }
        return StatsManager.PULL_SUCCESS;
    }
@@ -2321,7 +2327,8 @@ public class StatsPullAtomService extends SystemService {
            if (process.uid == Process.SYSTEM_UID) {
                continue;
            }
            DmabufInfoReader.ProcessDmabuf proc = DmabufInfoReader.getProcessStats(process.pid);
            KernelAllocationStats.ProcessDmabuf proc =
                    KernelAllocationStats.getDmabufAllocations(process.pid);
            if (proc == null || (proc.retainedBuffersCount <= 0 && proc.mappedBuffersCount <= 0)) {
                continue;
            }
Loading