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

Commit b3c88901 authored by Rafal Slawik's avatar Rafal Slawik Committed by Automerger Merge Worker
Browse files

Merge "Manage time_in_state tracking from one place" into sc-dev am: e4244b9d

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/13580619

MUST ONLY BE SUBMITTED BY AUTOMERGER

Change-Id: I2c54dcf44bd581d9cda10fa28c5c97f721e42b4c
parents d24e3e57 e4244b9d
Loading
Loading
Loading
Loading
+69 −1
Original line number Diff line number Diff line
@@ -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;
    }
}
+13 −13
Original line number Diff line number Diff line
@@ -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();
}
+7 −4
Original line number Diff line number Diff line
@@ -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();

@@ -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;
@@ -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) {
+40 −0
Original line number Diff line number Diff line
@@ -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) {
+13 −19
Original line number Diff line number Diff line
@@ -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