Merge "Read per-process GPU memory when pulling ProcessMemorySnapshot"

This commit is contained in:
Ioannis Ilkos
2021-12-06 21:13:03 +00:00
committed by Android (Google) Code Review
6 changed files with 134 additions and 76 deletions

View File

@@ -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();
}

View File

@@ -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",

View File

@@ -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),

View File

@@ -1,60 +0,0 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <dmabufinfo/dmabufinfo.h>
#include "core_jni_helpers.h"
namespace android {
static jobject DmabufInfoReader_getProcessStats(JNIEnv *env, jobject, jint pid) {
std::vector<dmabufinfo::DmaBuffer> buffers;
if (!dmabufinfo::ReadDmaBufMapRefs(pid, &buffers)) {
return nullptr;
}
jint mappedSize = 0;
jint mappedCount = buffers.size();
for (const auto &buffer : buffers) {
mappedSize += buffer.size();
}
mappedSize /= 1024;
jint retainedSize = -1;
jint retainedCount = -1;
if (dmabufinfo::ReadDmaBufFdRefs(pid, &buffers)) {
retainedCount = buffers.size();
retainedSize = 0;
for (const auto &buffer : buffers) {
retainedSize += buffer.size();
}
retainedSize /= 1024;
}
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 const JNINativeMethod methods[] = {
{"getProcessStats", "(I)Lcom/android/internal/os/DmabufInfoReader$ProcessDmabuf;",
(void *)DmabufInfoReader_getProcessStats},
};
int register_com_android_internal_os_DmabufInfoReader(JNIEnv *env) {
return RegisterMethodsOrDie(env, "com/android/internal/os/DmabufInfoReader", methods,
NELEM(methods));
}
} // namespace android

View File

@@ -0,0 +1,97 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* 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 KernelAllocationStats_getDmabufAllocations(JNIEnv *env, jobject, jint pid) {
std::vector<dmabufinfo::DmaBuffer> buffers;
if (!dmabufinfo::ReadDmaBufMapRefs(pid, &buffers)) {
return nullptr;
}
jint mappedSize = 0;
jint mappedCount = buffers.size();
for (const auto &buffer : buffers) {
mappedSize += buffer.size();
}
mappedSize /= 1024;
jint retainedSize = -1;
jint retainedCount = -1;
if (dmabufinfo::ReadDmaBufFdRefs(pid, &buffers)) {
retainedCount = buffers.size();
retainedSize = 0;
for (const auto &buffer : buffers) {
retainedSize += buffer.size();
}
retainedSize /= 1024;
}
return env->NewObject(gProcessDmabufClazz, gProcessDmabufCtor, 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[] = {
{"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_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

View File

@@ -172,6 +172,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;
@@ -183,7 +184,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;
@@ -425,7 +426,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();
@@ -563,9 +563,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);
@@ -2218,10 +2216,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) {
@@ -2230,7 +2234,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
@@ -2248,7 +2253,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;
}
@@ -2328,7 +2334,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;
}