Skip to content

Commit

Permalink
Introduce Wall- and ThreadTimingMetric measuring Wall and Thread time
Browse files Browse the repository at this point in the history
The goal of this change is to unify multiple concurrent attempts to
introduce TimingMetrics measuring Wall and Thread time.

The objective in all cases is same - to use metrics using
try-with-resources technique to measure time taken by a section of
code to execute.

Thread time is useful to evaluate perforomance of the code and drive
optimizations, whereas Wall time is helpful to evaluate what the user
experiences.

Core distinction is that the thread time does not include task
switching, garbage collection or system being under heavy pressure.

Change-Id: Id1c64f9d979df6636e026829915ebe617730a3b1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3614651
Reviewed-by: Peter Conn <peconn@chromium.org>
Reviewed-by: Andrew Grieve <agrieve@chromium.org>
Commit-Queue: Tomasz Wiszkowski <ender@google.com>
Reviewed-by: Ted Choc <tedchoc@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1001251}
  • Loading branch information
tomasz-wiszkowski authored and Chromium LUCI CQ committed May 9, 2022
1 parent c99a5e7 commit 98beb58
Show file tree
Hide file tree
Showing 6 changed files with 145 additions and 49 deletions.
1 change: 1 addition & 0 deletions base/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -4118,6 +4118,7 @@ if (is_android) {
"android/java/src/org/chromium/base/metrics/RecordUserAction.java",
"android/java/src/org/chromium/base/metrics/ScopedSysTraceEvent.java",
"android/java/src/org/chromium/base/metrics/StatisticsRecorderAndroid.java",
"android/java/src/org/chromium/base/metrics/TimingMetric.java",
"android/java/src/org/chromium/base/metrics/UmaRecorder.java",
"android/java/src/org/chromium/base/metrics/UmaRecorderHolder.java",
"android/java/src/org/chromium/base/multidex/ChromiumMultiDexInstaller.java",
Expand Down
125 changes: 125 additions & 0 deletions base/android/java/src/org/chromium/base/metrics/TimingMetric.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
// Copyright 2022 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.chromium.base.metrics;

import android.os.Debug;
import android.os.SystemClock;

import androidx.annotation.IntDef;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
* A class to be used with a try-with-resources to record the elapsed time within the try
* block. Measures time elapsed between instantiation and the call to close using supplied time
* source.
*/
public class TimingMetric implements AutoCloseable {
@IntDef({TimeSource.WALL, TimeSource.THREAD})
@Retention(RetentionPolicy.SOURCE)
@interface TimeSource {
int WALL = 0;
int THREAD = 1;
}

@IntDef({TimeDuration.SHORT, TimeDuration.MEDIUM, TimeDuration.LONG})
@Retention(RetentionPolicy.SOURCE)
@interface TimeDuration {
int SHORT = 0;
int MEDIUM = 1;
int LONG = 2;
}

private final String mMetric;
private final @TimeSource int mTimeSource;
private final @TimeDuration int mTimeDuration;

/**
* When non-0, holds the timestamp of the instantiation time of this object. Value of 0
* indicates canceled or already reported metric.
*/
private long mStartMillis;

/**
* Create a new TimingMetric measuring wall time (ie. time experienced by the User) of up to 3
* minutes.
*
* @param metric The name of the histogram to record.
*/
public static TimingMetric mediumWallTime(String name) {
return new TimingMetric(name, TimeSource.WALL, TimeDuration.MEDIUM);
}

/**
* Create a new TimingMetric measuring thread time (ie. actual time spent executing the code) of
* up to 10 seconds.
*
* @param metric The name of the histogram to record.
*/
public static TimingMetric shortThreadTime(String name) {
return new TimingMetric(name, TimeSource.THREAD, TimeDuration.SHORT);
}

/**
* Construct a new AutoCloseable time measuring metric.
* In most cases the user should defer to one of the static constructors to instantiate this
* class.
*
* @param metric The name of the histogram to record.
* @param timeSource The time source to use.
* @param timeDuration The anticipated duration for this metric.
*/
/* package */ TimingMetric(
String metric, @TimeSource int timeSource, @TimeDuration int timeDuration) {
mMetric = metric;
mTimeSource = timeSource;
mTimeDuration = timeDuration;
mStartMillis = getCurrentTimeMillis();
}

@Override
public void close() {
// If the start time has been cancel, do not record the histogram.
if (mStartMillis == 0) return;
final long measuredTime = getCurrentTimeMillis() - mStartMillis;
mStartMillis = 0;

switch (mTimeDuration) {
case TimeDuration.SHORT:
RecordHistogram.recordTimesHistogram(mMetric, measuredTime);
break;
case TimeDuration.MEDIUM:
RecordHistogram.recordMediumTimesHistogram(mMetric, measuredTime);
break;
case TimeDuration.LONG:
RecordHistogram.recordLongTimesHistogram(mMetric, measuredTime);
break;
}
}

/**
* Cancel the measurement.
*/
public void cancel() {
mStartMillis = 0;
}

/**
* Query the time source associated with this metric for current time.
*
* @return Current time expressed in milliseconds.
*/
private long getCurrentTimeMillis() {
switch (mTimeSource) {
case TimeSource.WALL:
return SystemClock.uptimeMillis();
case TimeSource.THREAD:
return Debug.threadCpuTimeNanos() / 1000000;
}
assert false : "unknown time source requested";
return 0;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import org.chromium.base.ContextUtils;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.NativeMethods;
import org.chromium.base.metrics.TimingMetric;
import org.chromium.base.task.PostTask;
import org.chromium.chrome.browser.browserservices.TrustedWebActivityClient;
import org.chromium.chrome.browser.browserservices.intents.WebappConstants;
Expand Down Expand Up @@ -97,8 +98,8 @@ private static void dispatchLaunch(final int requestId, final boolean incognito,
Context context = ContextUtils.getApplicationContext();

List<ResolveInfo> resolveInfos;
try (BrowserServicesTimingMetrics.TimingMetric t =
BrowserServicesTimingMetrics.getServiceTabResolveInfoTimingContext()) {
try (TimingMetric t = TimingMetric.mediumWallTime(
BrowserServicesTimingMetrics.SERVICE_TAB_RESOLVE_TIME)) {
resolveInfos = WebApkValidator.resolveInfosForUrl(context, url);
}
String webApkPackageName = WebApkValidator.findFirstWebApkPackage(context, resolveInfos);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import android.content.Intent;

import org.chromium.base.Log;
import org.chromium.base.metrics.TimingMetric;
import org.chromium.chrome.browser.ChromeApplicationImpl;
import org.chromium.chrome.browser.browserservices.metrics.BrowserServicesTimingMetrics;
import org.chromium.chrome.browser.browserservices.permissiondelegation.PermissionUpdater;
Expand Down Expand Up @@ -115,8 +116,8 @@ public void onReceive(Context context, Intent intent) {
}
}

try (BrowserServicesTimingMetrics.TimingMetric unused =
BrowserServicesTimingMetrics.getClientAppDataLoadTimingContext()) {
try (TimingMetric unused = TimingMetric.mediumWallTime(
BrowserServicesTimingMetrics.CLIENT_APP_DATA_LOAD_TIME)) {
// The ClientAppDataRegister (because it uses Preferences) is loaded lazily, so to time
// opening the file we must include the first read as well.
if (!mRegister.chromeHoldsDataForPackage(uid)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import org.chromium.base.Log;
import org.chromium.base.PackageManagerUtils;
import org.chromium.base.metrics.TimingMetric;
import org.chromium.chrome.browser.ChromeApplicationImpl;
import org.chromium.chrome.browser.browserservices.metrics.BrowserServicesTimingMetrics;
import org.chromium.components.embedder_support.util.Origin;
Expand Down Expand Up @@ -73,8 +74,8 @@ private boolean appHandlesBrowsableIntent(String packageName, Uri uri) {
browsableIntent.setAction(Intent.ACTION_VIEW);
browsableIntent.addCategory(Intent.CATEGORY_BROWSABLE);

try (BrowserServicesTimingMetrics.TimingMetric unused =
BrowserServicesTimingMetrics.getBrowsableIntentResolutionTimingContext()) {
try (TimingMetric unused = TimingMetric.mediumWallTime(
BrowserServicesTimingMetrics.BROWSABLE_INTENT_RESOLUTION_TIME)) {
return PackageManagerUtils.resolveActivity(browsableIntent, 0) != null;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,61 +4,28 @@

package org.chromium.chrome.browser.browserservices.metrics;

import android.os.SystemClock;

import org.chromium.base.metrics.RecordHistogram;

/**
* Class to contain metrics recording constants and behaviour for Browser Services.
* Data-only class to contain metrics recording constants and behaviour for Browser Services.
*/
public class BrowserServicesTimingMetrics {
/**
* Returns a {@link TimingMetric} that records the amount of time spent querying the Android
* Records a {@link TimingMetric} for the amount of time spent querying the Android
* system for ResolveInfos that will deal with a given URL when launching from a background
* service.
*/
public static TimingMetric getServiceTabResolveInfoTimingContext() {
return new TimingMetric("BrowserServices.ServiceTabResolveInfoQuery");
}
public static final String SERVICE_TAB_RESOLVE_TIME =
"BrowserServices.ServiceTabResolveInfoQuery";

/**
* Returns a {@link TimingMetric} that records the amount of time spent opening the
* Records a {@link WallTimingMetric} for the amount of time spent opening the
* {@link ClientAppDataRegister}.
*/
public static TimingMetric getClientAppDataLoadTimingContext() {
return new TimingMetric("BrowserServices.ClientAppDataLoad");
}

/**
* Returns a {@link TimingMetric} that records the amount of time taken to check if a package
* handles a Browsable intent.
*/
public static TimingMetric getBrowsableIntentResolutionTimingContext() {
return new TimingMetric("BrowserServices.BrowsableIntentCheck");
}
public static final String CLIENT_APP_DATA_LOAD_TIME = "BrowserServices.ClientAppDataLoad";

/**
* A class to be used with a try-with-resources to record the elapsed time within the try block.
* Records a {@link WallTimingMetric} for the amount of time taken to check if a
* package handles a Browsable intent.
*/
public static class TimingMetric implements AutoCloseable {
private final String mMetric;
private final long mStart;

private static long now() {
return SystemClock.uptimeMillis();
}

private TimingMetric(String metric) {
mMetric = metric;
mStart = now();
}

@Override
public void close() {
RecordHistogram.recordMediumTimesHistogram(mMetric, now() - mStart);
}
}

// Don't let anyone instantiate.
private BrowserServicesTimingMetrics() {}
public static final String BROWSABLE_INTENT_RESOLUTION_TIME =
"BrowserServices.BrowsableIntentCheck";
}

0 comments on commit 98beb58

Please sign in to comment.