Skip to content

Pre-construct TagMap.Entry objects in InternalTagsAdder#11555

Open
dougqh wants to merge 2 commits into
masterfrom
dougqh/preconstruct-internal-tags
Open

Pre-construct TagMap.Entry objects in InternalTagsAdder#11555
dougqh wants to merge 2 commits into
masterfrom
dougqh/preconstruct-internal-tags

Conversation

@dougqh
Copy link
Copy Markdown
Contributor

@dougqh dougqh commented Jun 4, 2026

What This Does

InternalTagsAdder sets _dd.base_service / version on spans via TagMap.set(tag, value), which allocates a fresh TagMap.Entry per span. Both values are fixed for the life of the tracer, and TagMap.Entry objects are explicitly safe to share across maps (the OptimizedTagMap collision design via BucketGroup relies on it). This pre-builds the two Entry objects once in the constructor and reuses them via set(entry).

Motivation

A JFR allocation profile of spring-petclinic under load (full agent, 2026-06-03) attributed ~52 allocation samples to InternalTagsAdder.processTags — one Entry allocated per span for base.service. Tag-map handling (TagMap$Entry + OptimizedTagMap) was the single largest non-core tracer allocation theme in that profile, ahead of the CSS metrics system. This change drops the InternalTagsAdder contribution to zero.

Notes

  • Re-applies the logic from Reuse TagMap.Entry objects in InternalTagsAdder #10965 (dd/pre-construct-tagmap-entries), which had drifted 415 commits behind master and changed processTags's signature; this version sits on current master with the unchanged AppendableSpanLinks signature. Supersedes Reuse TagMap.Entry objects in InternalTagsAdder #10965.
  • Behavior preserved: Entry.stringValue() for the OBJECT entry resolves to obj.toString() (cached), identical to the prior ddService.toString() in the equalsIgnoreCase comparison. The only edge case — empty ddService now yields an early return — is unreachable in production (Config.getServiceName() is never "").
  • Existing test InternalTagsAdderTest.groovy passes unchanged.

🤖 Generated with Claude Code

InternalTagsAdder set base.service / version via TagMap.set(tag, value),
allocating a fresh TagMap.Entry per span. Both values are fixed for the
life of the tracer, and TagMap.Entry objects are safe to share across maps
(the OptimizedTagMap collision design relies on it), so build the two
Entry objects once in the constructor and reuse them via set(entry).

A JFR profile of petclinic (2026-06-03) attributed ~52 allocation samples
to InternalTagsAdder.processTags (one Entry per span); this drops them to
zero. Re-applies the change from the stale PR #10965 (415 commits behind
master, drifted signature) onto current master.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@dougqh dougqh marked this pull request as ready for review June 4, 2026 00:14
@dougqh dougqh requested a review from a team as a code owner June 4, 2026 00:14
@dougqh dougqh requested a review from ygree June 4, 2026 00:14
@dd-octo-sts dd-octo-sts Bot added the tag: ai generated Largely based on code generated by an AI or LLM label Jun 4, 2026
@dd-octo-sts
Copy link
Copy Markdown
Contributor

dd-octo-sts Bot commented Jun 4, 2026

Hi! 👋 Thanks for your pull request! 🎉

To help us review it, please make sure to:

  • Add at least one type, and one component or instrumentation label to the pull request

If you need help, please check our contributing guidelines.

@datadog-datadog-prod-us1-2
Copy link
Copy Markdown
Contributor

datadog-datadog-prod-us1-2 Bot commented Jun 4, 2026

Pipelines

Fix all issues with BitsAI

⚠️ Warnings

🚦 2 Pipeline jobs failed

Run system tests | Check system tests success   View in Datadog   GitHub Actions

Run system tests | main / End-to-end #3 / uds-spring-boot 3   View in Datadog   GitHub Actions

See error Error pulling Docker image 'mcr.microsoft.com/mssql/server': access denied or repository does not exist. Ensure you are logged in.

Useful? React with 👍 / 👎

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: f5f5cc9 | Docs | Datadog PR Page | Give us feedback!

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 934fd5dc3b

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

this.version = version != null && !version.isEmpty() ? UTF8BytesString.create(version) : null;
this.baseServiceEntry =
ddService != null
? TagMap.Entry.create(DDTags.BASE_SERVICE, UTF8BytesString.create(ddService))
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve version handling for empty DD_SERVICE

When DD_SERVICE is explicitly set to an empty string, this now becomes null because TagMap.Entry.create(String, CharSequence) returns null for empty values, while Config can still pass through an empty configured service name from the config provider. In that scenario a span whose service name is also empty used to reach the version branch and add DD_VERSION, but the new baseServiceEntry == null guard exits before versionEntry is considered, silently dropping the version tag for that configuration.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good catch — fixed in f5f5cc9. The constructor now keeps a separate ddService UTF8BytesString handle that drives both the early-return guard and the case-insensitive service-name comparison (independent of whether baseServiceEntry was prebuilt). For the empty-DD_SERVICE case, Entry.create still returns null, so the base.service branch falls back to unsafeTags.set(BASE_SERVICE, ddService) — preserving byte-identical behavior — and crucially the version branch is still reached when the span's service name also matches the empty configured service.

I added regression coverage in the migrated InternalTagsAdderTest (now JUnit 5): new InternalTagsAdder("", "1.0") with an empty span service still adds version 1.0, and with a non-empty span service it takes the base.service branch and adds no version.

(Reply by Claude)

@dougqh dougqh added comp: core Tracer core type: enhancement Enhancements and improvements tag: performance Performance related changes labels Jun 4, 2026
Addresses the Codex review comment on #11555: pre-building the
base.service Entry must not change behavior for an explicitly-empty
DD_SERVICE. Entry.create rejects empty values, so baseServiceEntry is
null in that case; the processTags branch now falls back to
set(BASE_SERVICE, ddService) to preserve byte-identical behavior, and
the version branch is still reached when the span service also matches
the empty configured service.

Migrate InternalTagsAdderTest from Groovy/Spock to JUnit 5 (parameterized
with @MethodSource) and add regression coverage for the empty-DD_SERVICE
case (9 migrated cases + 2 new = 11).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@dd-octo-sts
Copy link
Copy Markdown
Contributor

dd-octo-sts Bot commented Jun 4, 2026

🟢 Java Benchmark SLOs — All performance SLOs passed

Suite Status
Startup 🟢 pass

SLO thresholds are defined here based on automatically generated metrics. A warning is raised when results are within 5% of the threshold.

PR vs. master results
Scenario Candidate master Δ (95% CI of mean)
startup:insecure-bank:iast:Agent 13.98 s 13.89 s [-0.4%; +1.7%] (no difference)
startup:insecure-bank:tracing:Agent 12.89 s 12.96 s [-1.4%; +0.3%] (no difference)
startup:petclinic:appsec:Agent 16.96 s 16.97 s [-1.3%; +1.1%] (no difference)
startup:petclinic:iast:Agent 16.94 s 16.27 s [-4.8%; +13.1%] (unstable)
startup:petclinic:profiling:Agent 17.07 s 16.29 s [-4.3%; +13.9%] (unstable)
startup:petclinic:tracing:Agent 16.16 s 16.34 s [-2.6%; +0.5%] (no difference)

Commit: f5f5cc90 · CI Pipeline · Benchmarking Platform UI


Load and DaCapo benchmarks can be triggered manually in the GitLab pipeline. Results will appear in the Benchmarking Platform UI after completion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp: core Tracer core tag: ai generated Largely based on code generated by an AI or LLM tag: performance Performance related changes type: enhancement Enhancements and improvements

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant