Skip to content

perf: improve process tags insertion#4010

Merged
dd-mergequeue[bot] merged 17 commits into
mainfrom
raphael/fix_process_tags_spans
Oct 7, 2025
Merged

perf: improve process tags insertion#4010
dd-mergequeue[bot] merged 17 commits into
mainfrom
raphael/fix_process_tags_spans

Conversation

@raphaelgavache

@raphaelgavache raphaelgavache commented Oct 1, 2025

Copy link
Copy Markdown
Member

What does this PR do?

Process tags were set on first span of each chunk instead of first span of first chunk which is what the agent expects. This results in a significant addition of bytes (+25%) for single span chunks with no tags!
The cost was caught by this regression test on the PR that enables process tags by default

Change of behaviour in this PR is to set process tags at the encoding level on the first span of the first chunk

NB Revisited tests to use getMeta/setMeta which are safe reads. They would trigger race conditions on map accesses when process tags are enabled without these changes

Motivation

Reviewer's Checklist

  • Changed code has unit tests for its functionality at or near 100% coverage.
  • System-Tests covering this feature have been added and enabled with the va.b.c-dev version tag.
  • There is a benchmark for any new code, or changes to existing code.
  • If this interacts with the agent in a new way, a system test has been added.
  • New code is free of linting errors. You can check this by running ./scripts/lint.sh locally.
  • Add an appropriate team label so this PR gets put in the right place for the release notes.
  • Non-trivial go.mod changes, e.g. adding new modules, are reviewed by @DataDog/dd-trace-go-guild.

Unsure? Have a question? Request a review!

@raphaelgavache raphaelgavache changed the title improve process tags insertion perf: improve process tags insertion Oct 1, 2025
@raphaelgavache
raphaelgavache force-pushed the raphael/fix_process_tags_spans branch from 7dc6b29 to 8a5339e Compare October 1, 2025 03:09
@pr-commenter

pr-commenter Bot commented Oct 1, 2025

Copy link
Copy Markdown

Benchmarks

Benchmark execution time: 2025-10-06 21:32:54

Comparing candidate commit a5d6611 in PR branch raphael/fix_process_tags_spans with baseline commit c7783df in branch main.

Found 0 performance improvements and 0 performance regressions! Performance is the same for 24 metrics, 0 unstable metrics.

@raphaelgavache
raphaelgavache force-pushed the raphael/fix_process_tags_spans branch from 8a5339e to 17e7345 Compare October 1, 2025 03:12
@datadog-official

datadog-official Bot commented Oct 1, 2025

Copy link
Copy Markdown
Contributor

✅ Tests

🎉 All green!

❄️ No new flaky tests detected
🧪 All tests passed

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: a5d6611 | Docs | Was this helpful? Give us feedback!

@raphaelgavache
raphaelgavache force-pushed the raphael/fix_process_tags_spans branch from 1976f52 to 17e7345 Compare October 1, 2025 03:29
Comment thread ddtrace/tracer/payload.go Outdated
@raphaelgavache
raphaelgavache force-pushed the raphael/fix_process_tags_spans branch from 290b71b to 7769535 Compare October 1, 2025 04:20
@raphaelgavache
raphaelgavache marked this pull request as ready for review October 1, 2025 04:43
@raphaelgavache
raphaelgavache requested review from a team as code owners October 1, 2025 04:43
@raphaelgavache
raphaelgavache force-pushed the raphael/fix_process_tags_spans branch from 328f168 to 28f42b0 Compare October 1, 2025 04:47
Comment thread ddtrace/tracer/payload_test.go Outdated
Comment thread ddtrace/tracer/payload_test.go Outdated
Comment thread ddtrace/tracer/payload_test.go Outdated
Comment thread ddtrace/tracer/payload.go Outdated
Co-authored-by: Rodrigo Argüello <[email protected]>
Comment thread ddtrace/tracer/payload.go Outdated
Comment on lines +141 to +144
shallowCopySpan := *s //nolint:govet // to avoid the copylocks warning, the locks were not used further down
// favoring a copy of all fields to avoid missing one
shallowCopySpan.meta = metaWithProcessTags(s.meta, pTags)
t[i] = &shallowCopySpan

@darccio darccio Oct 1, 2025

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think this is not required. Each unsafePayload function assumes that is under a lock from the same function at safePayload. Did you find race conditions during development?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I did find a race condition on map accesses of span.meta, that should be possible too on the field span.meta when overwriting it, that's why I did the copy.

I'll try to trigger that race on span.meta field

Copy link
Copy Markdown
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 trigger the race on TestSpanProcessTags with -race otpion, you can try it out by removing the shallow copy and running

$ go test -run TestSpanProcessTags -race

==================
WARNING: DATA RACE
Write at 0x00c0000003c8 by goroutine 8263:
  github.com/DataDog/dd-trace-go/v2/ddtrace/tracer.(*unsafePayload).setTracerTags()
      /Users/raphael.gavache/dd/dd-trace-go/ddtrace/tracer/payload.go:141 +0x2bc
  github.com/DataDog/dd-trace-go/v2/ddtrace/tracer.(*unsafePayload).push()
      /Users/raphael.gavache/dd/dd-trace-go/ddtrace/tracer/payload.go:116 +0x40
  github.com/DataDog/dd-trace-go/v2/ddtrace/tracer.(*safePayload).push()
      /Users/raphael.gavache/dd/dd-trace-go/ddtrace/tracer/payload.go:277 +0xa8
  github.com/DataDog/dd-trace-go/v2/ddtrace/tracer.(*agentTraceWriter).add()
      /Users/raphael.gavache/dd/dd-trace-go/ddtrace/tracer/writer.go:74 +0x74
  github.com/DataDog/dd-trace-go/v2/ddtrace/tracer.(*tracer).worker()
      /Users/raphael.gavache/dd/dd-trace-go/ddtrace/tracer/tracer.go:518 +0x22c
  github.com/DataDog/dd-trace-go/v2/ddtrace/tracer.newTracer.func2()
      /Users/raphael.gavache/dd/dd-trace-go/ddtrace/tracer/tracer.go:473 +0x10c

Previous read at 0x00c0000003c8 by goroutine 8248:
  github.com/DataDog/dd-trace-go/v2/ddtrace/tracer.(*concentrator).newTracerStatSpan()
  ...
  ==================
--- FAIL: TestSpanProcessTags (0.02s)
    --- FAIL: TestSpanProcessTags/enabled (0.01s)
        testing.go:1490: race detected during execution of test

@rarguelloF rarguelloF Oct 2, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

what about just using the span mutex?

s.mu.Lock()
s.meta[keyProcessTags] = pTags
s.mu.Unlock()

Given this is only done for the first span in the first chunk, it shouldn't add much lock contention and I think it should be slightly better performance-wise. WDYT? @darccio @raphaelgavache

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

looks good to me, nice call out
I don't know the implications on your side though, as it forces the span.finishes and especially stat computation to be completed before merging. From afar that doesn't seem a problem

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

updated with the lock, all tests pass

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@kakkoyun Could you check this, please? Specially, if you can check this lock with the checklocks tooling, that'd be interesting.

@kakkoyun kakkoyun left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is looking good.

I have only want comment.

Comment thread ddtrace/tracer/payload.go Outdated
Comment thread ddtrace/tracer/payload.go Outdated

@mtoffl01 mtoffl01 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Overall approach LGTM, just some nits.

Also, some feedback on the setTracerTags:

  • setProcessTags may be a better name as its more descriptive/accurate
  • Does it really need to be a method on unsafePayload? It could just take in a []*Span and set tags on the first one in the slice. Then you can move the if atomic.LoadUint32(&p.count) != 0 check to the unsafePayload.push method; if true, you call the set tags method.

I'm holding off on approving until I get confirmation about the Github Actions checks that are failing about the use of atomics 🤔 (reaching out now)

Comment thread ddtrace/tracer/payload.go Outdated
Comment on lines +135 to +137
if len(t) == 0 {
return
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why not move this above line 131? In this case, we can avoid processing lines 131-134 entirely.

// TestPayloadDecode ensures that whatever we push into the payload can
// be decoded by the codec.
func TestPayloadDecode(t *testing.T) {
t.Setenv("DD_EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED", "true")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code quality preference: I'd probably prefer making envProcessTagsEnabled public, and using that here instead of the raw string version.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

this env var will stop being called in the PR that follows where process tags are enabled by default:
#4008
I won't expose it as it will become public and not useful

Comment thread ddtrace/tracer/payload_test.go Outdated
Comment on lines +69 to +73
processtags.Reload()
defer func() {
t.Setenv("DD_EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED", "false")
processtags.Reload()
}()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@raphaelgavache raphaelgavache Oct 6, 2025

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

the reload call changes a global var/state of the process, so if we want this test not to impact all other tests run in the same process (tests run after the execution of this one), we have to reset

@mtoffl01 mtoffl01 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I still think setTracerTags should be called setProcessTags, but other than that - LGTM!

@raphaelgavache

Copy link
Copy Markdown
Member Author

/merge

@dd-devflow-routing-codex

dd-devflow-routing-codex Bot commented Oct 7, 2025

Copy link
Copy Markdown

View all feedbacks in Devflow UI.

2025-10-07 14:28:37 UTC ℹ️ Start processing command /merge


2025-10-07 14:28:43 UTC ℹ️ MergeQueue: pull request added to the queue

The expected merge time in main is approximately 18m (p90).


2025-10-07 14:44:51 UTC ℹ️ MergeQueue: This merge request was merged

@dd-mergequeue
dd-mergequeue Bot merged commit 23545d4 into main Oct 7, 2025
239 checks passed
@dd-mergequeue
dd-mergequeue Bot deleted the raphael/fix_process_tags_spans branch October 7, 2025 14:44
darccio added a commit that referenced this pull request Oct 16, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants