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

Commit 7c51335f authored by Dmitri Plotnikov's avatar Dmitri Plotnikov Committed by Android (Google) Code Review
Browse files

Merge "Eliminate LongArrayContainer" into main

parents 74ba0bfe 88c3309b
Loading
Loading
Loading
Loading
+1 −3
Original line number Diff line number Diff line
@@ -159,9 +159,7 @@ public class LongArrayMultiStateCounterPerfTest {
        LongArrayMultiStateCounter counter = new LongArrayMultiStateCounter(2, 4);
        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
        long time = 1000;
        LongArrayMultiStateCounter.LongArrayContainer timeInFreq =
                new LongArrayMultiStateCounter.LongArrayContainer(4);
        timeInFreq.setValues(new long[]{100, 200, 300, 400});
        long[] timeInFreq = {100, 200, 300, 400};
        while (state.keepRunning()) {
            counter.setState(1, time);
            counter.setState(0, time + 1000);
+1 −1
Original line number Diff line number Diff line
@@ -1315,7 +1315,7 @@ public final class BatteryUsageStats implements Parcelable, Closeable {
        }

        synchronized (BatteryUsageStats.class) {
            if (!sInstances.isEmpty()) {
            if (sInstances != null && !sInstances.isEmpty()) {
                Exception callSite = sInstances.entrySet().iterator().next().getValue();
                int count = sInstances.size();
                sInstances.clear();
+9 −12
Original line number Diff line number Diff line
@@ -18,14 +18,13 @@ package com.android.internal.os;
import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.util.Slog;
import android.util.SparseArray;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;

import dalvik.annotation.optimization.CriticalNative;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
@@ -255,8 +254,8 @@ public class KernelSingleUidTimeReader {
     * the delta in the supplied array container.
     */
    public void addDelta(int uid, LongArrayMultiStateCounter counter, long timestampMs,
            LongArrayMultiStateCounter.LongArrayContainer deltaContainer) {
        mInjector.addDelta(uid, counter, timestampMs, deltaContainer);
            long[] delta) {
        mInjector.addDelta(uid, counter, timestampMs, delta);
    }

    @VisibleForTesting
@@ -274,15 +273,13 @@ public class KernelSingleUidTimeReader {
         * The delta is also returned via the optional deltaOut parameter.
         */
        public boolean addDelta(int uid, LongArrayMultiStateCounter counter, long timestampMs,
                LongArrayMultiStateCounter.LongArrayContainer deltaOut) {
            return addDeltaFromBpf(uid, counter.mNativeObject, timestampMs,
                    deltaOut != null ? deltaOut.mNativeObject : 0);
                long[] deltaOut) {
            return addDeltaFromBpf(uid, counter.mNativeObject, timestampMs, deltaOut);
        }

        @CriticalNative
        private static native boolean addDeltaFromBpf(int uid,
                long longArrayMultiStateCounterNativePointer, long timestampMs,
                long longArrayContainerNativePointer);
                @Nullable long[] deltaOut);

        /**
         * Used for testing.
@@ -291,14 +288,14 @@ public class KernelSingleUidTimeReader {
         */
        public boolean addDeltaForTest(int uid, LongArrayMultiStateCounter counter,
                long timestampMs, long[][] timeInFreqDataNanos,
                LongArrayMultiStateCounter.LongArrayContainer deltaOut) {
                long[] deltaOut) {
            return addDeltaForTest(uid, counter.mNativeObject, timestampMs, timeInFreqDataNanos,
                    deltaOut != null ? deltaOut.mNativeObject : 0);
                    deltaOut);
        }

        private static native boolean addDeltaForTest(int uid,
                long longArrayMultiStateCounterNativePointer, long timestampMs,
                long[][] timeInFreqDataNanos, long longArrayContainerNativePointer);
                long[][] timeInFreqDataNanos, long[] deltaOut);
    }

    @VisibleForTesting
+40 −193
Original line number Diff line number Diff line
@@ -30,9 +30,6 @@ import dalvik.annotation.optimization.FastNative;

import libcore.util.NativeAllocationRegistry;

import java.util.Arrays;
import java.util.concurrent.atomic.AtomicReference;

/**
 * Performs per-state counting of multi-element values over time. The class' behavior is illustrated
 * by this example:
@@ -44,15 +41,14 @@ import java.util.concurrent.atomic.AtomicReference;
 *   counter.setState(1, 1000);
 *
 *   // At 3000 ms, the tracked values are updated to {30, 300}
 *   arrayContainer.setValues(new long[]{{30, 300}};
 *   counter.updateValues(arrayContainer, 3000);
 *   counter.updateValues(arrayContainer, new long[]{{30, 300}, 3000);
 *
 *   // The values are distributed between states 0 and 1 according to the time
 *   // spent in those respective states. In this specific case, 1000 and 2000 ms.
 *   counter.getValues(arrayContainer, 0);
 *   // arrayContainer now has values {10, 100}
 *   counter.getValues(arrayContainer, 1);
 *   // arrayContainer now has values {20, 200}
 *   counter.getCounts(array, 0);
 *   // array now has values {10, 100}
 *   counter.getCounts(array, 1);
 *   // array now has values {20, 200}
 * </pre>
 *
 * The tracked values are expected to increase monotonically.
@@ -62,110 +58,7 @@ import java.util.concurrent.atomic.AtomicReference;
@RavenwoodKeepWholeClass
@RavenwoodRedirectionClass("LongArrayMultiStateCounter_host")
public final class LongArrayMultiStateCounter implements Parcelable {

    /**
     * Container for a native equivalent of a long[].
     */
    @RavenwoodKeepWholeClass
    @RavenwoodRedirectionClass("LongArrayContainer_host")
    public static class LongArrayContainer {
        private static NativeAllocationRegistry sRegistry;

        // Visible to other objects in this package so that it can be passed to @CriticalNative
        // methods.
        final long mNativeObject;
        private final int mLength;

        public LongArrayContainer(int length) {
            mLength = length;
            mNativeObject = native_init(length);
            registerNativeAllocation();
        }

        @RavenwoodReplace
        private void registerNativeAllocation() {
            if (sRegistry == null) {
                synchronized (LongArrayMultiStateCounter.class) {
                    if (sRegistry == null) {
                        sRegistry = NativeAllocationRegistry.createMalloced(
                                LongArrayContainer.class.getClassLoader(), native_getReleaseFunc());
                    }
                }
            }
            sRegistry.registerNativeAllocation(this, mNativeObject);
        }

        private void registerNativeAllocation$ravenwood() {
            // No-op under ravenwood
        }

        /**
         * Copies the supplied values into the underlying native array.
         */
        public void setValues(long[] array) {
            if (array.length != mLength) {
                throw new IllegalArgumentException(
                        "Invalid array length: " + array.length + ", expected: " + mLength);
            }
            native_setValues(mNativeObject, array);
        }

        /**
         * Copies the underlying native array values to the supplied array.
         */
        public void getValues(long[] array) {
            if (array.length != mLength) {
                throw new IllegalArgumentException(
                        "Invalid array length: " + array.length + ", expected: " + mLength);
            }
            native_getValues(mNativeObject, array);
        }

        /**
         * Combines contained values into a smaller array by aggregating them
         * according to an index map.
         */
        public boolean combineValues(long[] array, int[] indexMap) {
            if (indexMap.length != mLength) {
                throw new IllegalArgumentException(
                        "Wrong index map size " + indexMap.length + ", expected " + mLength);
            }
            return native_combineValues(mNativeObject, array, indexMap);
        }

        @Override
        public String toString() {
            final long[] array = new long[mLength];
            getValues(array);
            return Arrays.toString(array);
        }

        @CriticalNative
        @RavenwoodRedirect
        private static native long native_init(int length);

        @CriticalNative
        @RavenwoodRedirect
        private static native long native_getReleaseFunc();

        @FastNative
        @RavenwoodRedirect
        private static native void native_setValues(long nativeObject, long[] array);

        @FastNative
        @RavenwoodRedirect
        private static native void native_getValues(long nativeObject, long[] array);

        @FastNative
        @RavenwoodRedirect
        private static native boolean native_combineValues(long nativeObject, long[] array,
                int[] indexMap);
    }

    private static volatile NativeAllocationRegistry sRegistry;
    private static final AtomicReference<LongArrayContainer> sTmpArrayContainer =
            new AtomicReference<>();

    private final int mStateCount;
    private final int mLength;

@@ -257,41 +150,14 @@ public final class LongArrayMultiStateCounter implements Parcelable {
            throw new IllegalArgumentException(
                    "Invalid array length: " + values.length + ", expected: " + mLength);
        }
        LongArrayContainer container = sTmpArrayContainer.getAndSet(null);
        if (container == null || container.mLength != values.length) {
            container = new LongArrayContainer(values.length);
        }
        container.setValues(values);
        native_setValues(mNativeObject, state, container.mNativeObject);
        sTmpArrayContainer.set(container);
    }

    /**
     * Sets the new values.  The delta between the previously set values and these values
     * is distributed among the state according to the time the object spent in those states
     * since the previous call to updateValues.
     */
    public void updateValues(long[] values, long timestampMs) {
        LongArrayContainer container = sTmpArrayContainer.getAndSet(null);
        if (container == null || container.mLength != values.length) {
            container = new LongArrayContainer(values.length);
        }
        container.setValues(values);
        updateValues(container, timestampMs);
        sTmpArrayContainer.set(container);
        native_setValues(mNativeObject, state, values);
    }

    /**
     * Adds the supplied values to the current accumulated values in the counter.
     */
    public void incrementValues(long[] values, long timestampMs) {
        LongArrayContainer container = sTmpArrayContainer.getAndSet(null);
        if (container == null || container.mLength != values.length) {
            container = new LongArrayContainer(values.length);
        }
        container.setValues(values);
        native_incrementValues(mNativeObject, container.mNativeObject, timestampMs);
        sTmpArrayContainer.set(container);
        native_incrementValues(mNativeObject, values, timestampMs);
    }

    /**
@@ -299,24 +165,23 @@ public final class LongArrayMultiStateCounter implements Parcelable {
     * is distributed among the state according to the time the object spent in those states
     * since the previous call to updateValues.
     */
    public void updateValues(LongArrayContainer longArrayContainer, long timestampMs) {
        if (longArrayContainer.mLength != mLength) {
    public void updateValues(long[] values, long timestampMs) {
        if (values.length != mLength) {
            throw new IllegalArgumentException(
                    "Invalid array length: " + longArrayContainer.mLength + ", expected: "
                            + mLength);
                    "Invalid array length: " + values.length + ", expected: " + mLength);
        }
        native_updateValues(mNativeObject, longArrayContainer.mNativeObject, timestampMs);
        native_updateValues(mNativeObject, values, timestampMs);
    }

    /**
     * Adds the supplied values to the current accumulated values in the counter.
     */
    public void addCounts(LongArrayContainer counts) {
        if (counts.mLength != mLength) {
    public void addCounts(long[] counts) {
        if (counts.length != mLength) {
            throw new IllegalArgumentException(
                    "Invalid array length: " + counts.mLength + ", expected: " + mLength);
                    "Invalid array length: " + counts.length + ", expected: " + mLength);
        }
        native_addCounts(mNativeObject, counts.mNativeObject);
        native_addCounts(mNativeObject, counts);
    }

    /**
@@ -330,29 +195,15 @@ public final class LongArrayMultiStateCounter implements Parcelable {
     * Populates the array with the accumulated counts for the specified state.
     */
    public void getCounts(long[] counts, int state) {
        LongArrayContainer container = sTmpArrayContainer.getAndSet(null);
        if (container == null || container.mLength != counts.length) {
            container = new LongArrayContainer(counts.length);
        }
        getCounts(container, state);
        container.getValues(counts);
        sTmpArrayContainer.set(container);
    }

    /**
     * Populates longArrayContainer with the accumulated counts for the specified state.
     */
    public void getCounts(LongArrayContainer longArrayContainer, int state) {
        if (state < 0 || state >= mStateCount) {
            throw new IllegalArgumentException(
                    "State: " + state + ", outside the range: [0-" + mStateCount + "]");
        }
        if (longArrayContainer.mLength != mLength) {
        if (counts.length != mLength) {
            throw new IllegalArgumentException(
                    "Invalid array length: " + longArrayContainer.mLength
                            + ", expected: " + mLength);
                    "Invalid array length: " + counts.length + ", expected: " + mLength);
        }
        native_getCounts(mNativeObject, longArrayContainer.mNativeObject, state);
        native_getCounts(mNativeObject, counts, state);
    }

    @Override
@@ -370,8 +221,7 @@ public final class LongArrayMultiStateCounter implements Parcelable {
        return 0;
    }

    public static final Creator<LongArrayMultiStateCounter> CREATOR =
            new Creator<LongArrayMultiStateCounter>() {
    public static final Creator<LongArrayMultiStateCounter> CREATOR = new Creator<>() {
        @Override
        public LongArrayMultiStateCounter createFromParcel(Parcel in) {
            return new LongArrayMultiStateCounter(in);
@@ -406,34 +256,31 @@ public final class LongArrayMultiStateCounter implements Parcelable {
    private static native void native_copyStatesFrom(long nativeObjectTarget,
            long nativeObjectSource);

    @CriticalNative
    @FastNative
    @RavenwoodRedirect
    private static native void native_setValues(long nativeObject, int state,
            long longArrayContainerNativeObject);
    private static native void native_setValues(long nativeObject, int state, long[] values);

    @CriticalNative
    @FastNative
    @RavenwoodRedirect
    private static native void native_updateValues(long nativeObject,
            long longArrayContainerNativeObject, long timestampMs);
    private static native void native_updateValues(long nativeObject, long[] values,
            long timestampMs);

    @CriticalNative
    @FastNative
    @RavenwoodRedirect
    private static native void native_incrementValues(long nativeObject,
            long longArrayContainerNativeObject, long timestampMs);
    private static native void native_incrementValues(long nativeObject, long[] values,
            long timestampMs);

    @CriticalNative
    @FastNative
    @RavenwoodRedirect
    private static native void native_addCounts(long nativeObject,
            long longArrayContainerNativeObject);
    private static native void native_addCounts(long nativeObject, long[] counts);

    @CriticalNative
    @RavenwoodRedirect
    private static native void native_reset(long nativeObject);

    @CriticalNative
    @FastNative
    @RavenwoodRedirect
    private static native void native_getCounts(long nativeObject,
            long longArrayContainerNativeObject, int state);
    private static native void native_getCounts(long nativeObject, long[] counts, int state);

    @FastNative
    @RavenwoodRedirect
+28 −28
Original line number Diff line number Diff line
@@ -49,27 +49,26 @@ static jlongArray getUidCpuFreqTimeMs(JNIEnv *env, jclass, jint uid) {
 * to the supplied multi-state counter in accordance with the counter's state.
 */
static jboolean addCpuTimeInFreqDelta(
        jint uid, jlong counterNativePtr, jlong timestampMs,
        JNIEnv *env, jint uid, jlong counterNativePtr, jlong timestampMs,
        std::optional<std::vector<std::vector<uint64_t>>> timeInFreqDataNanos,
        jlong deltaOutContainerNativePtr) {
        jlongArray deltaOut) {
    if (!timeInFreqDataNanos) {
        return false;
    }

    battery::LongArrayMultiStateCounter *counter =
            reinterpret_cast<battery::LongArrayMultiStateCounter *>(counterNativePtr);
    auto counter = reinterpret_cast<battery::LongArrayMultiStateCounter *>(counterNativePtr);
    size_t s = 0;
    for (const auto &cluster : *timeInFreqDataNanos) s += cluster.size();

    std::vector<uint64_t> flattened;
    flattened.reserve(s);
    auto offset = flattened.begin();
    battery::Uint64ArrayRW flattened(s);
    uint64_t *out = flattened.dataRW();
    auto offset = out;
    for (const auto &cluster : *timeInFreqDataNanos) {
        flattened.insert(offset, cluster.begin(), cluster.end());
        memcpy(offset, cluster.data(), cluster.size() * sizeof(uint64_t));
        offset += cluster.size();
    }
    for (size_t i = 0; i < s; ++i) {
        flattened[i] /= NSEC_PER_MSEC;
        out[i] /= NSEC_PER_MSEC;
    }
    if (s != counter->getCount(0).size()) { // Counter has at least one state
        ALOGE("Mismatch between eBPF data size (%d) and the counter size (%d)", (int)s,
@@ -77,29 +76,32 @@ static jboolean addCpuTimeInFreqDelta(
        return false;
    }

    const std::vector<uint64_t> &delta = counter->updateValue(flattened, timestampMs);
    if (deltaOutContainerNativePtr) {
        std::vector<uint64_t> *vector =
                reinterpret_cast<std::vector<uint64_t> *>(deltaOutContainerNativePtr);
        *vector = delta;
    const battery::Uint64Array &delta = counter->updateValue(flattened, timestampMs);
    if (deltaOut) {
        ScopedLongArrayRW scopedArray(env, deltaOut);
        uint64_t *array = reinterpret_cast<uint64_t *>(scopedArray.get());
        if (delta.data() != nullptr) {
            memcpy(array, delta.data(), s * sizeof(uint64_t));
        } else {
            memset(array, 0, s * sizeof(uint64_t));
        }
    }

    return true;
}

static jboolean addDeltaFromBpf(jint uid, jlong counterNativePtr, jlong timestampMs,
                                jlong deltaOutContainerNativePtr) {
    return addCpuTimeInFreqDelta(uid, counterNativePtr, timestampMs,
                                 android::bpf::getUidCpuFreqTimes(uid), deltaOutContainerNativePtr);
static jboolean addDeltaFromBpf(JNIEnv *env, jlong self, jint uid, jlong counterNativePtr,
                                jlong timestampMs, jlongArray deltaOut) {
    return addCpuTimeInFreqDelta(env, uid, counterNativePtr, timestampMs,
                                 android::bpf::getUidCpuFreqTimes(uid), deltaOut);
}

static jboolean addDeltaForTest(JNIEnv *env, jclass, jint uid, jlong counterNativePtr,
                                jlong timestampMs, jobjectArray timeInFreqDataNanos,
                                jlong deltaOutContainerNativePtr) {
                                jlongArray deltaOut) {
    if (!timeInFreqDataNanos) {
        return addCpuTimeInFreqDelta(uid, counterNativePtr, timestampMs,
                                     std::optional<std::vector<std::vector<uint64_t>>>(),
                                     deltaOutContainerNativePtr);
        return addCpuTimeInFreqDelta(env, uid, counterNativePtr, timestampMs,
                                     std::optional<std::vector<std::vector<uint64_t>>>(), deltaOut);
    }

    std::vector<std::vector<uint64_t>> timeInFreqData;
@@ -113,18 +115,16 @@ static jboolean addDeltaForTest(JNIEnv *env, jclass, jint uid, jlong counterNati
        }
        timeInFreqData.push_back(cluster);
    }
    return addCpuTimeInFreqDelta(uid, counterNativePtr, timestampMs, std::optional(timeInFreqData),
                                 deltaOutContainerNativePtr);
    return addCpuTimeInFreqDelta(env, uid, counterNativePtr, timestampMs,
                                 std::optional(timeInFreqData), deltaOut);
}

static const JNINativeMethod g_single_methods[] = {
        {"readBpfData", "(I)[J", (void *)getUidCpuFreqTimeMs},

        // @CriticalNative
        {"addDeltaFromBpf", "(IJJJ)Z", (void *)addDeltaFromBpf},
        {"addDeltaFromBpf", "(IJJ[J)Z", (void *)addDeltaFromBpf},

        // Used for testing
        {"addDeltaForTest", "(IJJ[[JJ)Z", (void *)addDeltaForTest},
        {"addDeltaForTest", "(IJJ[[J[J)Z", (void *)addDeltaForTest},
};

int register_com_android_internal_os_KernelSingleUidTimeReader(JNIEnv *env) {
Loading