Add LongArrayMultiStateCounter
Bug: 197162116 Test: atest FrameworksCoreTests:LongArrayMultiStateCounterTest Test: atest CorePerfTests:LongArrayMultiStateCounterPerfTest Change-Id: I3e20aa1a64b6bb89658c57c74487f95681d4f0ff
This commit is contained in:
parent
6fd7e85cdb
commit
2f618d1bab
@ -0,0 +1,172 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package android.os;
|
||||
|
||||
import android.perftests.utils.BenchmarkState;
|
||||
import android.perftests.utils.PerfStatusReporter;
|
||||
|
||||
import androidx.test.filters.LargeTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.internal.os.LongArrayMultiStateCounter;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@LargeTest
|
||||
public class LongArrayMultiStateCounterPerfTest {
|
||||
|
||||
@Rule
|
||||
public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
|
||||
|
||||
/**
|
||||
* A complete line-for-line reimplementation of
|
||||
* {@link }com.android.internal.os.CpuTimeInFreqMultiStateCounter}, 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 static class State {
|
||||
private long mTimeInStateSinceUpdate;
|
||||
private long[] mCounter;
|
||||
}
|
||||
|
||||
private final State[] mStates;
|
||||
private final long[] mLastTimeInFreq;
|
||||
private final long[] mDelta;
|
||||
|
||||
TestLongArrayMultiStateCounter(int stateCount, int arrayLength, int initialState,
|
||||
long timestampMs) {
|
||||
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();
|
||||
mStates[i].mCounter = new long[mArrayLength];
|
||||
}
|
||||
mLastTimeInFreq = new long[mArrayLength];
|
||||
mDelta = new long[mArrayLength];
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
mCurrentState = state;
|
||||
mLastStateChangeTimestampMs = timestampMs;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
} else if (timestampMs < mLastUpdateTimestampMs) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
System.arraycopy(timeInFreq, 0, mLastTimeInFreq, 0, mArrayLength);
|
||||
mLastUpdateTimestampMs = timestampMs;
|
||||
}
|
||||
|
||||
private boolean delta(long[] timeInFreq1, long[] timeInFreq2, long[] delta) {
|
||||
if (delta.length != mArrayLength) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
boolean is_delta_valid = true;
|
||||
for (int i = 0; i < mStateCount; i++) {
|
||||
if (timeInFreq2[i] >= timeInFreq1[i]) {
|
||||
delta[i] = timeInFreq2[i] - timeInFreq1[i];
|
||||
} else {
|
||||
delta[i] = 0;
|
||||
is_delta_valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
return is_delta_valid;
|
||||
}
|
||||
|
||||
private void add(long[] counter, long[] delta, long numerator, long denominator) {
|
||||
if (numerator != denominator) {
|
||||
for (int i = 0; i < mArrayLength; i++) {
|
||||
counter[i] += delta[i] * numerator / denominator;
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < mArrayLength; i++) {
|
||||
counter[i] += delta[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void javaImplementation() {
|
||||
TestLongArrayMultiStateCounter counter =
|
||||
new TestLongArrayMultiStateCounter(2, 4, 0, 1000);
|
||||
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
|
||||
long time = 1000;
|
||||
long[] timeInFreq = {100, 200, 300, 400};
|
||||
while (state.keepRunning()) {
|
||||
counter.setState(1, time);
|
||||
counter.setState(0, time + 1000);
|
||||
counter.updateValue(timeInFreq, time + 2000);
|
||||
time += 10000;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nativeImplementation() {
|
||||
LongArrayMultiStateCounter counter = new LongArrayMultiStateCounter(2, 4, 0, 1000);
|
||||
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
|
||||
long time = 1000;
|
||||
LongArrayMultiStateCounter.LongArrayContainer timeInFreq =
|
||||
new LongArrayMultiStateCounter.LongArrayContainer(4);
|
||||
timeInFreq.setValues(new long[]{100, 200, 300, 400});
|
||||
while (state.keepRunning()) {
|
||||
counter.setState(1, time);
|
||||
counter.setState(0, time + 1000);
|
||||
counter.updateValues(timeInFreq, time + 2000);
|
||||
time += 10000;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,181 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.android.internal.os;
|
||||
|
||||
import dalvik.annotation.optimization.CriticalNative;
|
||||
import dalvik.annotation.optimization.FastNative;
|
||||
|
||||
import libcore.util.NativeAllocationRegistry;
|
||||
|
||||
/**
|
||||
* Performs per-state counting of multi-element values over time. The class' behavior is illustrated
|
||||
* by this example:
|
||||
* <pre>
|
||||
* // At 0 ms, the state of the tracked object is 0
|
||||
* counter.setState(0, 0);
|
||||
*
|
||||
* // At 1000 ms, the state changes to 1
|
||||
* counter.setState(1, 1000);
|
||||
*
|
||||
* // At 3000 ms, the tracked values are updated to {100, 200}
|
||||
* arrayContainer.setValues(new long[]{{30, 300}};
|
||||
* counter.updateValues(arrayContainer, 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}
|
||||
* </pre>
|
||||
*
|
||||
* The tracked values are expected to increase monotonically.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class LongArrayMultiStateCounter {
|
||||
|
||||
/**
|
||||
* Container for a native equivalent of a long[].
|
||||
*/
|
||||
public static class LongArrayContainer {
|
||||
private static final NativeAllocationRegistry sRegistry =
|
||||
NativeAllocationRegistry.createMalloced(
|
||||
LongArrayContainer.class.getClassLoader(), native_getReleaseFunc());
|
||||
|
||||
private final long mNativeObject;
|
||||
private final int mLength;
|
||||
|
||||
public LongArrayContainer(int length) {
|
||||
mLength = length;
|
||||
mNativeObject = native_init(length);
|
||||
sRegistry.registerNativeAllocation(this, mNativeObject);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the supplied values into the underlying native array.
|
||||
*/
|
||||
public void setValues(long[] array) {
|
||||
if (array.length != mLength) {
|
||||
throw new IllegalArgumentException(
|
||||
"Invalid array length: " + mLength + ", 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: " + mLength + ", expected: " + mLength);
|
||||
}
|
||||
native_getValues(mNativeObject, array);
|
||||
}
|
||||
|
||||
@CriticalNative
|
||||
private static native long native_init(int length);
|
||||
|
||||
@CriticalNative
|
||||
private static native long native_getReleaseFunc();
|
||||
|
||||
@FastNative
|
||||
private native void native_setValues(long nativeObject, long[] array);
|
||||
|
||||
@FastNative
|
||||
private native void native_getValues(long nativeObject, long[] array);
|
||||
}
|
||||
|
||||
private static final NativeAllocationRegistry sRegistry =
|
||||
NativeAllocationRegistry.createMalloced(
|
||||
LongArrayMultiStateCounter.class.getClassLoader(), native_getReleaseFunc());
|
||||
|
||||
private final int mStateCount;
|
||||
private final int mLength;
|
||||
private final long mNativeObject;
|
||||
|
||||
public LongArrayMultiStateCounter(int stateCount, int arrayLength, int initialState,
|
||||
long timestampMs) {
|
||||
mStateCount = stateCount;
|
||||
mLength = arrayLength;
|
||||
mNativeObject = native_init(stateCount, arrayLength, initialState, timestampMs);
|
||||
sRegistry.registerNativeAllocation(this, mNativeObject);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current state to the supplied value.
|
||||
*/
|
||||
public void setState(int state, long timestampMs) {
|
||||
if (state < 0 || state >= mStateCount) {
|
||||
throw new IllegalArgumentException(
|
||||
"State: " + state + ", outside the range: [0-" + mStateCount + "]");
|
||||
}
|
||||
native_setState(mNativeObject, state, timestampMs);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(LongArrayContainer longArrayContainer, long timestampMs) {
|
||||
if (longArrayContainer.mLength != mLength) {
|
||||
throw new IllegalArgumentException(
|
||||
"Invalid array length: " + longArrayContainer.mLength + ", expected: "
|
||||
+ mLength);
|
||||
}
|
||||
native_updateValues(mNativeObject, longArrayContainer.mNativeObject, timestampMs);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 + "]");
|
||||
}
|
||||
native_getCounts(mNativeObject, longArrayContainer.mNativeObject, state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return native_toString(mNativeObject);
|
||||
}
|
||||
|
||||
@CriticalNative
|
||||
private static native long native_init(int stateCount, int arrayLength, int initialState,
|
||||
long timestampMs);
|
||||
|
||||
@CriticalNative
|
||||
private static native long native_getReleaseFunc();
|
||||
|
||||
@CriticalNative
|
||||
private static native void native_setState(long nativeObject, int state, long timestampMs);
|
||||
|
||||
@CriticalNative
|
||||
private static native void native_updateValues(long nativeObject,
|
||||
long longArrayContainerNativeObject, long timestampMs);
|
||||
|
||||
@CriticalNative
|
||||
private static native void native_getCounts(long nativeObject,
|
||||
long longArrayContainerNativeObject, int state);
|
||||
|
||||
@FastNative
|
||||
private native String native_toString(long nativeObject);
|
||||
}
|
@ -216,6 +216,7 @@ cc_library_shared {
|
||||
"com_android_internal_os_KernelCpuUidBpfMapReader.cpp",
|
||||
"com_android_internal_os_KernelSingleProcessCpuThreadReader.cpp",
|
||||
"com_android_internal_os_KernelSingleUidTimeReader.cpp",
|
||||
"com_android_internal_os_LongArrayMultiStateCounter.cpp",
|
||||
"com_android_internal_os_Zygote.cpp",
|
||||
"com_android_internal_os_ZygoteCommandBuffer.cpp",
|
||||
"com_android_internal_os_ZygoteInit.cpp",
|
||||
@ -244,6 +245,7 @@ cc_library_shared {
|
||||
"av-types-aidl-cpp",
|
||||
"android.hardware.camera.device@3.2",
|
||||
"libandroidicu",
|
||||
"libbattery",
|
||||
"libbpf_android",
|
||||
"libnetdbpf",
|
||||
"libnetdutils",
|
||||
|
@ -203,6 +203,7 @@ extern int register_com_android_internal_os_KernelCpuTotalBpfMapReader(JNIEnv* e
|
||||
extern int register_com_android_internal_os_KernelCpuUidBpfMapReader(JNIEnv *env);
|
||||
extern int register_com_android_internal_os_KernelSingleProcessCpuThreadReader(JNIEnv* env);
|
||||
extern int register_com_android_internal_os_KernelSingleUidTimeReader(JNIEnv *env);
|
||||
extern int register_com_android_internal_os_LongArrayMultiStateCounter(JNIEnv* env);
|
||||
extern int register_com_android_internal_os_Zygote(JNIEnv *env);
|
||||
extern int register_com_android_internal_os_ZygoteCommandBuffer(JNIEnv *env);
|
||||
extern int register_com_android_internal_os_ZygoteInit(JNIEnv *env);
|
||||
@ -1584,6 +1585,7 @@ static const RegJNIRec gRegJNI[] = {
|
||||
REG_JNI(register_com_android_internal_content_om_OverlayConfig),
|
||||
REG_JNI(register_com_android_internal_net_NetworkUtilsInternal),
|
||||
REG_JNI(register_com_android_internal_os_ClassLoaderFactory),
|
||||
REG_JNI(register_com_android_internal_os_LongArrayMultiStateCounter),
|
||||
REG_JNI(register_com_android_internal_os_Zygote),
|
||||
REG_JNI(register_com_android_internal_os_ZygoteCommandBuffer),
|
||||
REG_JNI(register_com_android_internal_os_ZygoteInit),
|
||||
|
144
core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp
Normal file
144
core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp
Normal file
@ -0,0 +1,144 @@
|
||||
/*
|
||||
* 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 <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) {
|
||||
battery::LongArrayMultiStateCounter *counter =
|
||||
new battery::LongArrayMultiStateCounter(stateCount, initialState,
|
||||
std::vector<uint64_t>(arrayLength), timestamp);
|
||||
return reinterpret_cast<jlong>(counter);
|
||||
}
|
||||
|
||||
static void native_dispose(void *nativePtr) {
|
||||
battery::LongArrayMultiStateCounter *counter =
|
||||
reinterpret_cast<battery::LongArrayMultiStateCounter *>(nativePtr);
|
||||
delete counter;
|
||||
}
|
||||
|
||||
static jlong native_getReleaseFunc() {
|
||||
return reinterpret_cast<jlong>(native_dispose);
|
||||
}
|
||||
|
||||
static void native_setState(jlong nativePtr, jint state, jlong timestamp) {
|
||||
battery::LongArrayMultiStateCounter *counter =
|
||||
reinterpret_cast<battery::LongArrayMultiStateCounter *>(nativePtr);
|
||||
counter->setState(state, timestamp);
|
||||
}
|
||||
|
||||
static void native_updateValues(jlong nativePtr, jlong longArrayContainerNativePtr,
|
||||
jlong timestamp) {
|
||||
battery::LongArrayMultiStateCounter *counter =
|
||||
reinterpret_cast<battery::LongArrayMultiStateCounter *>(nativePtr);
|
||||
std::vector<uint64_t> *vector =
|
||||
reinterpret_cast<std::vector<uint64_t> *>(longArrayContainerNativePtr);
|
||||
|
||||
counter->updateValue(*vector, timestamp);
|
||||
}
|
||||
|
||||
static void native_getCounts(jlong nativePtr, jlong longArrayContainerNativePtr, jint state) {
|
||||
battery::LongArrayMultiStateCounter *counter =
|
||||
reinterpret_cast<battery::LongArrayMultiStateCounter *>(nativePtr);
|
||||
std::vector<uint64_t> *vector =
|
||||
reinterpret_cast<std::vector<uint64_t> *>(longArrayContainerNativePtr);
|
||||
|
||||
*vector = counter->getCount(state);
|
||||
}
|
||||
|
||||
static jobject native_toString(JNIEnv *env, jlong nativePtr, jobject self) {
|
||||
battery::LongArrayMultiStateCounter *counter =
|
||||
reinterpret_cast<battery::LongArrayMultiStateCounter *>(nativePtr);
|
||||
return env->NewStringUTF(counter->toString().c_str());
|
||||
}
|
||||
|
||||
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},
|
||||
// @CriticalNative
|
||||
{"native_getReleaseFunc", "()J", (void *)native_getReleaseFunc},
|
||||
// @CriticalNative
|
||||
{"native_setState", "(JIJ)V", (void *)native_setState},
|
||||
// @CriticalNative
|
||||
{"native_updateValues", "(JJJ)V", (void *)native_updateValues},
|
||||
// @CriticalNative
|
||||
{"native_getCounts", "(JJI)V", (void *)native_getCounts},
|
||||
// @FastNative
|
||||
{"native_toString", "(J)Ljava/lang/String;", (void *)native_toString},
|
||||
};
|
||||
|
||||
/////////////////////// LongArrayMultiStateCounter.LongArrayContainer ////////////////////////
|
||||
|
||||
static void native_dispose_LongArrayContainer(jlong nativePtr) {
|
||||
std::vector<uint64_t> *vector = reinterpret_cast<std::vector<uint64_t> *>(nativePtr);
|
||||
delete vector;
|
||||
}
|
||||
|
||||
static jlong native_getReleaseFunc_LongArrayContainer() {
|
||||
return reinterpret_cast<jlong>(native_dispose_LongArrayContainer);
|
||||
}
|
||||
|
||||
static void native_setValues_LongArrayContainer(JNIEnv *env, jobject self, jlong nativePtr,
|
||||
jlongArray jarray) {
|
||||
std::vector<uint64_t> *vector = reinterpret_cast<std::vector<uint64_t> *>(nativePtr);
|
||||
ScopedLongArrayRO scopedArray(env, jarray);
|
||||
const uint64_t *array = reinterpret_cast<const uint64_t *>(scopedArray.get());
|
||||
uint8_t size = scopedArray.size();
|
||||
|
||||
// Boundary checks are performed in the Java layer
|
||||
std::copy(array, array + size, vector->data());
|
||||
}
|
||||
|
||||
static void native_getValues_LongArrayContainer(JNIEnv *env, jobject self, jlong nativePtr,
|
||||
jlongArray jarray) {
|
||||
std::vector<uint64_t> *vector = reinterpret_cast<std::vector<uint64_t> *>(nativePtr);
|
||||
ScopedLongArrayRW scopedArray(env, jarray);
|
||||
|
||||
// Boundary checks are performed in the Java layer
|
||||
std::copy(vector->data(), vector->data() + vector->size(), scopedArray.get());
|
||||
}
|
||||
|
||||
static const JNINativeMethod g_LongArrayContainer_methods[] = {
|
||||
// @CriticalNative
|
||||
{"native_init", "(I)J", (void *)native_init_LongArrayContainer},
|
||||
// @CriticalNative
|
||||
{"native_getReleaseFunc", "()J", (void *)native_getReleaseFunc_LongArrayContainer},
|
||||
// @FastNative
|
||||
{"native_setValues", "(J[J)V", (void *)native_setValues_LongArrayContainer},
|
||||
// @FastNative
|
||||
{"native_getValues", "(J[J)V", (void *)native_getValues_LongArrayContainer},
|
||||
};
|
||||
|
||||
int register_com_android_internal_os_LongArrayMultiStateCounter(JNIEnv *env) {
|
||||
// 0 represents success, thus "|" and not "&"
|
||||
return RegisterMethodsOrDie(env, "com/android/internal/os/LongArrayMultiStateCounter",
|
||||
g_LongArrayMultiStateCounter_methods,
|
||||
NELEM(g_LongArrayMultiStateCounter_methods)) |
|
||||
RegisterMethodsOrDie(env,
|
||||
"com/android/internal/os/LongArrayMultiStateCounter"
|
||||
"$LongArrayContainer",
|
||||
g_LongArrayContainer_methods, NELEM(g_LongArrayContainer_methods));
|
||||
}
|
||||
|
||||
} // namespace android
|
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.android.internal.os;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class LongArrayMultiStateCounterTest {
|
||||
|
||||
@Test
|
||||
public void setStateAndUpdateValue() {
|
||||
LongArrayMultiStateCounter.LongArrayContainer longArrayContainer =
|
||||
new LongArrayMultiStateCounter.LongArrayContainer(4);
|
||||
LongArrayMultiStateCounter counter = new LongArrayMultiStateCounter(2, 4, 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);
|
||||
|
||||
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});
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user