summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Vova Sharaienko <sharaienko@google.com> 2023-02-07 09:59:08 +0000
committer Gerrit Code Review <noreply-gerritcodereview@google.com> 2023-02-07 09:59:08 +0000
commitbb0845d30a38194f82d582cd512eb68a74e294f5 (patch)
tree5ca98c5b0d35f3680a40c8bd990cdb50404171af
parent24db27017f6d21e8faf8c53926182d776ecf277e (diff)
parente19dbb30532a107cfd9b4e9e83b82bb1b9d4d9f1 (diff)
Merge "[TeX] Introduced Telemetry Express Histogram Logging APIs"
-rw-r--r--core/java/com/android/internal/expresslog/Histogram.java107
-rw-r--r--core/java/com/android/internal/expresslog/TEST_MAPPING12
-rw-r--r--core/tests/expresslog/Android.bp47
-rw-r--r--core/tests/expresslog/AndroidManifest.xml29
-rw-r--r--core/tests/expresslog/OWNERS3
-rw-r--r--core/tests/expresslog/TEST_MAPPING12
-rw-r--r--core/tests/expresslog/src/com/android/internal/expresslog/UniformOptionsTest.java133
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));
+ }
+ }
+}