Merge "[TeX] Source code moved to modules-utils"

This commit is contained in:
Vova Sharaienko
2023-04-21 15:32:48 +00:00
committed by Gerrit Code Review
17 changed files with 6 additions and 787 deletions

View File

@@ -345,6 +345,7 @@ java_defaults {
"framework-permission-aidl-java",
"spatializer-aidl-java",
"audiopolicy-types-aidl-java",
"modules-utils-expresslog",
],
}

View File

@@ -31,7 +31,7 @@ import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.expresslog.Counter;
import com.android.modules.expresslog.Counter;
import com.android.server.job.JobSchedulerService;
import com.android.server.job.StateControllerProto;

View File

@@ -1,71 +0,0 @@
/*
* Copyright (C) 2023 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.expresslog;
import android.annotation.NonNull;
import com.android.internal.util.FrameworkStatsLog;
/** Counter encapsulates StatsD write API calls */
public final class Counter {
// Not instantiable.
private Counter() {}
/**
* Increments Telemetry Express Counter metric by 1
* @param metricId to log, no-op if metricId is not defined in the TeX catalog
* @hide
*/
public static void logIncrement(@NonNull String metricId) {
logIncrement(metricId, 1);
}
/**
* Increments Telemetry Express Counter metric by 1
* @param metricId to log, no-op if metricId is not defined in the TeX catalog
* @param uid used as a dimension for the count metric
* @hide
*/
public static void logIncrementWithUid(@NonNull String metricId, int uid) {
logIncrementWithUid(metricId, uid, 1);
}
/**
* Increments Telemetry Express Counter metric by arbitrary value
* @param metricId to log, no-op if metricId is not defined in the TeX catalog
* @param amount to increment counter
* @hide
*/
public static void logIncrement(@NonNull String metricId, long amount) {
final long metricIdHash = Utils.hashString(metricId);
FrameworkStatsLog.write(FrameworkStatsLog.EXPRESS_EVENT_REPORTED, metricIdHash, amount);
}
/**
* Increments Telemetry Express Counter metric by arbitrary value
* @param metricId to log, no-op if metricId is not defined in the TeX catalog
* @param uid used as a dimension for the count metric
* @param amount to increment counter
* @hide
*/
public static void logIncrementWithUid(@NonNull String metricId, int uid, long amount) {
final long metricIdHash = Utils.hashString(metricId);
FrameworkStatsLog.write(
FrameworkStatsLog.EXPRESS_UID_EVENT_REPORTED, metricIdHash, amount, uid);
}
}

View File

@@ -1,234 +0,0 @@
/*
* Copyright (C) 2023 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.expresslog;
import android.annotation.FloatRange;
import android.annotation.IntRange;
import android.annotation.NonNull;
import com.android.internal.util.FrameworkStatsLog;
import java.util.Arrays;
/** Histogram encapsulates StatsD write API calls */
public final class Histogram {
private final long mMetricIdHash;
private final BinOptions mBinOptions;
/**
* Creates Histogram metric logging wrapper
*
* @param metricId to log, logging will be no-op if metricId is not defined in the TeX catalog
* @param binOptions to calculate bin index for samples
* @hide
*/
public Histogram(@NonNull String metricId, @NonNull BinOptions binOptions) {
mMetricIdHash = Utils.hashString(metricId);
mBinOptions = binOptions;
}
/**
* Logs increment sample count for automatically calculated bin
*
* @param sample value
* @hide
*/
public void logSample(float sample) {
final int binIndex = mBinOptions.getBinForSample(sample);
FrameworkStatsLog.write(FrameworkStatsLog.EXPRESS_HISTOGRAM_SAMPLE_REPORTED, mMetricIdHash,
/*count*/ 1, binIndex);
}
/**
* Logs increment sample count for automatically calculated bin
*
* @param uid used as a dimension for the count metric
* @param sample value
* @hide
*/
public void logSampleWithUid(int uid, float sample) {
final int binIndex = mBinOptions.getBinForSample(sample);
FrameworkStatsLog.write(FrameworkStatsLog.EXPRESS_UID_HISTOGRAM_SAMPLE_REPORTED,
mMetricIdHash, /*count*/ 1, binIndex, uid);
}
/** Used by Histogram to map data sample to corresponding bin */
public interface BinOptions {
/**
* Returns bins count to be used by a histogram
*
* @return bins count used to initialize Options, including overflow & underflow bins
* @hide
*/
int getBinsCount();
/**
* Returns bin index for the input sample value
* index == 0 stands for underflow
* index == getBinsCount() - 1 stands for overflow
*
* @return zero based index
* @hide
*/
int getBinForSample(float sample);
}
/** Used by Histogram to map data sample to corresponding bin for uniform bins */
public static final class UniformOptions implements BinOptions {
private final int mBinCount;
private final float mMinValue;
private final float mExclusiveMaxValue;
private final float mBinSize;
/**
* Creates options for uniform (linear) sized bins
*
* @param binCount amount of histogram bins. 2 bin indexes will be calculated
* automatically to represent underflow & overflow bins
* @param minValue is included in the first bin, values less than minValue
* go to underflow bin
* @param exclusiveMaxValue is included in the overflow bucket. For accurate
* measure up to kMax, then exclusiveMaxValue
* should be set to kMax + 1
* @hide
*/
public UniformOptions(@IntRange(from = 1) int binCount, float minValue,
float exclusiveMaxValue) {
if (binCount < 1) {
throw new IllegalArgumentException("Bin count should be positive number");
}
if (exclusiveMaxValue <= minValue) {
throw new IllegalArgumentException("Bins range invalid (maxValue < minValue)");
}
mMinValue = minValue;
mExclusiveMaxValue = exclusiveMaxValue;
mBinSize = (mExclusiveMaxValue - minValue) / binCount;
// Implicitly add 2 for the extra underflow & overflow bins
mBinCount = binCount + 2;
}
@Override
public int getBinsCount() {
return mBinCount;
}
@Override
public int getBinForSample(float sample) {
if (sample < mMinValue) {
// goes to underflow
return 0;
} else if (sample >= mExclusiveMaxValue) {
// goes to overflow
return mBinCount - 1;
}
return (int) ((sample - mMinValue) / mBinSize + 1);
}
}
/** Used by Histogram to map data sample to corresponding bin for scaled bins */
public static final class ScaledRangeOptions implements BinOptions {
// store minimum value per bin
final long[] mBins;
/**
* Creates options for scaled range bins
*
* @param binCount amount of histogram bins. 2 bin indexes will be calculated
* automatically to represent underflow & overflow bins
* @param minValue is included in the first bin, values less than minValue
* go to underflow bin
* @param firstBinWidth used to represent first bin width and as a reference to calculate
* width for consecutive bins
* @param scaleFactor used to calculate width for consecutive bins
* @hide
*/
public ScaledRangeOptions(@IntRange(from = 1) int binCount, int minValue,
@FloatRange(from = 1.f) float firstBinWidth,
@FloatRange(from = 1.f) float scaleFactor) {
if (binCount < 1) {
throw new IllegalArgumentException("Bin count should be positive number");
}
if (firstBinWidth < 1.f) {
throw new IllegalArgumentException(
"First bin width invalid (should be 1.f at minimum)");
}
if (scaleFactor < 1.f) {
throw new IllegalArgumentException(
"Scaled factor invalid (should be 1.f at minimum)");
}
// precalculating bins ranges (no need to create a bin for underflow reference value)
mBins = initBins(binCount + 1, minValue, firstBinWidth, scaleFactor);
}
@Override
public int getBinsCount() {
return mBins.length + 1;
}
@Override
public int getBinForSample(float sample) {
if (sample < mBins[0]) {
// goes to underflow
return 0;
} else if (sample >= mBins[mBins.length - 1]) {
// goes to overflow
return mBins.length;
}
return lower_bound(mBins, (long) sample) + 1;
}
// To find lower bound using binary search implementation of Arrays utility class
private static int lower_bound(long[] array, long sample) {
int index = Arrays.binarySearch(array, sample);
// If key is not present in the array
if (index < 0) {
// Index specify the position of the key when inserted in the sorted array
// so the element currently present at this position will be the lower bound
return Math.abs(index) - 2;
}
return index;
}
private static long[] initBins(int count, int minValue, float firstBinWidth,
float scaleFactor) {
long[] bins = new long[count];
bins[0] = minValue;
double lastWidth = firstBinWidth;
for (int i = 1; i < count; i++) {
// current bin minValue = previous bin width * scaleFactor
double currentBinMinValue = bins[i - 1] + lastWidth;
if (currentBinMinValue > Integer.MAX_VALUE) {
throw new IllegalArgumentException(
"Attempted to create a bucket larger than maxint");
}
bins[i] = (long) currentBinMinValue;
lastWidth *= scaleFactor;
}
return bins;
}
}
}

View File

@@ -1 +0,0 @@
include /services/core/java/com/android/server/stats/OWNERS

View File

@@ -1,12 +0,0 @@
{
"presubmit": [
{
"name": "ExpressLogTests",
"options": [
{
"exclude-annotation": "org.junit.Ignore"
}
]
}
]
}

View File

@@ -1,21 +0,0 @@
/*
* Copyright (C) 2023 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.expresslog;
final class Utils {
static native long hashString(String stringToHash);
}

View File

@@ -221,7 +221,6 @@ cc_library_shared {
"android_content_res_Configuration.cpp",
"android_security_Scrypt.cpp",
"com_android_internal_content_om_OverlayConfig.cpp",
"com_android_internal_expresslog_Utils.cpp",
"com_android_internal_net_NetworkUtilsInternal.cpp",
"com_android_internal_os_ClassLoaderFactory.cpp",
"com_android_internal_os_FuseAppLoop.cpp",
@@ -256,6 +255,7 @@ cc_library_shared {
"libstatssocket_lazy",
"libskia",
"libtextclassifier_hash_static",
"libexpresslog_jni",
],
shared_libs: [

View File

@@ -195,8 +195,7 @@ extern int register_android_animation_PropertyValuesHolder(JNIEnv *env);
extern int register_android_security_Scrypt(JNIEnv *env);
extern int register_com_android_internal_content_F2fsUtils(JNIEnv* env);
extern int register_com_android_internal_content_NativeLibraryHelper(JNIEnv *env);
extern int register_com_android_internal_content_om_OverlayConfig(JNIEnv *env);
extern int register_com_android_internal_expresslog_Utils(JNIEnv* env);
extern int register_com_android_internal_content_om_OverlayConfig(JNIEnv* env);
extern int register_com_android_internal_net_NetworkUtilsInternal(JNIEnv* env);
extern int register_com_android_internal_os_ClassLoaderFactory(JNIEnv* env);
extern int register_com_android_internal_os_FuseAppLoop(JNIEnv* env);
@@ -213,6 +212,7 @@ extern int register_com_android_internal_os_ZygoteCommandBuffer(JNIEnv *env);
extern int register_com_android_internal_os_ZygoteInit(JNIEnv *env);
extern int register_com_android_internal_security_VerityUtils(JNIEnv* env);
extern int register_com_android_internal_util_VirtualRefBasePtr(JNIEnv *env);
extern int register_com_android_modules_expresslog_Utils(JNIEnv* env);
extern int register_android_window_WindowInfosListener(JNIEnv* env);
// Namespace for Android Runtime flags applied during boot time.
@@ -1591,7 +1591,6 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_os_SharedMemory),
REG_JNI(register_android_os_incremental_IncrementalManager),
REG_JNI(register_com_android_internal_content_om_OverlayConfig),
REG_JNI(register_com_android_internal_expresslog_Utils),
REG_JNI(register_com_android_internal_net_NetworkUtilsInternal),
REG_JNI(register_com_android_internal_os_ClassLoaderFactory),
REG_JNI(register_com_android_internal_os_LongArrayMultiStateCounter),
@@ -1601,6 +1600,7 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_com_android_internal_os_ZygoteInit),
REG_JNI(register_com_android_internal_security_VerityUtils),
REG_JNI(register_com_android_internal_util_VirtualRefBasePtr),
REG_JNI(register_com_android_modules_expresslog_Utils),
REG_JNI(register_android_hardware_Camera),
REG_JNI(register_android_hardware_camera2_CameraMetadata),
REG_JNI(register_android_hardware_camera2_DngCreator),

View File

@@ -102,6 +102,3 @@ per-file com_android_internal_os_*MultiStateCounter* = file:/BATTERY_STATS_OWNER
# PM
per-file com_android_internal_content_* = file:/PACKAGE_MANAGER_OWNERS
# Stats/expresslog
per-file *expresslog* = file:/services/core/java/com/android/server/stats/OWNERS

View File

@@ -1,57 +0,0 @@
/*
* Copyright (C) 2022 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/JNIHelp.h>
#include <utils/hash/farmhash.h>
#include "core_jni_helpers.h"
// ----------------------------------------------------------------------------
// JNI Glue
// ----------------------------------------------------------------------------
static jclass g_stringClass = nullptr;
/**
* Class: com_android_internal_expresslog_Utils
* Method: hashString
* Signature: (Ljava/lang/String;)J
*/
static jlong hashString(JNIEnv* env, jclass /*class*/, jstring metricNameObj) {
ScopedUtfChars name(env, metricNameObj);
if (name.c_str() == nullptr) {
return 0;
}
return static_cast<jlong>(farmhash::Fingerprint64(name.c_str(), name.size()));
}
static const JNINativeMethod g_methods[] = {
{"hashString", "(Ljava/lang/String;)J", (void*)hashString},
};
static const char* const kUtilsPathName = "com/android/internal/expresslog/Utils";
namespace android {
int register_com_android_internal_expresslog_Utils(JNIEnv* env) {
jclass stringClass = FindClassOrDie(env, "java/lang/String");
g_stringClass = MakeGlobalRefOrDie(env, stringClass);
return RegisterMethodsOrDie(env, kUtilsPathName, g_methods, NELEM(g_methods));
}
} // namespace android

