Skip to content
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

Keep baggage sample rate/rand as doubles #4279

Merged

Conversation

markushi
Copy link
Member

@markushi markushi commented Mar 21, 2025

📜 Description

Keeps the rate / rand values as doubles, until being transferred to TraceContext.

💡 Motivation and Context

We seem to be hitting some performance regression with 8.x.x where formatting the sample rate/rand seems to have some impact. I don't trust the profiled app fully, be there seems to be something to it:

Before:
sentry-android-init-8 x x

After:
image

TODO: Check why this even being called 3 times (assuming it's for every scope right now)

💚 How did you test it?

📝 Checklist

  • I added tests to verify the changes.
  • No new PII added or SDK only sends newly added PII if sendDefaultPII is enabled.
  • I updated the docs if needed.
  • I updated the wizard if needed.
  • Review from the native team if needed.
  • No breaking change or entry added to the changelog.
  • No breaking change for hybrid SDKs or communicated to hybrid SDKs.

🔮 Next steps

Copy link
Contributor

github-actions bot commented Mar 21, 2025

Performance metrics 🚀

  Plain With Sentry Diff
Startup time 409.76 ms 484.30 ms 74.54 ms
Size 1.58 MiB 2.22 MiB 652.77 KiB

Previous results on branch: markushi/feat/retain-baggage-sample-rate-rand-as-double

Startup times

Revision Plain With Sentry Diff
2bb10ef 439.64 ms 446.10 ms 6.46 ms
e9d765b 375.22 ms 445.06 ms 69.84 ms
f2b6704 406.86 ms 435.69 ms 28.83 ms
902043e 409.27 ms 486.46 ms 77.19 ms
524a008 464.70 ms 594.53 ms 129.84 ms

App size

Revision Plain With Sentry Diff
2bb10ef 1.58 MiB 2.22 MiB 652.83 KiB
e9d765b 1.58 MiB 2.22 MiB 652.62 KiB
f2b6704 1.58 MiB 2.22 MiB 652.55 KiB
902043e 1.58 MiB 2.22 MiB 652.54 KiB
524a008 1.58 MiB 2.22 MiB 652.84 KiB

@@ -231,8 +261,18 @@ public String getThirdPartyHeader() {
}

final Set<String> keys = new TreeSet<>(keyValues.keySet());
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this is quite hacky, an alternative would be to let keyValues be a Map<String, String|Number> aka Map<String, Object>

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can revisit when more fields need to be added in the future and this current approach gets harder to maintain. I think it's fine for now.

@@ -1076,16 +1093,17 @@ public void setPropagationContext(final @NotNull PropagationContext propagationC
@ApiStatus.Internal
@Override
public @NotNull PropagationContext getPropagationContext() {
return propagationContext;
return propagationContext.getValue();
}

@ApiStatus.Internal
@Override
public @NotNull PropagationContext withPropagationContext(
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the use case of returning a clone of PropagationContext here? As far as I can see we at least internally never seem to use the return type.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To avoid modifications from outside the withPropagationContext block, i.e. misusing this as a getter for modifying the instance.

@markushi markushi marked this pull request as ready for review March 25, 2025 10:28
@@ -231,8 +261,18 @@ public String getThirdPartyHeader() {
}

final Set<String> keys = new TreeSet<>(keyValues.keySet());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can revisit when more fields need to be added in the future and this current approach gets harder to maintain. I think it's fine for now.

@@ -1076,16 +1093,17 @@ public void setPropagationContext(final @NotNull PropagationContext propagationC
@ApiStatus.Internal
@Override
public @NotNull PropagationContext getPropagationContext() {
return propagationContext;
return propagationContext.getValue();
}

@ApiStatus.Internal
@Override
public @NotNull PropagationContext withPropagationContext(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To avoid modifications from outside the withPropagationContext block, i.e. misusing this as a getter for modifying the instance.

@@ -93,7 +94,7 @@ public final class Scope implements IScope {
/** Scope's attachments */
private @NotNull List<Attachment> attachments = new CopyOnWriteArrayList<>();

private @NotNull PropagationContext propagationContext;
private @NotNull LazyEvaluator<PropagationContext> propagationContext;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did we do any performance comparison as to whether this specific part actually improves anything?

Copy link
Member Author

@markushi markushi Mar 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No I didn't, and after sleeping over it I think it's better to revert this specific change: it makes everything less predictable 😅 I'll do a quick test, but I suspect the performance gains to be negligible.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok I did some testing using https://github.com/melix/jmh-gradle-plugin/, it's all within the same ballpark.
This is throughput, so higher values are better.

# Without Lazy
Benchmark                              Mode  Cnt        Score         Error  Units
ScopeBenchmark.ctor                   thrpt    4  4063093,683 ±  185929,301  ops/s
ScopeBenchmark.getPropagationContext  thrpt    4  4283007,711 ± 1670048,430  ops/s

# With Lazy
Benchmark                              Mode  Cnt        Score        Error  Units
ScopeBenchmark.ctor                   thrpt    4  4639302,930 ± 518388,199  ops/s
ScopeBenchmark.getPropagationContext  thrpt    4  3769735,655 ± 102168,937  ops/s

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which ctor did you test there? The Scope(final @NotNull Scope scope) one or the Scope(final @NotNull SentryOptions options) one?

  • Scope(final @NotNull SentryOptions options) should only be used on init
  • Scope(final @NotNull Scope scope) is used by clone very often

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general I'd say, if this has little to no benefit, let's rather keep it simple and avoid LazyEvaluator here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did test Scope(final @NotNull SentryOptions options) so the one being used for init. Here's the code I used for testing. But yeah let's keep it without lazy, the ctor gain is just too small.

markushi and others added 2 commits March 26, 2025 09:21
Co-authored-by: Alexander Dinauer <adinauer@users.noreply.github.com>
@markushi markushi enabled auto-merge (squash) March 26, 2025 11:34
@markushi markushi merged commit 1090788 into main Mar 26, 2025
33 checks passed
@markushi markushi deleted the markushi/feat/retain-baggage-sample-rate-rand-as-double branch March 26, 2025 14:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants