Skip to content

Commit 6441653

Browse files
boekkooi-impossibleclouddashpoledmathieu
authored
Performance improvements for the trace SDK in Span. (#5874)
Good day, Thanks for review this PR! This PR follows from #5864 and avoid multiple locks in `End`, `RecordError`, `AddEvent` and `AddLink`. Benchstats result are: ``` goos: linux goarch: amd64 pkg: go.opentelemetry.io/otel/sdk/trace cpu: 11th Gen Intel(R) Core(TM) i5-11400H @ 2.70GHz │ event-3cbd9671.txt │ event-pr-e9744b48.txt │ │ sec/op │ │ SpanEnd-12 63.07n ± 1% 53.63n ± 1% -14.97% (p=0.000 n=10) │ event-3cbd9671.txt │ event-pr-e9744b48.txt │ │ B/op │ B/op vs base │ SpanEnd-12 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹ ¹ all samples are equal │ event-3cbd9671.txt │ event-pr-e9744b48.txt │ │ allocs/op │ allocs/op vs base │ SpanEnd-12 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹ ¹ all samples are equal ``` --------- Co-authored-by: David Ashpole <[email protected]> Co-authored-by: Damien Mathieu <[email protected]>
1 parent 8e9baf2 commit 6441653

File tree

2 files changed

+34
-13
lines changed

2 files changed

+34
-13
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
2020
- The `Record` type in `go.opentelemetry.io/otel/log` is no longer comparable. (#5847)
2121
- Performance improvements for the trace SDK `SetAttributes` method in `Span`. (#5864)
2222
- Reduce memory allocations for the `Event` and `Link` lists in `Span`. (#5858)
23+
- Performance improvements for the trace SDK `AddEvent`, `AddLink`, `RecordError` and `End` methods in `Span`. (#5874)
2324

2425
### Deprecated
2526

sdk/trace/span.go

+33-13
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,8 @@ func (s *recordingSpan) IsRecording() bool {
179179

180180
// isRecording returns if this span is being recorded. If this span has ended
181181
// this will return false.
182-
// This is done without acquiring a lock.
182+
//
183+
// This method assumes s.mu.Lock is held by the caller.
183184
func (s *recordingSpan) isRecording() bool {
184185
if s == nil {
185186
return false
@@ -408,9 +409,10 @@ func (s *recordingSpan) End(options ...trace.SpanEndOption) {
408409
// the span's duration in case some operation below takes a while.
409410
et := monotonicEndTime(s.startTime)
410411

411-
// Do relative expensive check now that we have an end time and see if we
412-
// need to do any more processing.
413-
if !s.IsRecording() {
412+
// Lock the span now that we have an end time and see if we need to do any more processing.
413+
s.mu.Lock()
414+
if !s.isRecording() {
415+
s.mu.Unlock()
414416
return
415417
}
416418

@@ -435,10 +437,11 @@ func (s *recordingSpan) End(options ...trace.SpanEndOption) {
435437
}
436438

437439
if s.executionTracerTaskEnd != nil {
440+
s.mu.Unlock()
438441
s.executionTracerTaskEnd()
442+
s.mu.Lock()
439443
}
440444

441-
s.mu.Lock()
442445
// Setting endTime to non-zero marks the span as ended and not recording.
443446
if config.Timestamp().IsZero() {
444447
s.endTime = et
@@ -472,7 +475,13 @@ func monotonicEndTime(start time.Time) time.Time {
472475
// does not change the Span status. If this span is not being recorded or err is nil
473476
// than this method does nothing.
474477
func (s *recordingSpan) RecordError(err error, opts ...trace.EventOption) {
475-
if s == nil || err == nil || !s.IsRecording() {
478+
if s == nil || err == nil {
479+
return
480+
}
481+
482+
s.mu.Lock()
483+
defer s.mu.Unlock()
484+
if !s.isRecording() {
476485
return
477486
}
478487

@@ -508,14 +517,23 @@ func recordStackTrace() string {
508517
}
509518

510519
// AddEvent adds an event with the provided name and options. If this span is
511-
// not being recorded than this method does nothing.
520+
// not being recorded then this method does nothing.
512521
func (s *recordingSpan) AddEvent(name string, o ...trace.EventOption) {
513-
if !s.IsRecording() {
522+
if s == nil {
523+
return
524+
}
525+
526+
s.mu.Lock()
527+
defer s.mu.Unlock()
528+
if !s.isRecording() {
514529
return
515530
}
516531
s.addEvent(name, o...)
517532
}
518533

534+
// addEvent adds an event with the provided name and options.
535+
//
536+
// This method assumes s.mu.Lock is held by the caller.
519537
func (s *recordingSpan) addEvent(name string, o ...trace.EventOption) {
520538
c := trace.NewEventConfig(o...)
521539
e := Event{Name: name, Attributes: c.Attributes(), Time: c.Timestamp()}
@@ -532,9 +550,7 @@ func (s *recordingSpan) addEvent(name string, o ...trace.EventOption) {
532550
e.Attributes = e.Attributes[:limit]
533551
}
534552

535-
s.mu.Lock()
536553
s.events.add(e)
537-
s.mu.Unlock()
538554
}
539555

540556
// SetName sets the name of this span. If this span is not being recorded than
@@ -682,14 +698,20 @@ func (s *recordingSpan) Resource() *resource.Resource {
682698
}
683699

684700
func (s *recordingSpan) AddLink(link trace.Link) {
685-
if !s.IsRecording() {
701+
if s == nil {
686702
return
687703
}
688704
if !link.SpanContext.IsValid() && len(link.Attributes) == 0 &&
689705
link.SpanContext.TraceState().Len() == 0 {
690706
return
691707
}
692708

709+
s.mu.Lock()
710+
defer s.mu.Unlock()
711+
if !s.isRecording() {
712+
return
713+
}
714+
693715
l := Link{SpanContext: link.SpanContext, Attributes: link.Attributes}
694716

695717
// Discard attributes over limit.
@@ -703,9 +725,7 @@ func (s *recordingSpan) AddLink(link trace.Link) {
703725
l.Attributes = l.Attributes[:limit]
704726
}
705727

706-
s.mu.Lock()
707728
s.links.add(l)
708-
s.mu.Unlock()
709729
}
710730

711731
// DroppedAttributes returns the number of attributes dropped by the span

0 commit comments

Comments
 (0)