View File

@@ -1,47 +0,0 @@
// Copyright (C) 2023 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 {
// See: http://go/android-license-faq
// A large-scale-change added 'default_applicable_licenses' to import
// all of the 'license_kinds' from "frameworks_base_license"
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["frameworks_base_license"],
}
android_test {
name: "ExpressLogTests",
srcs: [
"src/**/*.java",
],
static_libs: [
"androidx.test.rules",
"modules-utils-build",
],
libs: [
"android.test.base",
"android.test.runner",
],
platform_apis: true,
test_suites: [
"general-tests",
],
certificate: "platform",
}

View File

@@ -1,29 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2023 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.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:installLocation="internalOnly"
package="com.android.internal.expresslog" >
<application >
<uses-library android:name="android.test.runner" />
</application>
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="com.android.internal.expresslog"
android:label="Telemetry Express Logging Helper Tests" />
</manifest>

View File

@@ -1,3 +0,0 @@
# Bug component: 719316
# Stats/expresslog
file:/services/core/java/com/android/server/stats/OWNERS

View File

@@ -1,12 +0,0 @@
{
"presubmit": [
{
"name": "ExpressLogTests",
"options": [
{
"exclude-annotation": "org.junit.Ignore"
}
]
}
]
}

View File

@@ -1,167 +0,0 @@
/*
* Copyright (C) 2023 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.expresslog;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import androidx.test.filters.SmallTest;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@RunWith(JUnit4.class)
@SmallTest
public class ScaledRangeOptionsTest {
private static final String TAG = ScaledRangeOptionsTest.class.getSimpleName();
@Test
public void testGetBinsCount() {
Histogram.ScaledRangeOptions options1 = new Histogram.ScaledRangeOptions(1, 100, 100, 2);
assertEquals(3, options1.getBinsCount());
Histogram.ScaledRangeOptions options10 = new Histogram.ScaledRangeOptions(10, 100, 100, 2);
assertEquals(12, options10.getBinsCount());
}
@Test(expected = IllegalArgumentException.class)
public void testConstructZeroBinsCount() {
new Histogram.ScaledRangeOptions(0, 100, 100, 2);
}
@Test(expected = IllegalArgumentException.class)
public void testConstructNegativeBinsCount() {
new Histogram.ScaledRangeOptions(-1, 100, 100, 2);
}
@Test(expected = IllegalArgumentException.class)
public void testConstructNegativeFirstBinWidth() {
new Histogram.ScaledRangeOptions(10, 100, -100, 2);
}
@Test(expected = IllegalArgumentException.class)
public void testConstructTooSmallFirstBinWidth() {
new Histogram.ScaledRangeOptions(10, 100, 0.5f, 2);
}
@Test(expected = IllegalArgumentException.class)
public void testConstructNegativeScaleFactor() {
new Histogram.ScaledRangeOptions(10, 100, 100, -2);
}
@Test(expected = IllegalArgumentException.class)
public void testConstructTooSmallScaleFactor() {
new Histogram.ScaledRangeOptions(10, 100, 100, 0.5f);
}
@Test(expected = IllegalArgumentException.class)
public void testConstructTooBigScaleFactor() {
new Histogram.ScaledRangeOptions(10, 100, 100, 500.f);
}
@Test(expected = IllegalArgumentException.class)
public void testConstructTooBigBinRange() {
new Histogram.ScaledRangeOptions(100, 100, 100, 10.f);
}
@Test
public void testBinIndexForRangeEqual1() {
Histogram.ScaledRangeOptions options = new Histogram.ScaledRangeOptions(10, 1, 1, 1);
assertEquals(12, options.getBinsCount());
assertEquals(11, options.getBinForSample(11));
for (int i = 0, bins = options.getBinsCount(); i < bins; i++) {
assertEquals(i, options.getBinForSample(i));
}
}
@Test
public void testBinIndexForRangeEqual2() {
// this should produce bin otpions similar to linear histogram with bin width 2
Histogram.ScaledRangeOptions options = new Histogram.ScaledRangeOptions(10, 1, 2, 1);
assertEquals(12, options.getBinsCount());
for (int i = 0, bins = options.getBinsCount(); i < bins; i++) {
assertEquals(i, options.getBinForSample(i * 2));
assertEquals(i, options.getBinForSample(i * 2 - 1));
}
}
@Test
public void testBinIndexForRangeEqual5() {
Histogram.ScaledRangeOptions options = new Histogram.ScaledRangeOptions(2, 0, 5, 1);
assertEquals(4, options.getBinsCount());
for (int i = 0; i < 2; i++) {
for (int sample = 0; sample < 5; sample++) {
assertEquals(i + 1, options.getBinForSample(i * 5 + sample));
}
}
}
@Test
public void testBinIndexForRangeEqual10() {
Histogram.ScaledRangeOptions options = new Histogram.ScaledRangeOptions(10, 1, 10, 1);
assertEquals(0, options.getBinForSample(0));
assertEquals(options.getBinsCount() - 2, options.getBinForSample(100));
assertEquals(options.getBinsCount() - 1, options.getBinForSample(101));
final float binSize = (101 - 1) / 10f;
for (int i = 1, bins = options.getBinsCount() - 1; i < bins; i++) {
assertEquals(i, options.getBinForSample(i * binSize));
}
}
@Test
public void testBinIndexForScaleFactor2() {
final int binsCount = 10;
final int minValue = 10;
final int firstBinWidth = 5;
final int scaledFactor = 2;
Histogram.ScaledRangeOptions options = new Histogram.ScaledRangeOptions(
binsCount, minValue, firstBinWidth, scaledFactor);
assertEquals(binsCount + 2, options.getBinsCount());
long[] binCounts = new long[10];
// precalculate max valid value - start value for the overflow bin
int lastBinStartValue = minValue; //firstBinMin value
int lastBinWidth = firstBinWidth;
for (int binIdx = 2; binIdx <= binsCount + 1; binIdx++) {
lastBinStartValue = lastBinStartValue + lastBinWidth;
lastBinWidth *= scaledFactor;
}
// underflow bin
for (int i = 1; i < minValue; i++) {
assertEquals(0, options.getBinForSample(i));
}
for (int i = 10; i < lastBinStartValue; i++) {
assertTrue(options.getBinForSample(i) > 0);
assertTrue(options.getBinForSample(i) <= binsCount);
binCounts[options.getBinForSample(i) - 1]++;
}
// overflow bin
assertEquals(binsCount + 1, options.getBinForSample(lastBinStartValue));
for (int i = 1; i < binsCount; i++) {
assertEquals(binCounts[i], binCounts[i - 1] * 2L);
}
}
}

View File

@@ -1,125 +0,0 @@
/*
* Copyright (C) 2023 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.expresslog;
import androidx.test.filters.SmallTest;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@RunWith(JUnit4.class)
@SmallTest
public class UniformOptionsTest {
private static final String TAG = UniformOptionsTest.class.getSimpleName();
@Test
public void testGetBinsCount() {
Histogram.UniformOptions options1 = new Histogram.UniformOptions(1, 100, 1000);
assertEquals(3, options1.getBinsCount());
Histogram.UniformOptions options10 = new Histogram.UniformOptions(10, 100, 1000);
assertEquals(12, options10.getBinsCount());
}
@Test(expected = IllegalArgumentException.class)
public void testConstructZeroBinsCount() {
new Histogram.UniformOptions(0, 100, 1000);
}
@Test(expected = IllegalArgumentException.class)
public void testConstructNegativeBinsCount() {
new Histogram.UniformOptions(-1, 100, 1000);
}
@Test(expected = IllegalArgumentException.class)
public void testConstructMaxValueLessThanMinValue() {
new Histogram.UniformOptions(10, 1000, 100);
}
@Test
public void testBinIndexForRangeEqual1() {
Histogram.UniformOptions options = new Histogram.UniformOptions(10, 1, 11);
for (int i = 0, bins = options.getBinsCount(); i < bins; i++) {
assertEquals(i, options.getBinForSample(i));
}
}
@Test
public void testBinIndexForRangeEqual2() {
Histogram.UniformOptions options = new Histogram.UniformOptions(10, 1, 21);
for (int i = 0, bins = options.getBinsCount(); i < bins; i++) {
assertEquals(i, options.getBinForSample(i * 2));
assertEquals(i, options.getBinForSample(i * 2 - 1));
}
}
@Test
public void testBinIndexForRangeEqual5() {
Histogram.UniformOptions options = new Histogram.UniformOptions(2, 0, 10);
assertEquals(4, options.getBinsCount());
for (int i = 0; i < 2; i++) {
for (int sample = 0; sample < 5; sample++) {
assertEquals(i + 1, options.getBinForSample(i * 5 + sample));
}
}
}
@Test
public void testBinIndexForRangeEqual10() {
Histogram.UniformOptions options = new Histogram.UniformOptions(10, 1, 101);
assertEquals(0, options.getBinForSample(0));
assertEquals(options.getBinsCount() - 2, options.getBinForSample(100));
assertEquals(options.getBinsCount() - 1, options.getBinForSample(101));
final float binSize = (101 - 1) / 10f;
for (int i = 1, bins = options.getBinsCount() - 1; i < bins; i++) {
assertEquals(i, options.getBinForSample(i * binSize));
}
}
@Test
public void testBinIndexForRangeEqual90() {
final int binCount = 10;
final int minValue = 100;
final int maxValue = 100000;
Histogram.UniformOptions options = new Histogram.UniformOptions(binCount, minValue,
maxValue);
// logging underflow sample
assertEquals(0, options.getBinForSample(minValue - 1));
// logging overflow sample
assertEquals(binCount + 1, options.getBinForSample(maxValue));
assertEquals(binCount + 1, options.getBinForSample(maxValue + 1));
// logging min edge sample
assertEquals(1, options.getBinForSample(minValue));
// logging max edge sample
assertEquals(binCount, options.getBinForSample(maxValue - 1));
// logging single valid sample per bin
final int binSize = (maxValue - minValue) / binCount;
for (int i = 0; i < binCount; i++) {
assertEquals(i + 1, options.getBinForSample(minValue + binSize * i));
}
}
}