-
-
Notifications
You must be signed in to change notification settings - Fork 444
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix slow and frozen frames tracking #2271
Changes from 4 commits
343ada1
6044b4c
2f4462c
f6b0dc7
4f2ca28
8cab3eb
391ea57
5b7f10b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
@@ -10,6 +10,7 @@ | |||||||||
import io.sentry.protocol.SentryId; | ||||||||||
import java.util.HashMap; | ||||||||||
import java.util.Map; | ||||||||||
import java.util.WeakHashMap; | ||||||||||
import java.util.concurrent.ConcurrentHashMap; | ||||||||||
import org.jetbrains.annotations.NotNull; | ||||||||||
import org.jetbrains.annotations.Nullable; | ||||||||||
|
@@ -27,6 +28,8 @@ public final class ActivityFramesTracker { | |||||||||
|
||||||||||
private final @NotNull Map<SentryId, Map<String, @NotNull MeasurementValue>> | ||||||||||
activityMeasurements = new ConcurrentHashMap<>(); | ||||||||||
private final @NotNull Map<Activity, FrameCounts> frameCountAtStartSnapshots = | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I like the name 👏 |
||||||||||
new WeakHashMap<>(); | ||||||||||
|
||||||||||
public ActivityFramesTracker(final @NotNull LoadClass loadClass, final @Nullable ILogger logger) { | ||||||||||
androidXAvailable = | ||||||||||
|
@@ -55,33 +58,50 @@ public synchronized void addActivity(final @NotNull Activity activity) { | |||||||||
return; | ||||||||||
} | ||||||||||
frameMetricsAggregator.add(activity); | ||||||||||
snapshotFrameCountsAtStart(activity); | ||||||||||
} | ||||||||||
|
||||||||||
@SuppressWarnings("NullAway") | ||||||||||
public synchronized void setMetrics( | ||||||||||
final @NotNull Activity activity, final @NotNull SentryId sentryId) { | ||||||||||
private void snapshotFrameCountsAtStart(final @NotNull Activity activity) { | ||||||||||
FrameCounts frameCounts = calculateCurrentFrameCounts(); | ||||||||||
if (frameCounts != null) { | ||||||||||
frameCountAtStartSnapshots.put(activity, frameCounts); | ||||||||||
} | ||||||||||
} | ||||||||||
|
||||||||||
private @Nullable FrameCounts diffFrameCountsAtEnd(final @NotNull Activity activity) { | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks, forgot to reorder them |
||||||||||
@Nullable | ||||||||||
final FrameCounts frameCountsAtStartFromMap = frameCountAtStartSnapshots.remove(activity); | ||||||||||
@NotNull | ||||||||||
final FrameCounts frameCountsAtStart = | ||||||||||
frameCountsAtStartFromMap == null ? new FrameCounts(0, 0, 0) : frameCountsAtStartFromMap; | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Lines 169 to 172 in f6b0dc7
The parameter is also annotated @NotNull . If this happens, something is wrong and I think we should better not count the frames at all and return null here. If we use FrameCounts(0, 0, 0) , I think we risk calculating incorrect frame counts.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My idea here was that we might not be able to determine frame counts if the |
||||||||||
|
||||||||||
@Nullable final FrameCounts frameCountsAtEnd = calculateCurrentFrameCounts(); | ||||||||||
if (frameCountsAtEnd == null) { | ||||||||||
return null; | ||||||||||
} | ||||||||||
|
||||||||||
final int diffTotalFrames = frameCountsAtEnd.totalFrames - frameCountsAtStart.totalFrames; | ||||||||||
final int diffSlowFrames = frameCountsAtEnd.slowFrames - frameCountsAtStart.slowFrames; | ||||||||||
final int diffFrozenFrames = frameCountsAtEnd.frozenFrames - frameCountsAtStart.frozenFrames; | ||||||||||
|
||||||||||
return new FrameCounts(diffTotalFrames, diffSlowFrames, diffFrozenFrames); | ||||||||||
} | ||||||||||
|
||||||||||
private @Nullable FrameCounts calculateCurrentFrameCounts() { | ||||||||||
if (!isFrameMetricsAggregatorAvailable()) { | ||||||||||
return; | ||||||||||
return null; | ||||||||||
} | ||||||||||
|
||||||||||
if (frameMetricsAggregator == null) { | ||||||||||
return null; | ||||||||||
} | ||||||||||
final @Nullable SparseIntArray[] framesRates = frameMetricsAggregator.getMetrics(); | ||||||||||
|
||||||||||
int totalFrames = 0; | ||||||||||
int slowFrames = 0; | ||||||||||
int frozenFrames = 0; | ||||||||||
|
||||||||||
SparseIntArray[] framesRates = null; | ||||||||||
try { | ||||||||||
framesRates = frameMetricsAggregator.remove(activity); | ||||||||||
} catch (Throwable ignored) { | ||||||||||
// throws IllegalArgumentException when attempting to remove OnFrameMetricsAvailableListener | ||||||||||
// that was never added. | ||||||||||
// there's no contains method. | ||||||||||
// throws NullPointerException when attempting to remove OnFrameMetricsAvailableListener and | ||||||||||
// there was no | ||||||||||
// Observers, See | ||||||||||
// https://android.googlesource.com/platform/frameworks/base/+/140ff5ea8e2d99edc3fbe63a43239e459334c76b | ||||||||||
} | ||||||||||
|
||||||||||
if (framesRates != null) { | ||||||||||
if (framesRates != null && framesRates.length > 0) { | ||||||||||
final SparseIntArray totalIndexArray = framesRates[FrameMetricsAggregator.TOTAL_INDEX]; | ||||||||||
if (totalIndexArray != null) { | ||||||||||
for (int i = 0; i < totalIndexArray.size(); i++) { | ||||||||||
|
@@ -100,13 +120,53 @@ public synchronized void setMetrics( | |||||||||
} | ||||||||||
} | ||||||||||
|
||||||||||
if (totalFrames == 0 && slowFrames == 0 && frozenFrames == 0) { | ||||||||||
return new FrameCounts(totalFrames, slowFrames, frozenFrames); | ||||||||||
} | ||||||||||
|
||||||||||
private static final class FrameCounts { | ||||||||||
private final int totalFrames; | ||||||||||
private final int slowFrames; | ||||||||||
private final int frozenFrames; | ||||||||||
|
||||||||||
private FrameCounts(final int totalFrames, final int slowFrames, final int frozenFrames) { | ||||||||||
this.totalFrames = totalFrames; | ||||||||||
this.slowFrames = slowFrames; | ||||||||||
this.frozenFrames = frozenFrames; | ||||||||||
} | ||||||||||
} | ||||||||||
|
||||||||||
@SuppressWarnings("NullAway") | ||||||||||
public synchronized void setMetrics( | ||||||||||
final @NotNull Activity activity, final @NotNull SentryId sentryId) { | ||||||||||
adinauer marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||
if (!isFrameMetricsAggregatorAvailable()) { | ||||||||||
return; | ||||||||||
} | ||||||||||
|
||||||||||
try { | ||||||||||
// NOTE: removing an activity does not reset the frame counts, only reset() does | ||||||||||
frameMetricsAggregator.remove(activity); | ||||||||||
} catch (Throwable ignored) { | ||||||||||
// throws IllegalArgumentException when attempting to remove OnFrameMetricsAvailableListener | ||||||||||
// that was never added. | ||||||||||
// there's no contains method. | ||||||||||
// throws NullPointerException when attempting to remove OnFrameMetricsAvailableListener and | ||||||||||
// there was no | ||||||||||
// Observers, See | ||||||||||
// https://android.googlesource.com/platform/frameworks/base/+/140ff5ea8e2d99edc3fbe63a43239e459334c76b | ||||||||||
} | ||||||||||
|
||||||||||
final @Nullable FrameCounts frameCounts = diffFrameCountsAtEnd(activity); | ||||||||||
|
||||||||||
if (frameCounts == null | ||||||||||
|| (frameCounts.totalFrames == 0 | ||||||||||
&& frameCounts.slowFrames == 0 | ||||||||||
&& frameCounts.frozenFrames == 0)) { | ||||||||||
return; | ||||||||||
} | ||||||||||
|
||||||||||
final MeasurementValue tfValues = new MeasurementValue(totalFrames, NONE_UNIT); | ||||||||||
final MeasurementValue sfValues = new MeasurementValue(slowFrames, NONE_UNIT); | ||||||||||
final MeasurementValue ffValues = new MeasurementValue(frozenFrames, NONE_UNIT); | ||||||||||
final MeasurementValue tfValues = new MeasurementValue(frameCounts.totalFrames, NONE_UNIT); | ||||||||||
final MeasurementValue sfValues = new MeasurementValue(frameCounts.slowFrames, NONE_UNIT); | ||||||||||
final MeasurementValue ffValues = new MeasurementValue(frameCounts.frozenFrames, NONE_UNIT); | ||||||||||
final Map<String, @NotNull MeasurementValue> measurements = new HashMap<>(); | ||||||||||
measurements.put("frames_total", tfValues); | ||||||||||
measurements.put("frames_slow", sfValues); | ||||||||||
|
@@ -132,6 +192,7 @@ public synchronized void setMetrics( | |||||||||
public synchronized void stop() { | ||||||||||
if (isFrameMetricsAggregatorAvailable()) { | ||||||||||
frameMetricsAggregator.stop(); | ||||||||||
frameMetricsAggregator.reset(); | ||||||||||
} | ||||||||||
activityMeasurements.clear(); | ||||||||||
} | ||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@marandaneto since no public API changes were necessary I assume this fix doesn't require any further action on hybrid SDKs.