Skip to content

Commit

Permalink
feat: Add slow and frozen frames to spans (#3450)
Browse files Browse the repository at this point in the history
Add total, slow, and frozen frame numbers to span data.

Fixes GH-3448

Co-authored-by: Andrew McKnight <[email protected]>
  • Loading branch information
philipphofmann and armcknight authored Dec 5, 2023
1 parent b9a9dca commit ef5821b
Show file tree
Hide file tree
Showing 12 changed files with 230 additions and 25 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## Unreleased

## Features

- Add slow and frozen frames to spans (#3450)

## 8.17.1

### Fixes
Expand Down
2 changes: 1 addition & 1 deletion SentryTestUtils/TestDisplayLinkWrapper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ public class TestDisplayLinkWrapper: SentryDisplayLinkWrapper {
call()
}

public func givenFrames(_ slow: Int, _ frozen: Int, _ normal: Int) {
public func renderFrames(_ slow: Int, _ frozen: Int, _ normal: Int) {
self.call()

for _ in 0..<slow {
Expand Down
2 changes: 1 addition & 1 deletion Sources/Sentry/SentryBuildAppStartSpans.m
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
origin:SentryTraceOriginAutoAppStart
sampled:tracer.sampled];

return [[SentrySpan alloc] initWithTracer:tracer context:context];
return [[SentrySpan alloc] initWithTracer:tracer context:context framesTracker:nil];
}

NSArray<SentrySpan *> *
Expand Down
10 changes: 10 additions & 0 deletions Sources/Sentry/SentryFramesTracker.m
Original file line number Diff line number Diff line change
Expand Up @@ -242,4 +242,14 @@ - (void)dealloc

@end

BOOL
sentryShouldAddSlowFrozenFramesData(
NSInteger totalFrames, NSInteger slowFrames, NSInteger frozenFrames)
{
BOOL allBiggerThanOrEqualToZero = totalFrames >= 0 && slowFrames >= 0 && frozenFrames >= 0;
BOOL oneBiggerThanZero = totalFrames > 0 || slowFrames > 0 || frozenFrames > 0;

return allBiggerThanOrEqualToZero && oneBiggerThanZero;
}

#endif // SENTRY_HAS_UIKIT
56 changes: 55 additions & 1 deletion Sources/Sentry/SentrySpan.m
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@
#import "SentryTraceHeader.h"
#import "SentryTracer.h"

#if SENTRY_HAS_UIKIT
# import <SentryFramesTracker.h>
# import <SentryScreenFrames.h>
#endif // SENTRY_HAS_UIKIT

NS_ASSUME_NONNULL_BEGIN

@interface
Expand All @@ -30,9 +35,18 @@ @implementation SentrySpan {
NSMutableDictionary<NSString *, id> *_tags;
NSObject *_stateLock;
BOOL _isFinished;
#if SENTRY_HAS_UIKIT
NSUInteger initTotalFrames;
NSUInteger initSlowFrames;
NSUInteger initFrozenFrames;
SentryFramesTracker *_framesTracker;
#endif // SENTRY_HAS_UIKIT
}

- (instancetype)initWithContext:(SentrySpanContext *)context
#if SENTRY_HAS_UIKIT
framesTracker:(nullable SentryFramesTracker *)framesTracker;
#endif // SENTRY_HAS_UIKIT
{
if (self = [super init]) {
self.startTimestamp = [SentryDependencyContainer.sharedInstance.dateProvider date];
Expand All @@ -43,6 +57,17 @@ - (instancetype)initWithContext:(SentrySpanContext *)context

if ([NSThread isMainThread]) {
_data[SPAN_DATA_THREAD_NAME] = @"main";

#if SENTRY_HAS_UIKIT
// Only track frames if running on main thread.
_framesTracker = framesTracker;
if (_framesTracker.isRunning) {
SentryScreenFrames *currentFrames = _framesTracker.currentFrames;
initTotalFrames = currentFrames.total;
initSlowFrames = currentFrames.slow;
initFrozenFrames = currentFrames.frozen;
}
#endif // SENTRY_HAS_UIKIT
} else {
_data[SPAN_DATA_THREAD_NAME] = [SentryDependencyContainer.sharedInstance.threadInspector
getThreadName:currentThread];
Expand All @@ -64,9 +89,17 @@ - (instancetype)initWithContext:(SentrySpanContext *)context
return self;
}

- (instancetype)initWithTracer:(SentryTracer *)tracer context:(SentrySpanContext *)context
- (instancetype)initWithTracer:(SentryTracer *)tracer
context:(SentrySpanContext *)context
#if SENTRY_HAS_UIKIT
framesTracker:(nullable SentryFramesTracker *)framesTracker
{
if (self = [self initWithContext:context framesTracker:framesTracker]) {
#else
{
if (self = [self initWithContext:context]) {
#endif // SENTRY_HAS_UIKIT

_tracer = tracer;
}
return self;
Expand Down Expand Up @@ -171,6 +204,27 @@ - (void)finishWithStatus:(SentrySpanStatus)status
SENTRY_LOG_DEBUG(@"Setting span timestamp: %@ at system time %llu", self.timestamp,
(unsigned long long)SentryDependencyContainer.sharedInstance.dateProvider.systemTime);
}

#if SENTRY_HAS_UIKIT
if (_framesTracker.isRunning) {

SentryScreenFrames *currentFrames = _framesTracker.currentFrames;
NSInteger totalFrames = currentFrames.total - initTotalFrames;
NSInteger slowFrames = currentFrames.slow - initSlowFrames;
NSInteger frozenFrames = currentFrames.frozen - initFrozenFrames;

if (sentryShouldAddSlowFrozenFramesData(totalFrames, slowFrames, frozenFrames)) {
[self setDataValue:@(totalFrames) forKey:@"frames.total"];
[self setDataValue:@(slowFrames) forKey:@"frames.slow"];
[self setDataValue:@(frozenFrames) forKey:@"frames.frozen"];

SENTRY_LOG_DEBUG(@"Frames for span \"%@\" Total:%ld Slow:%ld Frozen:%ld",
self.operation, (long)totalFrames, (long)slowFrames, (long)frozenFrames);
}
}

#endif // SENTRY_HAS_UIKIT

if (self.tracer == nil) {
SENTRY_LOG_DEBUG(
@"No tracer associated with span with id %@", self.spanId.sentrySpanIdString);
Expand Down
19 changes: 13 additions & 6 deletions Sources/Sentry/SentryTracer.m
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,11 @@ - (instancetype)initWithTransactionContext:(SentryTransactionContext *)transacti
hub:(nullable SentryHub *)hub
configuration:(SentryTracerConfiguration *)configuration;
{
if (!(self = [super initWithContext:transactionContext])) {
if (!(self = [super initWithContext:transactionContext
#if SENTRY_HAS_UIKIT
framesTracker:SentryDependencyContainer.sharedInstance.framesTracker
#endif // SENTRY_HAS_UIKIT
])) {
return nil;
}

Expand Down Expand Up @@ -351,7 +355,13 @@ - (void)cancelDeadlineTimer
spanDescription:description
sampled:self.sampled];

SentrySpan *child = [[SentrySpan alloc] initWithTracer:self context:context];
SentrySpan *child =
[[SentrySpan alloc] initWithTracer:self
context:context
#if SENTRY_HAS_UIKIT
framesTracker:SentryDependencyContainer.sharedInstance.framesTracker
#endif // SENTRY_HAS_UIKIT
];
child.startTimestamp = [SentryDependencyContainer.sharedInstance.dateProvider date];
SENTRY_LOG_DEBUG(@"Started child span %@ under %@", child.spanId.sentrySpanIdString,
parentId.sentrySpanIdString);
Expand Down Expand Up @@ -741,10 +751,7 @@ - (void)addMeasurements:(SentryTransaction *)transaction
NSInteger slowFrames = currentFrames.slow - initSlowFrames;
NSInteger frozenFrames = currentFrames.frozen - initFrozenFrames;

BOOL allBiggerThanZero = totalFrames >= 0 && slowFrames >= 0 && frozenFrames >= 0;
BOOL oneBiggerThanZero = totalFrames > 0 || slowFrames > 0 || frozenFrames > 0;

if (allBiggerThanZero && oneBiggerThanZero) {
if (sentryShouldAddSlowFrozenFramesData(totalFrames, slowFrames, frozenFrames)) {
[self setMeasurement:@"frames_total" value:@(totalFrames)];
[self setMeasurement:@"frames_slow" value:@(slowFrames)];
[self setMeasurement:@"frames_frozen" value:@(frozenFrames)];
Expand Down
3 changes: 3 additions & 0 deletions Sources/Sentry/include/SentryFramesTracker.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ NS_ASSUME_NONNULL_BEGIN

@end

BOOL sentryShouldAddSlowFrozenFramesData(
NSInteger totalFrames, NSInteger slowFrames, NSInteger frozenFrames);

NS_ASSUME_NONNULL_END

#endif // SENTRY_HAS_UIKIT
17 changes: 15 additions & 2 deletions Sources/Sentry/include/SentrySpan.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ NS_ASSUME_NONNULL_BEGIN
@class SentryTracer, SentryId, SentrySpanId, SentryFrame, SentrySpanContext;
@protocol SentrySerializable;

#if SENTRY_HAS_UIKIT
@class SentryFramesTracker;
#endif // SENTRY_HAS_UIKIT

@interface SentrySpan : NSObject <SentrySpan, SentrySerializable>
SENTRY_NO_INIT

Expand Down Expand Up @@ -85,13 +89,22 @@ SENTRY_NO_INIT
* @param transaction The @c SentryTracer managing the transaction this span is associated with.
* @param context This span context information.
*/
- (instancetype)initWithTracer:(SentryTracer *)transaction context:(SentrySpanContext *)context;
- (instancetype)initWithTracer:(SentryTracer *)transaction
context:(SentrySpanContext *)context
#if SENTRY_HAS_UIKIT
framesTracker:(nullable SentryFramesTracker *)framesTracker;
#endif // SENTRY_HAS_UIKIT
;

/**
* Init a @c SentrySpan with given context.
* @param context This span context information.
*/
- (instancetype)initWithContext:(SentrySpanContext *)context;
- (instancetype)initWithContext:(SentrySpanContext *)context
#if SENTRY_HAS_UIKIT
framesTracker:(nullable SentryFramesTracker *)framesTracker;
#endif // SENTRY_HAS_UIKIT
;

- (void)setExtraValue:(nullable id)value forKey:(NSString *)key DEPRECATED_ATTRIBUTE;
@end
Expand Down
2 changes: 1 addition & 1 deletion Tests/SentryTests/PrivateSentrySDKOnlyTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ class PrivateSentrySDKOnlyTests: XCTestCase {
let slow = 2
let frozen = 1
let normal = 100
displayLink.givenFrames(slow, frozen, normal)
displayLink.renderFrames(slow, frozen, normal)

let currentFrames = PrivateSentrySDKOnly.currentScreenFrames
XCTAssertEqual(UInt(slow + frozen + normal), currentFrames.total)
Expand Down
2 changes: 1 addition & 1 deletion Tests/SentryTests/SentryClientTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,7 @@ class SentryClientTest: XCTestCase {
func testCaptureTransactionWithoutScreen() {
SentryDependencyContainer.sharedInstance().application = TestSentryUIApplication()

let event = Transaction(trace: SentryTracer(context: SpanContext(operation: "test")), children: [])
let event = Transaction(trace: SentryTracer(context: SpanContext(operation: "test"), framesTracker: nil), children: [])
fixture.getSut().capture(event: event, scope: fixture.scope)

try? assertLastSentEventWithAttachment { event in
Expand Down
Loading

0 comments on commit ef5821b

Please sign in to comment.