Loading core/java/com/android/internal/os/KernelCpuBpfTracking.java +69 −1 Original line number Diff line number Diff line Loading @@ -16,11 +16,79 @@ package com.android.internal.os; /** CPU tracking using eBPF. */ import android.annotation.Nullable; /** * CPU tracking using eBPF. * * The tracking state and data about available frequencies are cached to avoid JNI calls and * creating temporary arrays. The data is stored in a format that is convenient for metrics * computation. * * Synchronization is not needed because the underlying native library can be invoked concurrently * and getters are idempotent. */ public final class KernelCpuBpfTracking { private static boolean sTracking = false; /** Cached mapping from frequency index to frequency in kHz. */ private static long[] sFreqs = null; /** Cached mapping from frequency index to CPU cluster / policy. */ private static int[] sFreqsClusters = null; private KernelCpuBpfTracking() { } /** Returns whether CPU tracking using eBPF is supported. */ public static native boolean isSupported(); /** Starts CPU tracking using eBPF. */ public static boolean startTracking() { if (!sTracking) { sTracking = startTrackingInternal(); } return sTracking; } private static native boolean startTrackingInternal(); /** Returns frequencies in kHz on which CPU is tracked. Empty if not supported. */ public static long[] getFreqs() { if (sFreqs == null) { long[] freqs = getFreqsInternal(); if (freqs == null) { return new long[0]; } sFreqs = freqs; } return sFreqs; } @Nullable static native long[] getFreqsInternal(); /** * Returns the cluster (policy) number for each frequency on which CPU is tracked. Empty if * not supported. */ public static int[] getFreqsClusters() { if (sFreqsClusters == null) { int[] freqsClusters = getFreqsClustersInternal(); if (freqsClusters == null) { return new int[0]; } sFreqsClusters = freqsClusters; } return sFreqsClusters; } @Nullable private static native int[] getFreqsClustersInternal(); /** Returns the number of clusters (policies). */ public static int getClusters() { int[] freqClusters = getFreqsClusters(); return freqClusters.length > 0 ? freqClusters[freqClusters.length - 1] + 1 : 0; } } core/java/com/android/internal/os/KernelCpuTotalBpfMapReader.java +13 −13 Original line number Diff line number Diff line Loading @@ -16,22 +16,22 @@ package com.android.internal.os; /** * Reads total CPU time bpf map. */ import android.annotation.Nullable; /** Reads total CPU time bpf map. */ public final class KernelCpuTotalBpfMapReader { private KernelCpuTotalBpfMapReader() { } /** Reads total CPU time from bpf map. */ public static native boolean read(Callback callback); /** Callback accepting values read from bpf map. */ public interface Callback { /** * Accepts values read from bpf map: cluster index, frequency in kilohertz and time in * milliseconds that the cpu cluster spent at the frequency (excluding sleep). */ void accept(int cluster, int freqKhz, long timeMs); /** Reads total CPU times (excluding sleep) per frequency in milliseconds from bpf map. */ @Nullable public static long[] read() { if (!KernelCpuBpfTracking.startTracking()) { return null; } return readInternal(); } @Nullable private static native long[] readInternal(); } core/java/com/android/internal/os/KernelCpuUidBpfMapReader.java +7 −4 Original line number Diff line number Diff line Loading @@ -68,14 +68,15 @@ public abstract class KernelCpuUidBpfMapReader { final String mTag = this.getClass().getSimpleName(); private int mErrors = 0; private boolean mTracking = false; protected SparseArray<long[]> mData = new SparseArray<>(); private long mLastReadTime = 0; protected final ReentrantReadWriteLock mLock = new ReentrantReadWriteLock(); protected final ReentrantReadWriteLock.ReadLock mReadLock = mLock.readLock(); protected final ReentrantReadWriteLock.WriteLock mWriteLock = mLock.writeLock(); public native boolean startTrackingBpfTimes(); public boolean startTrackingBpfTimes() { return KernelCpuBpfTracking.startTracking(); } protected abstract boolean readBpfData(); Loading Loading @@ -116,7 +117,7 @@ public abstract class KernelCpuUidBpfMapReader { if (mErrors > ERROR_THRESHOLD) { return null; } if (!mTracking && !startTrackingBpfTimes()) { if (!startTrackingBpfTimes()) { Slog.w(mTag, "Failed to start tracking"); mErrors++; return null; Loading Loading @@ -182,7 +183,9 @@ public abstract class KernelCpuUidBpfMapReader { protected final native boolean readBpfData(); @Override public final native long[] getDataDimensions(); public final long[] getDataDimensions() { return KernelCpuBpfTracking.getFreqsInternal(); } @Override public void removeUidsInRange(int startUid, int endUid) { Loading core/jni/com_android_internal_os_KernelCpuBpfTracking.cpp +40 −0 Original line number Diff line number Diff line Loading @@ -24,8 +24,48 @@ static jboolean KernelCpuBpfTracking_isSupported(JNIEnv *, jobject) { return android::bpf::isTrackingUidTimesSupported() ? JNI_TRUE : JNI_FALSE; } static jboolean KernelCpuBpfTracking_startTrackingInternal(JNIEnv *, jobject) { return android::bpf::startTrackingUidTimes(); } static jlongArray KernelCpuBpfTracking_getFreqsInternal(JNIEnv *env, jobject) { auto freqs = android::bpf::getCpuFreqs(); if (!freqs) return NULL; std::vector<uint64_t> allFreqs; for (const auto &vec : *freqs) std::copy(vec.begin(), vec.end(), std::back_inserter(allFreqs)); auto ar = env->NewLongArray(allFreqs.size()); if (ar != NULL) { env->SetLongArrayRegion(ar, 0, allFreqs.size(), reinterpret_cast<const jlong *>(allFreqs.data())); } return ar; } static jintArray KernelCpuBpfTracking_getFreqsClustersInternal(JNIEnv *env, jobject) { auto freqs = android::bpf::getCpuFreqs(); if (!freqs) return NULL; std::vector<uint32_t> freqsClusters; uint32_t clusters = freqs->size(); for (uint32_t c = 0; c < clusters; ++c) { freqsClusters.insert(freqsClusters.end(), (*freqs)[c].size(), c); } auto ar = env->NewIntArray(freqsClusters.size()); if (ar != NULL) { env->SetIntArrayRegion(ar, 0, freqsClusters.size(), reinterpret_cast<const jint *>(freqsClusters.data())); } return ar; } static const JNINativeMethod methods[] = { {"isSupported", "()Z", (void *)KernelCpuBpfTracking_isSupported}, {"startTrackingInternal", "()Z", (void *)KernelCpuBpfTracking_startTrackingInternal}, {"getFreqsInternal", "()[J", (void *)KernelCpuBpfTracking_getFreqsInternal}, {"getFreqsClustersInternal", "()[I", (void *)KernelCpuBpfTracking_getFreqsClustersInternal}, }; int register_com_android_internal_os_KernelCpuBpfTracking(JNIEnv *env) { Loading core/jni/com_android_internal_os_KernelCpuTotalBpfMapReader.cpp +13 −19 Original line number Diff line number Diff line Loading @@ -20,33 +20,27 @@ namespace android { static jboolean KernelCpuTotalBpfMapReader_read(JNIEnv *env, jobject, jobject callback) { jclass callbackClass = env->GetObjectClass(callback); jmethodID callbackMethod = env->GetMethodID(callbackClass, "accept", "(IIJ)V"); if (callbackMethod == 0) { return JNI_FALSE; } auto freqs = android::bpf::getCpuFreqs(); if (!freqs) return JNI_FALSE; static jlongArray KernelCpuTotalBpfMapReader_readInternal(JNIEnv *env, jobject) { auto freqTimes = android::bpf::getTotalCpuFreqTimes(); if (!freqTimes) return JNI_FALSE; auto freqsClusterSize = (*freqs).size(); for (uint32_t clusterIndex = 0; clusterIndex < freqsClusterSize; ++clusterIndex) { auto freqsSize = (*freqs)[clusterIndex].size(); for (uint32_t freqIndex = 0; freqIndex < freqsSize; ++freqIndex) { env->CallVoidMethod(callback, callbackMethod, clusterIndex, (*freqs)[clusterIndex][freqIndex], (*freqTimes)[clusterIndex][freqIndex] / 1000000); std::vector<uint64_t> allTimes; for (const auto &vec : *freqTimes) { for (const auto &timeNs : vec) { allTimes.push_back(timeNs / 1000000); } } return JNI_TRUE; auto ar = env->NewLongArray(allTimes.size()); if (ar != NULL) { env->SetLongArrayRegion(ar, 0, allTimes.size(), reinterpret_cast<const jlong *>(allTimes.data())); } return ar; } static const JNINativeMethod methods[] = { {"read", "(Lcom/android/internal/os/KernelCpuTotalBpfMapReader$Callback;)Z", (void *)KernelCpuTotalBpfMapReader_read}, {"readInternal", "()[J", (void *)KernelCpuTotalBpfMapReader_readInternal}, }; int register_com_android_internal_os_KernelCpuTotalBpfMapReader(JNIEnv *env) { Loading Loading
core/java/com/android/internal/os/KernelCpuBpfTracking.java +69 −1 Original line number Diff line number Diff line Loading @@ -16,11 +16,79 @@ package com.android.internal.os; /** CPU tracking using eBPF. */ import android.annotation.Nullable; /** * CPU tracking using eBPF. * * The tracking state and data about available frequencies are cached to avoid JNI calls and * creating temporary arrays. The data is stored in a format that is convenient for metrics * computation. * * Synchronization is not needed because the underlying native library can be invoked concurrently * and getters are idempotent. */ public final class KernelCpuBpfTracking { private static boolean sTracking = false; /** Cached mapping from frequency index to frequency in kHz. */ private static long[] sFreqs = null; /** Cached mapping from frequency index to CPU cluster / policy. */ private static int[] sFreqsClusters = null; private KernelCpuBpfTracking() { } /** Returns whether CPU tracking using eBPF is supported. */ public static native boolean isSupported(); /** Starts CPU tracking using eBPF. */ public static boolean startTracking() { if (!sTracking) { sTracking = startTrackingInternal(); } return sTracking; } private static native boolean startTrackingInternal(); /** Returns frequencies in kHz on which CPU is tracked. Empty if not supported. */ public static long[] getFreqs() { if (sFreqs == null) { long[] freqs = getFreqsInternal(); if (freqs == null) { return new long[0]; } sFreqs = freqs; } return sFreqs; } @Nullable static native long[] getFreqsInternal(); /** * Returns the cluster (policy) number for each frequency on which CPU is tracked. Empty if * not supported. */ public static int[] getFreqsClusters() { if (sFreqsClusters == null) { int[] freqsClusters = getFreqsClustersInternal(); if (freqsClusters == null) { return new int[0]; } sFreqsClusters = freqsClusters; } return sFreqsClusters; } @Nullable private static native int[] getFreqsClustersInternal(); /** Returns the number of clusters (policies). */ public static int getClusters() { int[] freqClusters = getFreqsClusters(); return freqClusters.length > 0 ? freqClusters[freqClusters.length - 1] + 1 : 0; } }
core/java/com/android/internal/os/KernelCpuTotalBpfMapReader.java +13 −13 Original line number Diff line number Diff line Loading @@ -16,22 +16,22 @@ package com.android.internal.os; /** * Reads total CPU time bpf map. */ import android.annotation.Nullable; /** Reads total CPU time bpf map. */ public final class KernelCpuTotalBpfMapReader { private KernelCpuTotalBpfMapReader() { } /** Reads total CPU time from bpf map. */ public static native boolean read(Callback callback); /** Callback accepting values read from bpf map. */ public interface Callback { /** * Accepts values read from bpf map: cluster index, frequency in kilohertz and time in * milliseconds that the cpu cluster spent at the frequency (excluding sleep). */ void accept(int cluster, int freqKhz, long timeMs); /** Reads total CPU times (excluding sleep) per frequency in milliseconds from bpf map. */ @Nullable public static long[] read() { if (!KernelCpuBpfTracking.startTracking()) { return null; } return readInternal(); } @Nullable private static native long[] readInternal(); }
core/java/com/android/internal/os/KernelCpuUidBpfMapReader.java +7 −4 Original line number Diff line number Diff line Loading @@ -68,14 +68,15 @@ public abstract class KernelCpuUidBpfMapReader { final String mTag = this.getClass().getSimpleName(); private int mErrors = 0; private boolean mTracking = false; protected SparseArray<long[]> mData = new SparseArray<>(); private long mLastReadTime = 0; protected final ReentrantReadWriteLock mLock = new ReentrantReadWriteLock(); protected final ReentrantReadWriteLock.ReadLock mReadLock = mLock.readLock(); protected final ReentrantReadWriteLock.WriteLock mWriteLock = mLock.writeLock(); public native boolean startTrackingBpfTimes(); public boolean startTrackingBpfTimes() { return KernelCpuBpfTracking.startTracking(); } protected abstract boolean readBpfData(); Loading Loading @@ -116,7 +117,7 @@ public abstract class KernelCpuUidBpfMapReader { if (mErrors > ERROR_THRESHOLD) { return null; } if (!mTracking && !startTrackingBpfTimes()) { if (!startTrackingBpfTimes()) { Slog.w(mTag, "Failed to start tracking"); mErrors++; return null; Loading Loading @@ -182,7 +183,9 @@ public abstract class KernelCpuUidBpfMapReader { protected final native boolean readBpfData(); @Override public final native long[] getDataDimensions(); public final long[] getDataDimensions() { return KernelCpuBpfTracking.getFreqsInternal(); } @Override public void removeUidsInRange(int startUid, int endUid) { Loading
core/jni/com_android_internal_os_KernelCpuBpfTracking.cpp +40 −0 Original line number Diff line number Diff line Loading @@ -24,8 +24,48 @@ static jboolean KernelCpuBpfTracking_isSupported(JNIEnv *, jobject) { return android::bpf::isTrackingUidTimesSupported() ? JNI_TRUE : JNI_FALSE; } static jboolean KernelCpuBpfTracking_startTrackingInternal(JNIEnv *, jobject) { return android::bpf::startTrackingUidTimes(); } static jlongArray KernelCpuBpfTracking_getFreqsInternal(JNIEnv *env, jobject) { auto freqs = android::bpf::getCpuFreqs(); if (!freqs) return NULL; std::vector<uint64_t> allFreqs; for (const auto &vec : *freqs) std::copy(vec.begin(), vec.end(), std::back_inserter(allFreqs)); auto ar = env->NewLongArray(allFreqs.size()); if (ar != NULL) { env->SetLongArrayRegion(ar, 0, allFreqs.size(), reinterpret_cast<const jlong *>(allFreqs.data())); } return ar; } static jintArray KernelCpuBpfTracking_getFreqsClustersInternal(JNIEnv *env, jobject) { auto freqs = android::bpf::getCpuFreqs(); if (!freqs) return NULL; std::vector<uint32_t> freqsClusters; uint32_t clusters = freqs->size(); for (uint32_t c = 0; c < clusters; ++c) { freqsClusters.insert(freqsClusters.end(), (*freqs)[c].size(), c); } auto ar = env->NewIntArray(freqsClusters.size()); if (ar != NULL) { env->SetIntArrayRegion(ar, 0, freqsClusters.size(), reinterpret_cast<const jint *>(freqsClusters.data())); } return ar; } static const JNINativeMethod methods[] = { {"isSupported", "()Z", (void *)KernelCpuBpfTracking_isSupported}, {"startTrackingInternal", "()Z", (void *)KernelCpuBpfTracking_startTrackingInternal}, {"getFreqsInternal", "()[J", (void *)KernelCpuBpfTracking_getFreqsInternal}, {"getFreqsClustersInternal", "()[I", (void *)KernelCpuBpfTracking_getFreqsClustersInternal}, }; int register_com_android_internal_os_KernelCpuBpfTracking(JNIEnv *env) { Loading
core/jni/com_android_internal_os_KernelCpuTotalBpfMapReader.cpp +13 −19 Original line number Diff line number Diff line Loading @@ -20,33 +20,27 @@ namespace android { static jboolean KernelCpuTotalBpfMapReader_read(JNIEnv *env, jobject, jobject callback) { jclass callbackClass = env->GetObjectClass(callback); jmethodID callbackMethod = env->GetMethodID(callbackClass, "accept", "(IIJ)V"); if (callbackMethod == 0) { return JNI_FALSE; } auto freqs = android::bpf::getCpuFreqs(); if (!freqs) return JNI_FALSE; static jlongArray KernelCpuTotalBpfMapReader_readInternal(JNIEnv *env, jobject) { auto freqTimes = android::bpf::getTotalCpuFreqTimes(); if (!freqTimes) return JNI_FALSE; auto freqsClusterSize = (*freqs).size(); for (uint32_t clusterIndex = 0; clusterIndex < freqsClusterSize; ++clusterIndex) { auto freqsSize = (*freqs)[clusterIndex].size(); for (uint32_t freqIndex = 0; freqIndex < freqsSize; ++freqIndex) { env->CallVoidMethod(callback, callbackMethod, clusterIndex, (*freqs)[clusterIndex][freqIndex], (*freqTimes)[clusterIndex][freqIndex] / 1000000); std::vector<uint64_t> allTimes; for (const auto &vec : *freqTimes) { for (const auto &timeNs : vec) { allTimes.push_back(timeNs / 1000000); } } return JNI_TRUE; auto ar = env->NewLongArray(allTimes.size()); if (ar != NULL) { env->SetLongArrayRegion(ar, 0, allTimes.size(), reinterpret_cast<const jlong *>(allTimes.data())); } return ar; } static const JNINativeMethod methods[] = { {"read", "(Lcom/android/internal/os/KernelCpuTotalBpfMapReader$Callback;)Z", (void *)KernelCpuTotalBpfMapReader_read}, {"readInternal", "()[J", (void *)KernelCpuTotalBpfMapReader_readInternal}, }; int register_com_android_internal_os_KernelCpuTotalBpfMapReader(JNIEnv *env) { Loading