Make LongArrayMultiStateCounter parcelable
Bug: 197162116
Test: atest FrameworksCoreTests:LongArrayMultiStateCounterTest
atest CorePerfTests:LongArrayMultiStateCounterPerfTest
Change-Id: Ibc94620f2f106695fa7f17fc0737496f0e32ba48
This commit is contained in:
@@ -37,15 +37,15 @@ public class LongArrayMultiStateCounterPerfTest {
|
||||
|
||||
/**
|
||||
* A complete line-for-line reimplementation of
|
||||
* {@link }com.android.internal.os.CpuTimeInFreqMultiStateCounter}, only in Java instead of
|
||||
* {@link com.android.internal.os.LongArrayMultiStateCounter}, only in Java instead of
|
||||
* native.
|
||||
*/
|
||||
private static class TestLongArrayMultiStateCounter {
|
||||
private final int mStateCount;
|
||||
private final int mArrayLength;
|
||||
private int mCurrentState;
|
||||
private long mLastStateChangeTimestampMs;
|
||||
private long mLastUpdateTimestampMs;
|
||||
private long mLastStateChangeTimestampMs = -1;
|
||||
private long mLastUpdateTimestampMs = -1;
|
||||
|
||||
private static class State {
|
||||
private long mTimeInStateSinceUpdate;
|
||||
@@ -56,13 +56,9 @@ public class LongArrayMultiStateCounterPerfTest {
|
||||
private final long[] mLastTimeInFreq;
|
||||
private final long[] mDelta;
|
||||
|
||||
TestLongArrayMultiStateCounter(int stateCount, int arrayLength, int initialState,
|
||||
long timestampMs) {
|
||||
TestLongArrayMultiStateCounter(int stateCount, int arrayLength) {
|
||||
mStateCount = stateCount;
|
||||
mArrayLength = arrayLength;
|
||||
mCurrentState = initialState;
|
||||
mLastStateChangeTimestampMs = timestampMs;
|
||||
mLastUpdateTimestampMs = timestampMs;
|
||||
mStates = new State[stateCount];
|
||||
for (int i = 0; i < mStateCount; i++) {
|
||||
mStates[i] = new State();
|
||||
@@ -73,12 +69,14 @@ public class LongArrayMultiStateCounterPerfTest {
|
||||
}
|
||||
|
||||
public void setState(int state, long timestampMs) {
|
||||
if (timestampMs >= mLastStateChangeTimestampMs) {
|
||||
mStates[mCurrentState].mTimeInStateSinceUpdate +=
|
||||
timestampMs - mLastStateChangeTimestampMs;
|
||||
} else {
|
||||
for (int i = 0; i < mStateCount; i++) {
|
||||
mStates[i].mTimeInStateSinceUpdate = 0;
|
||||
if (mLastStateChangeTimestampMs > 0) {
|
||||
if (timestampMs >= mLastStateChangeTimestampMs) {
|
||||
mStates[mCurrentState].mTimeInStateSinceUpdate +=
|
||||
timestampMs - mLastStateChangeTimestampMs;
|
||||
} else {
|
||||
for (int i = 0; i < mStateCount; i++) {
|
||||
mStates[i].mTimeInStateSinceUpdate = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
mCurrentState = state;
|
||||
@@ -88,21 +86,23 @@ public class LongArrayMultiStateCounterPerfTest {
|
||||
public void updateValue(long[] timeInFreq, long timestampMs) {
|
||||
setState(mCurrentState, timestampMs);
|
||||
|
||||
if (timestampMs > mLastUpdateTimestampMs) {
|
||||
if (delta(mLastTimeInFreq, timeInFreq, mDelta)) {
|
||||
long timeSinceUpdate = timestampMs - mLastUpdateTimestampMs;
|
||||
for (int i = 0; i < mStateCount; i++) {
|
||||
long timeInState = mStates[i].mTimeInStateSinceUpdate;
|
||||
if (timeInState > 0) {
|
||||
add(mStates[i].mCounter, mDelta, timeInState, timeSinceUpdate);
|
||||
mStates[i].mTimeInStateSinceUpdate = 0;
|
||||
if (mLastUpdateTimestampMs >= 0) {
|
||||
if (timestampMs > mLastUpdateTimestampMs) {
|
||||
if (delta(mLastTimeInFreq, timeInFreq, mDelta)) {
|
||||
long timeSinceUpdate = timestampMs - mLastUpdateTimestampMs;
|
||||
for (int i = 0; i < mStateCount; i++) {
|
||||
long timeInState = mStates[i].mTimeInStateSinceUpdate;
|
||||
if (timeInState > 0) {
|
||||
add(mStates[i].mCounter, mDelta, timeInState, timeSinceUpdate);
|
||||
mStates[i].mTimeInStateSinceUpdate = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
} else {
|
||||
} else if (timestampMs < mLastUpdateTimestampMs) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
} else if (timestampMs < mLastUpdateTimestampMs) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
System.arraycopy(timeInFreq, 0, mLastTimeInFreq, 0, mArrayLength);
|
||||
mLastUpdateTimestampMs = timestampMs;
|
||||
@@ -142,7 +142,7 @@ public class LongArrayMultiStateCounterPerfTest {
|
||||
@Test
|
||||
public void javaImplementation() {
|
||||
TestLongArrayMultiStateCounter counter =
|
||||
new TestLongArrayMultiStateCounter(2, 4, 0, 1000);
|
||||
new TestLongArrayMultiStateCounter(2, 4);
|
||||
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
|
||||
long time = 1000;
|
||||
long[] timeInFreq = {100, 200, 300, 400};
|
||||
@@ -156,7 +156,7 @@ public class LongArrayMultiStateCounterPerfTest {
|
||||
|
||||
@Test
|
||||
public void nativeImplementation() {
|
||||
LongArrayMultiStateCounter counter = new LongArrayMultiStateCounter(2, 4, 0, 1000);
|
||||
LongArrayMultiStateCounter counter = new LongArrayMultiStateCounter(2, 4);
|
||||
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
|
||||
long time = 1000;
|
||||
LongArrayMultiStateCounter.LongArrayContainer timeInFreq =
|
||||
|
||||
@@ -16,6 +16,11 @@
|
||||
|
||||
package com.android.internal.os;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import com.android.internal.util.Preconditions;
|
||||
|
||||
import dalvik.annotation.optimization.CriticalNative;
|
||||
import dalvik.annotation.optimization.FastNative;
|
||||
|
||||
@@ -47,7 +52,7 @@ import libcore.util.NativeAllocationRegistry;
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class LongArrayMultiStateCounter {
|
||||
public final class LongArrayMultiStateCounter implements Parcelable {
|
||||
|
||||
/**
|
||||
* Container for a native equivalent of a long[].
|
||||
@@ -112,14 +117,22 @@ public class LongArrayMultiStateCounter {
|
||||
// methods.
|
||||
final long mNativeObject;
|
||||
|
||||
public LongArrayMultiStateCounter(int stateCount, int arrayLength, int initialState,
|
||||
long timestampMs) {
|
||||
public LongArrayMultiStateCounter(int stateCount, int arrayLength) {
|
||||
Preconditions.checkArgumentPositive(stateCount, "stateCount must be greater than 0");
|
||||
mStateCount = stateCount;
|
||||
mLength = arrayLength;
|
||||
mNativeObject = native_init(stateCount, arrayLength, initialState, timestampMs);
|
||||
mNativeObject = native_init(stateCount, arrayLength);
|
||||
sRegistry.registerNativeAllocation(this, mNativeObject);
|
||||
}
|
||||
|
||||
private LongArrayMultiStateCounter(Parcel in) {
|
||||
mNativeObject = native_initFromParcel(in);
|
||||
sRegistry.registerNativeAllocation(this, mNativeObject);
|
||||
|
||||
mStateCount = native_getStateCount(mNativeObject);
|
||||
mLength = native_getArrayLength(mNativeObject);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current state to the supplied value.
|
||||
*/
|
||||
@@ -161,9 +174,32 @@ public class LongArrayMultiStateCounter {
|
||||
return native_toString(mNativeObject);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
native_writeToParcel(mNativeObject, dest, flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static final Creator<LongArrayMultiStateCounter> CREATOR =
|
||||
new Creator<LongArrayMultiStateCounter>() {
|
||||
@Override
|
||||
public LongArrayMultiStateCounter createFromParcel(Parcel in) {
|
||||
return new LongArrayMultiStateCounter(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LongArrayMultiStateCounter[] newArray(int size) {
|
||||
return new LongArrayMultiStateCounter[size];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@CriticalNative
|
||||
private static native long native_init(int stateCount, int arrayLength, int initialState,
|
||||
long timestampMs);
|
||||
private static native long native_init(int stateCount, int arrayLength);
|
||||
|
||||
@CriticalNative
|
||||
private static native long native_getReleaseFunc();
|
||||
@@ -181,4 +217,16 @@ public class LongArrayMultiStateCounter {
|
||||
|
||||
@FastNative
|
||||
private native String native_toString(long nativeObject);
|
||||
|
||||
@FastNative
|
||||
private native void native_writeToParcel(long nativeObject, Parcel dest, int flags);
|
||||
|
||||
@FastNative
|
||||
private static native long native_initFromParcel(Parcel parcel);
|
||||
|
||||
@CriticalNative
|
||||
private static native int native_getStateCount(long nativeObject);
|
||||
|
||||
@CriticalNative
|
||||
private static native int native_getArrayLength(long nativeObject);
|
||||
}
|
||||
|
||||
@@ -263,6 +263,7 @@ cc_library_shared {
|
||||
"libdebuggerd_client",
|
||||
"libutils",
|
||||
"libbinder",
|
||||
"libbinder_ndk",
|
||||
"libui",
|
||||
"libgraphicsenv",
|
||||
"libgui",
|
||||
|
||||
@@ -14,17 +14,22 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <android/binder_parcel.h>
|
||||
#include <android/binder_parcel_jni.h>
|
||||
#include <android/binder_parcel_utils.h>
|
||||
#include <android_runtime/Log.h>
|
||||
#include <nativehelper/ScopedPrimitiveArray.h>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "LongArrayMultiStateCounter.h"
|
||||
#include "core_jni_helpers.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
static jlong native_init(jint stateCount, jint arrayLength, jint initialState, jlong timestamp) {
|
||||
static jlong native_init(jint stateCount, jint arrayLength) {
|
||||
battery::LongArrayMultiStateCounter *counter =
|
||||
new battery::LongArrayMultiStateCounter(stateCount, initialState,
|
||||
std::vector<uint64_t>(arrayLength), timestamp);
|
||||
new battery::LongArrayMultiStateCounter(stateCount, std::vector<uint64_t>(arrayLength));
|
||||
return reinterpret_cast<jlong>(counter);
|
||||
}
|
||||
|
||||
@@ -69,13 +74,95 @@ static jobject native_toString(JNIEnv *env, jobject self, jlong nativePtr) {
|
||||
return env->NewStringUTF(counter->toString().c_str());
|
||||
}
|
||||
|
||||
static void throwWriteRE(JNIEnv *env, binder_status_t status) {
|
||||
ALOGE("Could not write LongArrayMultiStateCounter to Parcel, status = %d", status);
|
||||
jniThrowRuntimeException(env, "Could not write LongArrayMultiStateCounter to Parcel");
|
||||
}
|
||||
|
||||
#define THROW_ON_WRITE_ERROR(expr) \
|
||||
{ \
|
||||
binder_status_t status = expr; \
|
||||
if (status != STATUS_OK) { \
|
||||
throwWriteRE(env, status); \
|
||||
} \
|
||||
}
|
||||
|
||||
static void native_writeToParcel(JNIEnv *env, jobject self, jlong nativePtr, jobject jParcel,
|
||||
jint flags) {
|
||||
battery::LongArrayMultiStateCounter *counter =
|
||||
reinterpret_cast<battery::LongArrayMultiStateCounter *>(nativePtr);
|
||||
AParcel *parcel = AParcel_fromJavaParcel(env, jParcel);
|
||||
|
||||
uint16_t stateCount = counter->getStateCount();
|
||||
THROW_ON_WRITE_ERROR(AParcel_writeInt32(parcel, stateCount));
|
||||
|
||||
// LongArrayMultiStateCounter has at least state 0
|
||||
const std::vector<uint64_t> &anyState = counter->getCount(0);
|
||||
THROW_ON_WRITE_ERROR(AParcel_writeInt32(parcel, anyState.size()));
|
||||
|
||||
for (battery::state_t state = 0; state < stateCount; state++) {
|
||||
THROW_ON_WRITE_ERROR(ndk::AParcel_writeVector(parcel, counter->getCount(state)));
|
||||
}
|
||||
}
|
||||
|
||||
static void throwReadRE(JNIEnv *env, binder_status_t status) {
|
||||
ALOGE("Could not read LongArrayMultiStateCounter from Parcel, status = %d", status);
|
||||
jniThrowRuntimeException(env, "Could not read LongArrayMultiStateCounter from Parcel");
|
||||
}
|
||||
|
||||
#define THROW_ON_READ_ERROR(expr) \
|
||||
{ \
|
||||
binder_status_t status = expr; \
|
||||
if (status != STATUS_OK) { \
|
||||
throwReadRE(env, status); \
|
||||
} \
|
||||
}
|
||||
|
||||
static jlong native_initFromParcel(JNIEnv *env, jclass theClass, jobject jParcel) {
|
||||
AParcel *parcel = AParcel_fromJavaParcel(env, jParcel);
|
||||
|
||||
int32_t stateCount;
|
||||
THROW_ON_READ_ERROR(AParcel_readInt32(parcel, &stateCount));
|
||||
|
||||
int32_t arrayLength;
|
||||
THROW_ON_READ_ERROR(AParcel_readInt32(parcel, &arrayLength));
|
||||
|
||||
battery::LongArrayMultiStateCounter *counter =
|
||||
new battery::LongArrayMultiStateCounter(stateCount, std::vector<uint64_t>(arrayLength));
|
||||
|
||||
std::vector<uint64_t> value;
|
||||
value.reserve(arrayLength);
|
||||
|
||||
for (battery::state_t state = 0; state < stateCount; state++) {
|
||||
THROW_ON_READ_ERROR(ndk::AParcel_readVector(parcel, &value));
|
||||
counter->setValue(state, value);
|
||||
}
|
||||
|
||||
return reinterpret_cast<jlong>(counter);
|
||||
}
|
||||
|
||||
static jint native_getStateCount(jlong nativePtr) {
|
||||
battery::LongArrayMultiStateCounter *counter =
|
||||
reinterpret_cast<battery::LongArrayMultiStateCounter *>(nativePtr);
|
||||
return counter->getStateCount();
|
||||
}
|
||||
|
||||
static jint native_getArrayLength(jlong nativePtr) {
|
||||
battery::LongArrayMultiStateCounter *counter =
|
||||
reinterpret_cast<battery::LongArrayMultiStateCounter *>(nativePtr);
|
||||
|
||||
// LongArrayMultiStateCounter has at least state 0
|
||||
const std::vector<uint64_t> &anyState = counter->getCount(0);
|
||||
return anyState.size();
|
||||
}
|
||||
|
||||
static jlong native_init_LongArrayContainer(jint length) {
|
||||
return reinterpret_cast<jlong>(new std::vector<uint64_t>(length));
|
||||
}
|
||||
|
||||
static const JNINativeMethod g_LongArrayMultiStateCounter_methods[] = {
|
||||
// @CriticalNative
|
||||
{"native_init", "(IIIJ)J", (void *)native_init},
|
||||
{"native_init", "(II)J", (void *)native_init},
|
||||
// @CriticalNative
|
||||
{"native_getReleaseFunc", "()J", (void *)native_getReleaseFunc},
|
||||
// @CriticalNative
|
||||
@@ -86,6 +173,14 @@ static const JNINativeMethod g_LongArrayMultiStateCounter_methods[] = {
|
||||
{"native_getCounts", "(JJI)V", (void *)native_getCounts},
|
||||
// @FastNative
|
||||
{"native_toString", "(J)Ljava/lang/String;", (void *)native_toString},
|
||||
// @FastNative
|
||||
{"native_writeToParcel", "(JLandroid/os/Parcel;I)V", (void *)native_writeToParcel},
|
||||
// @FastNative
|
||||
{"native_initFromParcel", "(Landroid/os/Parcel;)J", (void *)native_initFromParcel},
|
||||
// @CriticalNative
|
||||
{"native_getStateCount", "(J)I", (void *)native_getStateCount},
|
||||
// @CriticalNative
|
||||
{"native_getArrayLength", "(J)I", (void *)native_getArrayLength},
|
||||
};
|
||||
|
||||
/////////////////////// LongArrayMultiStateCounter.LongArrayContainer ////////////////////////
|
||||
|
||||
@@ -282,7 +282,11 @@ public class KernelSingleUidTimeReaderTest {
|
||||
|
||||
@Test
|
||||
public void testAddDeltaFromBpf() {
|
||||
LongArrayMultiStateCounter counter = new LongArrayMultiStateCounter(2, 5, 0, 0);
|
||||
LongArrayMultiStateCounter counter = new LongArrayMultiStateCounter(2, 5);
|
||||
counter.setState(0, 0);
|
||||
mInjector.setCpuTimeInStatePerClusterNs(new long[][]{{0, 0, 0}, {0, 0}});
|
||||
boolean success = mInjector.addDelta(TEST_UID, counter, 0);
|
||||
assertThat(success).isTrue();
|
||||
|
||||
// Nanoseconds
|
||||
mInjector.setCpuTimeInStatePerClusterNs(
|
||||
@@ -290,7 +294,7 @@ public class KernelSingleUidTimeReaderTest {
|
||||
{1_000_000, 2_000_000, 3_000_000},
|
||||
{4_000_000, 5_000_000}});
|
||||
|
||||
boolean success = mInjector.addDelta(TEST_UID, counter, 2000);
|
||||
success = mInjector.addDelta(TEST_UID, counter, 2000);
|
||||
assertThat(success).isTrue();
|
||||
|
||||
LongArrayMultiStateCounter.LongArrayContainer array =
|
||||
|
||||
@@ -18,6 +18,8 @@ package com.android.internal.os;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.os.Parcel;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
@@ -30,26 +32,74 @@ public class LongArrayMultiStateCounterTest {
|
||||
|
||||
@Test
|
||||
public void setStateAndUpdateValue() {
|
||||
LongArrayMultiStateCounter.LongArrayContainer longArrayContainer =
|
||||
new LongArrayMultiStateCounter.LongArrayContainer(4);
|
||||
LongArrayMultiStateCounter counter = new LongArrayMultiStateCounter(2, 4, 0, 1000);
|
||||
LongArrayMultiStateCounter counter = new LongArrayMultiStateCounter(2, 4);
|
||||
|
||||
updateValue(counter, new long[]{0, 0, 0, 0}, 1000);
|
||||
counter.setState(0, 1000);
|
||||
counter.setState(1, 2000);
|
||||
counter.setState(0, 4000);
|
||||
longArrayContainer.setValues(new long[]{100, 200, 300, 400});
|
||||
counter.updateValues(longArrayContainer, 9000);
|
||||
counter.getCounts(longArrayContainer, 0);
|
||||
updateValue(counter, new long[]{100, 200, 300, 400}, 9000);
|
||||
|
||||
long[] result = new long[4];
|
||||
longArrayContainer.getValues(result);
|
||||
assertThat(result).isEqualTo(new long[]{75, 150, 225, 300});
|
||||
|
||||
counter.getCounts(longArrayContainer, 1);
|
||||
longArrayContainer.getValues(result);
|
||||
assertThat(result).isEqualTo(new long[]{25, 50, 75, 100});
|
||||
assertCounts(counter, 0, new long[]{75, 150, 225, 300});
|
||||
assertCounts(counter, 1, new long[]{25, 50, 75, 100});
|
||||
|
||||
assertThat(counter.toString()).isEqualTo(
|
||||
"currentState: 0 lastStateChangeTimestamp: 9000 lastUpdateTimestamp: 9000 states:"
|
||||
+ " [0: time: 0 counter: { 75, 150, 225, 300}"
|
||||
+ ", 1: time: 0 counter: { 25, 50, 75, 100}]");
|
||||
"[0: {75, 150, 225, 300}, 1: {25, 50, 75, 100}] updated: 9000 currentState: 0");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parceling() {
|
||||
LongArrayMultiStateCounter counter = new LongArrayMultiStateCounter(2, 4);
|
||||
updateValue(counter, new long[]{0, 0, 0, 0}, 1000);
|
||||
counter.setState(0, 1000);
|
||||
updateValue(counter, new long[]{100, 200, 300, 400}, 2000);
|
||||
counter.setState(1, 2000);
|
||||
updateValue(counter, new long[]{101, 202, 304, 408}, 3000);
|
||||
|
||||
assertCounts(counter, 0, new long[]{100, 200, 300, 400});
|
||||
assertCounts(counter, 1, new long[]{1, 2, 4, 8});
|
||||
|
||||
Parcel parcel = Parcel.obtain();
|
||||
counter.writeToParcel(parcel, 0);
|
||||
byte[] bytes = parcel.marshall();
|
||||
parcel.recycle();
|
||||
|
||||
parcel = Parcel.obtain();
|
||||
parcel.unmarshall(bytes, 0, bytes.length);
|
||||
parcel.setDataPosition(0);
|
||||
|
||||
LongArrayMultiStateCounter newCounter =
|
||||
LongArrayMultiStateCounter.CREATOR.createFromParcel(parcel);
|
||||
parcel.recycle();
|
||||
|
||||
assertCounts(newCounter, 0, new long[]{100, 200, 300, 400});
|
||||
assertCounts(newCounter, 1, new long[]{1, 2, 4, 8});
|
||||
|
||||
// ==== Verify that the counter keeps accumulating after unparceling.
|
||||
|
||||
// State, last update timestamp and current counts are undefined at this point.
|
||||
newCounter.setState(0, 100);
|
||||
updateValue(newCounter, new long[]{300, 400, 500, 600}, 100);
|
||||
|
||||
// A new base state and counters are established; we can continue accumulating deltas
|
||||
updateValue(newCounter, new long[]{316, 432, 564, 728}, 200);
|
||||
|
||||
assertCounts(newCounter, 0, new long[]{116, 232, 364, 528});
|
||||
}
|
||||
|
||||
private void updateValue(LongArrayMultiStateCounter counter, long[] values, int timestamp) {
|
||||
LongArrayMultiStateCounter.LongArrayContainer container =
|
||||
new LongArrayMultiStateCounter.LongArrayContainer(values.length);
|
||||
container.setValues(values);
|
||||
counter.updateValues(container, timestamp);
|
||||
}
|
||||
|
||||
private void assertCounts(LongArrayMultiStateCounter counter, int state, long[] expected) {
|
||||
LongArrayMultiStateCounter.LongArrayContainer container =
|
||||
new LongArrayMultiStateCounter.LongArrayContainer(expected.length);
|
||||
long[] counts = new long[expected.length];
|
||||
counter.getCounts(container, state);
|
||||
container.getValues(counts);
|
||||
assertThat(counts).isEqualTo(expected);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user