Merge "Use PerfettoTrigger to trigger traces from LatencyTracker" into sc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
81ed6656ba
@@ -59,6 +59,7 @@ import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.jank.FrameTracker.FrameMetricsWrapper;
|
||||
import com.android.internal.jank.FrameTracker.ThreadedRendererWrapper;
|
||||
import com.android.internal.jank.FrameTracker.ViewRootWrapper;
|
||||
import com.android.internal.util.PerfettoTrigger;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.
|
||||
*/
|
||||
|
||||
//TODO (165884885): Make PerfettoTrigger more generic and move it to another package.
|
||||
package com.android.internal.jank;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
|
||||
/**
|
||||
* A trigger implementation with perfetto backend.
|
||||
* @hide
|
||||
*/
|
||||
public class PerfettoTrigger {
|
||||
private static final String TAG = PerfettoTrigger.class.getSimpleName();
|
||||
private static final boolean DEBUG = false;
|
||||
private static final String TRIGGER_COMMAND = "/system/bin/trigger_perfetto";
|
||||
|
||||
/**
|
||||
* @param triggerName The name of the trigger. Must match the value defined in the AOT
|
||||
* Perfetto config.
|
||||
*/
|
||||
public static void trigger(String triggerName) {
|
||||
try {
|
||||
ProcessBuilder pb = new ProcessBuilder(TRIGGER_COMMAND, triggerName);
|
||||
if (DEBUG) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (String arg : pb.command()) {
|
||||
sb.append(arg).append(" ");
|
||||
}
|
||||
Log.d(TAG, "Triggering " + sb.toString());
|
||||
}
|
||||
Process process = pb.start();
|
||||
if (DEBUG) {
|
||||
readConsoleOutput(process);
|
||||
}
|
||||
} catch (IOException | InterruptedException e) {
|
||||
Log.w(TAG, "Failed to trigger " + triggerName, e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void readConsoleOutput(@NonNull Process process)
|
||||
throws IOException, InterruptedException {
|
||||
process.waitFor();
|
||||
try (BufferedReader errReader =
|
||||
new BufferedReader(new InputStreamReader(process.getErrorStream()))) {
|
||||
StringBuilder errLine = new StringBuilder();
|
||||
String line;
|
||||
while ((line = errReader.readLine()) != null) {
|
||||
errLine.append(line).append("\n");
|
||||
}
|
||||
errLine.append(", code=").append(process.exitValue());
|
||||
Log.d(TAG, "err message=" + errLine.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
package com.android.internal.util;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.os.SystemClock;
|
||||
@@ -23,9 +24,12 @@ import android.util.EventLog;
|
||||
import android.util.Log;
|
||||
import android.util.SparseLongArray;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.logging.EventLogTags;
|
||||
import com.android.internal.os.BackgroundThread;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
/**
|
||||
@@ -91,6 +95,34 @@ public class LatencyTracker {
|
||||
*/
|
||||
public static final int ACTION_START_RECENTS_ANIMATION = 8;
|
||||
|
||||
private static final int[] ACTIONS_ALL = {
|
||||
ACTION_EXPAND_PANEL,
|
||||
ACTION_TOGGLE_RECENTS,
|
||||
ACTION_FINGERPRINT_WAKE_AND_UNLOCK,
|
||||
ACTION_CHECK_CREDENTIAL,
|
||||
ACTION_CHECK_CREDENTIAL_UNLOCKED,
|
||||
ACTION_TURN_ON_SCREEN,
|
||||
ACTION_ROTATE_SCREEN,
|
||||
ACTION_FACE_WAKE_AND_UNLOCK,
|
||||
ACTION_START_RECENTS_ANIMATION
|
||||
};
|
||||
|
||||
/** @hide */
|
||||
@IntDef({
|
||||
ACTION_EXPAND_PANEL,
|
||||
ACTION_TOGGLE_RECENTS,
|
||||
ACTION_FINGERPRINT_WAKE_AND_UNLOCK,
|
||||
ACTION_CHECK_CREDENTIAL,
|
||||
ACTION_CHECK_CREDENTIAL_UNLOCKED,
|
||||
ACTION_TURN_ON_SCREEN,
|
||||
ACTION_ROTATE_SCREEN,
|
||||
ACTION_FACE_WAKE_AND_UNLOCK,
|
||||
ACTION_START_RECENTS_ANIMATION
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface Action {
|
||||
}
|
||||
|
||||
private static final int[] STATSD_ACTION = new int[]{
|
||||
FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_EXPAND_PANEL,
|
||||
FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_TOGGLE_RECENTS,
|
||||
@@ -105,9 +137,14 @@ public class LatencyTracker {
|
||||
|
||||
private static LatencyTracker sLatencyTracker;
|
||||
|
||||
private final Object mLock = new Object();
|
||||
private final SparseLongArray mStartRtc = new SparseLongArray();
|
||||
private volatile int mSamplingInterval;
|
||||
private volatile boolean mEnabled;
|
||||
@GuardedBy("mLock")
|
||||
private final int[] mTraceThresholdPerAction = new int[ACTIONS_ALL.length];
|
||||
@GuardedBy("mLock")
|
||||
private int mSamplingInterval;
|
||||
@GuardedBy("mLock")
|
||||
private boolean mEnabled;
|
||||
|
||||
public static LatencyTracker getInstance(Context context) {
|
||||
if (sLatencyTracker == null) {
|
||||
@@ -132,20 +169,26 @@ public class LatencyTracker {
|
||||
}
|
||||
|
||||
private void updateProperties(DeviceConfig.Properties properties) {
|
||||
mSamplingInterval = properties.getInt(SETTINGS_SAMPLING_INTERVAL_KEY,
|
||||
DEFAULT_SAMPLING_INTERVAL);
|
||||
mEnabled = properties.getBoolean(SETTINGS_ENABLED_KEY, DEFAULT_ENABLED);
|
||||
synchronized (mLock) {
|
||||
mSamplingInterval = properties.getInt(SETTINGS_SAMPLING_INTERVAL_KEY,
|
||||
DEFAULT_SAMPLING_INTERVAL);
|
||||
mEnabled = properties.getBoolean(SETTINGS_ENABLED_KEY, DEFAULT_ENABLED);
|
||||
for (int action : ACTIONS_ALL) {
|
||||
mTraceThresholdPerAction[action] =
|
||||
properties.getInt(getTraceTriggerNameForAction(action), -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper method to translate action type to name.
|
||||
*
|
||||
* @param action the action type defined in AtomsProto.java
|
||||
* @param atomsProtoAction the action type defined in AtomsProto.java
|
||||
* @return the name of the action
|
||||
*/
|
||||
public static String getNameOfAction(int action) {
|
||||
public static String getNameOfAction(int atomsProtoAction) {
|
||||
// Defined in AtomsProto.java
|
||||
switch (action) {
|
||||
switch (atomsProtoAction) {
|
||||
case 0:
|
||||
return "UNKNOWN";
|
||||
case 1:
|
||||
@@ -171,16 +214,22 @@ public class LatencyTracker {
|
||||
}
|
||||
}
|
||||
|
||||
private static String getTraceNameOfAction(int action) {
|
||||
private static String getTraceNameOfAction(@Action int action) {
|
||||
return "L<" + getNameOfAction(STATSD_ACTION[action]) + ">";
|
||||
}
|
||||
|
||||
private static String getTraceTriggerNameForAction(@Action int action) {
|
||||
return "latency-tracker-" + getNameOfAction(STATSD_ACTION[action]);
|
||||
}
|
||||
|
||||
public static boolean isEnabled(Context ctx) {
|
||||
return getInstance(ctx).isEnabled();
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return mEnabled;
|
||||
synchronized (mLock) {
|
||||
return mEnabled;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -188,7 +237,7 @@ public class LatencyTracker {
|
||||
*
|
||||
* @param action The action to start. One of the ACTION_* values.
|
||||
*/
|
||||
public void onActionStart(int action) {
|
||||
public void onActionStart(@Action int action) {
|
||||
if (!isEnabled()) {
|
||||
return;
|
||||
}
|
||||
@@ -201,7 +250,7 @@ public class LatencyTracker {
|
||||
*
|
||||
* @param action The action to end. One of the ACTION_* values.
|
||||
*/
|
||||
public void onActionEnd(int action) {
|
||||
public void onActionEnd(@Action int action) {
|
||||
if (!isEnabled()) {
|
||||
return;
|
||||
}
|
||||
@@ -221,19 +270,30 @@ public class LatencyTracker {
|
||||
* @param action The action to end. One of the ACTION_* values.
|
||||
* @param duration The duration of the action in ms.
|
||||
*/
|
||||
public void logAction(int action, int duration) {
|
||||
boolean shouldSample = ThreadLocalRandom.current().nextInt() % mSamplingInterval == 0;
|
||||
public void logAction(@Action int action, int duration) {
|
||||
boolean shouldSample;
|
||||
int traceThreshold;
|
||||
synchronized (mLock) {
|
||||
shouldSample = ThreadLocalRandom.current().nextInt() % mSamplingInterval == 0;
|
||||
traceThreshold = mTraceThresholdPerAction[action];
|
||||
}
|
||||
|
||||
if (traceThreshold > 0 && duration >= traceThreshold) {
|
||||
PerfettoTrigger.trigger(getTraceTriggerNameForAction(action));
|
||||
}
|
||||
|
||||
logActionDeprecated(action, duration, shouldSample);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs an action that has started and ended. This needs to be called from the main thread.
|
||||
*
|
||||
* @param action The action to end. One of the ACTION_* values.
|
||||
* @param duration The duration of the action in ms.
|
||||
* @param action The action to end. One of the ACTION_* values.
|
||||
* @param duration The duration of the action in ms.
|
||||
* @param writeToStatsLog Whether to write the measured latency to FrameworkStatsLog.
|
||||
*/
|
||||
public static void logActionDeprecated(int action, int duration, boolean writeToStatsLog) {
|
||||
public static void logActionDeprecated(
|
||||
@Action int action, int duration, boolean writeToStatsLog) {
|
||||
Log.i(TAG, getNameOfAction(STATSD_ACTION[action]) + " latency=" + duration);
|
||||
EventLog.writeEvent(EventLogTags.SYSUI_LATENCY, action, duration);
|
||||
|
||||
|
||||
44
core/java/com/android/internal/util/PerfettoTrigger.java
Normal file
44
core/java/com/android/internal/util/PerfettoTrigger.java
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.util;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* A trigger implementation with perfetto backend.
|
||||
* @hide
|
||||
*/
|
||||
public class PerfettoTrigger {
|
||||
private static final String TAG = "PerfettoTrigger";
|
||||
private static final String TRIGGER_COMMAND = "/system/bin/trigger_perfetto";
|
||||
|
||||
/**
|
||||
* @param triggerName The name of the trigger. Must match the value defined in the AOT
|
||||
* Perfetto config.
|
||||
*/
|
||||
public static void trigger(String triggerName) {
|
||||
try {
|
||||
ProcessBuilder pb = new ProcessBuilder(TRIGGER_COMMAND, triggerName);
|
||||
Log.v(TAG, "Triggering " + String.join(" ", pb.command()));
|
||||
Process process = pb.start();
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, "Failed to trigger " + triggerName, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user