diff options
-rw-r--r-- | core/java/com/android/internal/expresslog/Histogram.java | 107 | ||||
-rw-r--r-- | core/java/com/android/internal/expresslog/TEST_MAPPING | 12 | ||||
-rw-r--r-- | core/tests/expresslog/Android.bp | 47 | ||||
-rw-r--r-- | core/tests/expresslog/AndroidManifest.xml | 29 | ||||
-rw-r--r-- | core/tests/expresslog/OWNERS | 3 | ||||
-rw-r--r-- | core/tests/expresslog/TEST_MAPPING | 12 | ||||
-rw-r--r-- | core/tests/expresslog/src/com/android/internal/expresslog/UniformOptionsTest.java | 133 |
7 files changed, 343 insertions, 0 deletions
diff --git a/core/java/com/android/internal/expresslog/Histogram.java b/core/java/com/android/internal/expresslog/Histogram.java new file mode 100644 index 000000000000..fe950c4c2932 --- /dev/null +++ b/core/java/com/android/internal/expresslog/Histogram.java @@ -0,0 +1,107 @@ +/* + * 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; + +/** CounterHistogram encapsulates StatsD write API calls */ +public final class Histogram { + + private final long mMetricIdHash; + private final BinOptions mBinOptions; + + public Histogram(@NonNull String metricId, @NonNull BinOptions binOptions) { + mMetricIdHash = Utils.hashString(metricId); + mBinOptions = binOptions; + } + + /** + * Logs increment sample count for automatically calculated bin + * + * @hide + */ + public void logSample(float sample) { + final int binIndex = mBinOptions.getBinForSample(sample); + FrameworkStatsLog.write(FrameworkStatsLog.EXPRESS_HISTOGRAM_SAMPLE_REPORTED, mMetricIdHash, + /*count*/ 1, binIndex); + } + + /** Used by CounterHistogram to map data sample to corresponding bin */ + public interface BinOptions { + /** + * Returns bins count to be used by counter histogram + * + * @return bins count used to initialize Options, including overflow & underflow bins + * @hide + */ + int getBinsCount(); + + /** + * @return zero based index + * Calculates bin index for the input sample value + * index == 0 stands for underflow + * index == getBinsCount() - 1 stands for overflow + * @hide + */ + int getBinForSample(float sample); + } + + /** Used by CounterHistogram to map data sample to corresponding bin for on 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; + + public UniformOptions(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 undeflow & 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); + } + } +} diff --git a/core/java/com/android/internal/expresslog/TEST_MAPPING b/core/java/com/android/internal/expresslog/TEST_MAPPING new file mode 100644 index 000000000000..c9b0cf80a1e6 --- /dev/null +++ b/core/java/com/android/internal/expresslog/TEST_MAPPING @@ -0,0 +1,12 @@ +{ + "presubmit": [ + { + "name": "ExpressLogTests", + "options": [ + { + "exclude-annotation": "org.junit.Ignore" + } + ] + } + ] +}
\ No newline at end of file diff --git a/core/tests/expresslog/Android.bp b/core/tests/expresslog/Android.bp new file mode 100644 index 000000000000..cab49a76a734 --- /dev/null +++ b/core/tests/expresslog/Android.bp @@ -0,0 +1,47 @@ +// 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", +} diff --git a/core/tests/expresslog/AndroidManifest.xml b/core/tests/expresslog/AndroidManifest.xml new file mode 100644 index 000000000000..94a39e06c974 --- /dev/null +++ b/core/tests/expresslog/AndroidManifest.xml @@ -0,0 +1,29 @@ +<?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> diff --git a/core/tests/expresslog/OWNERS b/core/tests/expresslog/OWNERS new file mode 100644 index 000000000000..3dc958b07f9c --- /dev/null +++ b/core/tests/expresslog/OWNERS @@ -0,0 +1,3 @@ +# Bug component: 719316 +# Stats/expresslog +file:/services/core/java/com/android/server/stats/OWNERS diff --git a/core/tests/expresslog/TEST_MAPPING b/core/tests/expresslog/TEST_MAPPING new file mode 100644 index 000000000000..c9b0cf80a1e6 --- /dev/null +++ b/core/tests/expresslog/TEST_MAPPING @@ -0,0 +1,12 @@ +{ + "presubmit": [ + { + "name": "ExpressLogTests", + "options": [ + { + "exclude-annotation": "org.junit.Ignore" + } + ] + } + ] +}
\ No newline at end of file diff --git a/core/tests/expresslog/src/com/android/internal/expresslog/UniformOptionsTest.java b/core/tests/expresslog/src/com/android/internal/expresslog/UniformOptionsTest.java new file mode 100644 index 000000000000..9fa6d0634fbe --- /dev/null +++ b/core/tests/expresslog/src/com/android/internal/expresslog/UniformOptionsTest.java @@ -0,0 +1,133 @@ +/* + * 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) +public class UniformOptionsTest { + private static final String TAG = UniformOptionsTest.class.getSimpleName(); + + @Test + @SmallTest + 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) + @SmallTest + public void testConstructZeroBinsCount() { + new Histogram.UniformOptions(0, 100, 1000); + } + + @Test(expected = IllegalArgumentException.class) + @SmallTest + public void testConstructNegativeBinsCount() { + new Histogram.UniformOptions(-1, 100, 1000); + } + + @Test(expected = IllegalArgumentException.class) + @SmallTest + public void testConstructMaxValueLessThanMinValue() { + new Histogram.UniformOptions(10, 1000, 100); + } + + @Test + @SmallTest + 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 + @SmallTest + 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 + @SmallTest + 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 + @SmallTest + 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 + @SmallTest + 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)); + } + } +} |