Merge "[TeX] Introduced Telemetry Express Histogram Logging APIs"

This commit is contained in:
Vova Sharaienko
2023-02-07 09:59:08 +00:00
committed by Gerrit Code Review
7 changed files with 343 additions and 0 deletions

View File

@@ -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);
}
}
}

View File

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

View File

@@ -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",
}

View File

@@ -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>

View File

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

View File

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

View File

@@ -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));
}
}
}