Skip to content

Optimizing the trace sdk #6721

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

Open
jschaf opened this issue May 1, 2025 · 7 comments
Open

Optimizing the trace sdk #6721

jschaf opened this issue May 1, 2025 · 7 comments
Labels
area:trace Part of OpenTelemetry tracing enhancement New feature or request

Comments

@jschaf
Copy link
Contributor

jschaf commented May 1, 2025

Problem Statement

I'm exploring ways to optimize the trace functionality and wanted to gauge the appetite for optimization.

I'm willing to send PRs.

Proposed Solution

There are a few areas I've exprimented with in https://github.com/jschaf/observe. Ranked roughly in terms of feasibility, impact, and long term maintenance costs.

  1. Use atomics for Span.End instead of a mutex. Provides about a 1.5x speed up on the Span.End benchmark. As a side benefit, reduces the Span size by 16 bytes since time.Time takes 24 bytes.

  2. Inline hex encoding and decoding for TraceID and SpanID. Provides about a 2x speedup for parsing (27 ns to 12 ns) and reduces allocations to 0.

  3. Zero allocation state parsing. This is a fair bit more complex than the current parsing, but has about the same line count. Provides about a 1.8x speed up and reduces allocations to zero.

  4. [Still baking] Get syscall.Gettimeofday directly instead of time.Now. Saves about 15 ns compare to 30 ns for time.Now. I suspect there's a bunch of unhandled complexity here. It'd be swell if there was an alternative time library that handled this.

Alternatives

Doing nothing is perfectly reasonable.

Prior Art

https://www.pingcap.com/blog/how-we-trace-a-kv-database-with-less-than-5-percent-performance-impact/: They squeeze out performance using time-stamp counters and thread local state, both of which would be difficult to emulate in Go.

@jschaf jschaf added the enhancement New feature or request label May 1, 2025
@dmathieu
Copy link
Member

dmathieu commented May 1, 2025

Any improvement is welcome. But each separate improvement should be its own PR with benchmark comparison (either using the existing benchmarks, or adding new ones).

jschaf added a commit to jschaf/opentelemetry-go that referenced this issue May 2, 2025
Instead of using a mutex, use atomic compare-and-swap to set the endTime.
Store unix nanoseconds as an int64 to enable atomics.

This has few nice properties:

- Span.End() no longer needs the mutex. The first call to Span.End() does an
  atomic compare-and-swap. Later calls will return early.

- We remove the isRecording method and use the public IsRecording method since
  we don't need the mutex to access endTime.

- We reduce the recordingSpan size by 32 bytes. time.Time takes 24 bytes
  compared to 8 bytes for int64 nanoseconds. We save 16 bytes each for startTime
  and endTime.

Benchstat

```
benchstat private/base2.txt private/new2.txt
goos: darwin
goarch: arm64
pkg: go.opentelemetry.io/otel/sdk/trace
cpu: Apple M2 Max
                                              │ private/base2.txt │           private/new2.txt            │
                                              │      sec/op       │    sec/op      vs base                │
Truncate/Unlimited-12                               0.2089n ±  2%   0.2090n ±  4%        ~ (p=0.698 n=10)
Truncate/Zero-12                                    0.3052n ±  1%   0.3087n ± 20%        ~ (p=0.127 n=10)
Truncate/Short-12                                   0.2081n ±  0%   0.2089n ±  1%        ~ (p=0.362 n=10)
Truncate/ASCII-12                                   0.7140n ±  2%   0.6855n ±  0%   -4.00% (p=0.000 n=10)
Truncate/ValidUTF-8-12                               1.311n ±  2%    1.303n ±  1%   -0.61% (p=0.015 n=10)
Truncate/InvalidUTF-8-12                             9.437n ±  1%    9.315n ±  3%        ~ (p=0.143 n=10)
Truncate/MixedUTF-8-12                               17.32n ±  0%    17.16n ±  2%        ~ (p=0.159 n=10)
RecordingSpanSetAttributes/WithLimit/false-12        2.080µ ±  1%    2.010µ ±  1%   -3.39% (p=0.000 n=10)
RecordingSpanSetAttributes/WithLimit/true-12         4.358µ ±  0%    4.297µ ±  0%   -1.40% (p=0.000 n=10)
SpanEnd-12                                          107.90n ± 10%    94.44n ±  1%  -12.47% (p=0.001 n=10)
TraceStart/with_a_simple_span-12                     319.5n ±  6%    293.7n ±  3%   -8.08% (p=0.000 n=10)
TraceStart/with_several_links-12                     428.3n ±  2%    411.2n ±  1%   -3.99% (p=0.000 n=10)
TraceStart/with_attributes-12                        469.6n ±  3%    430.4n ±  1%   -8.35% (p=0.000 n=10)
SpanLimits/AttributeValueLengthLimit-12              4.379µ ±  1%    4.144µ ±  1%   -5.38% (p=0.000 n=10)
SpanLimits/AttributeCountLimit-12                    4.219µ ±  2%    3.909µ ±  1%   -7.36% (p=0.000 n=10)
SpanLimits/EventCountLimit-12                        3.994µ ±  6%    3.663µ ±  1%   -8.28% (p=0.000 n=10)
SpanLimits/LinkCountLimit-12                         3.835µ ±  2%    3.619µ ±  1%   -5.63% (p=0.000 n=10)
SpanLimits/AttributePerEventCountLimit-12            4.225µ ±  3%    3.961µ ±  1%   -6.25% (p=0.000 n=10)
SpanLimits/AttributePerLinkCountLimit-12             4.218µ ±  1%    3.951µ ±  1%   -6.32% (p=0.000 n=10)
SpanSetAttributesOverCapacity-12                     1.676µ ±  2%    1.582µ ±  0%   -5.58% (p=0.000 n=10)
StartEndSpan/AlwaysSample-12                         322.3n ±  0%    279.1n ±  0%  -13.40% (p=0.000 n=10)
StartEndSpan/NeverSample-12                          153.5n ±  4%    148.1n ±  0%   -3.55% (p=0.000 n=10)
SpanWithAttributes_4/AlwaysSample-12                 527.6n ±  1%    467.7n ±  0%  -11.36% (p=0.000 n=10)
SpanWithAttributes_4/NeverSample-12                  245.1n ±  0%    227.6n ±  0%   -7.14% (p=0.000 n=10)
SpanWithAttributes_8/AlwaysSample-12                 702.7n ±  2%    638.2n ±  1%   -9.19% (p=0.000 n=10)
SpanWithAttributes_8/NeverSample-12                  336.4n ±  1%    305.0n ±  1%   -9.32% (p=0.000 n=10)
SpanWithAttributes_all/AlwaysSample-12               593.9n ±  3%    518.8n ±  1%  -12.65% (p=0.000 n=10)
SpanWithAttributes_all/NeverSample-12                267.0n ±  3%    251.6n ±  0%   -5.73% (p=0.000 n=10)
SpanWithAttributes_all_2x/AlwaysSample-12            850.2n ±  1%    749.9n ±  0%  -11.80% (p=0.000 n=10)
SpanWithAttributes_all_2x/NeverSample-12             398.4n ±  2%    350.8n ±  2%  -11.95% (p=0.000 n=10)
SpanWithEvents_4/AlwaysSample-12                     736.3n ±  9%    640.9n ±  0%  -12.96% (p=0.000 n=10)
SpanWithEvents_4/NeverSample-12                      158.1n ±  3%    149.8n ±  0%   -5.25% (p=0.000 n=10)
SpanWithEvents_8/AlwaysSample-12                    1111.5n ±  1%    995.0n ±  0%  -10.48% (p=0.000 n=10)
SpanWithEvents_8/NeverSample-12                      159.9n ±  2%    153.1n ±  0%   -4.28% (p=0.000 n=10)
SpanWithEvents_WithStackTrace/AlwaysSample-12        446.3n ±  1%    395.8n ±  0%  -11.30% (p=0.000 n=10)
SpanWithEvents_WithStackTrace/NeverSample-12         170.4n ±  1%    161.4n ±  0%   -5.25% (p=0.000 n=10)
SpanWithEvents_WithTimestamp/AlwaysSample-12         441.9n ±  1%    379.1n ±  0%  -14.19% (p=0.000 n=10)
SpanWithEvents_WithTimestamp/NeverSample-12          196.3n ±  5%    185.2n ±  1%   -5.65% (p=0.000 n=10)
TraceID_DotString-12                                 43.07n ±  1%    40.19n ±  0%   -6.69% (p=0.000 n=10)
SpanID_DotString-12                                  31.61n ±  1%    32.63n ±  0%   +3.23% (p=0.001 n=10)
SpanProcessorOnEnd/batch:_10,_spans:_10-12           163.3n ±  3%    162.3n ±  0%   -0.64% (p=0.010 n=10)
SpanProcessorOnEnd/batch:_10,_spans:_100-12          1.645µ ±  1%    1.624µ ±  0%   -1.31% (p=0.000 n=10)
SpanProcessorOnEnd/batch:_100,_spans:_10-12          162.2n ±  1%    162.5n ±  0%        ~ (p=0.587 n=10)
SpanProcessorOnEnd/batch:_100,_spans:_100-12         1.626µ ±  1%    1.623µ ±  0%        ~ (p=0.361 n=10)
SpanProcessorVerboseLogging-12                       6.795µ ±  2%    5.789µ ±  3%  -14.81% (p=0.000 n=10)
geomean                                              225.5n          211.6n         -6.19%

                                              │ private/base2.txt │           private/new2.txt            │
                                              │       B/op        │     B/op      vs base                 │
Truncate/Unlimited-12                                0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/Zero-12                                     0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/Short-12                                    0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/ASCII-12                                    0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/ValidUTF-8-12                               0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/InvalidUTF-8-12                             16.00 ± 0%       16.00 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/MixedUTF-8-12                               32.00 ± 0%       32.00 ± 0%       ~ (p=1.000 n=10) ¹
RecordingSpanSetAttributes/WithLimit/false-12      6.891Ki ± 0%     6.859Ki ± 0%  -0.45% (p=0.000 n=10)
RecordingSpanSetAttributes/WithLimit/true-12       7.023Ki ± 0%     6.992Ki ± 0%  -0.44% (p=0.000 n=10)
SpanEnd-12                                           0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
TraceStart/with_a_simple_span-12                     528.0 ± 0%       496.0 ± 0%  -6.06% (p=0.000 n=10)
TraceStart/with_several_links-12                     704.0 ± 0%       672.0 ± 0%  -4.55% (p=0.000 n=10)
TraceStart/with_attributes-12                        784.0 ± 0%       752.0 ± 0%  -4.08% (p=0.000 n=10)
SpanLimits/AttributeValueLengthLimit-12            10.56Ki ± 0%     10.53Ki ± 0%  -0.30% (p=0.000 n=10)
SpanLimits/AttributeCountLimit-12                  9.844Ki ± 0%     9.812Ki ± 0%  -0.32% (p=0.000 n=10)
SpanLimits/EventCountLimit-12                      9.422Ki ± 0%     9.391Ki ± 0%  -0.33% (p=0.000 n=10)
SpanLimits/LinkCountLimit-12                       9.031Ki ± 0%     9.000Ki ± 0%  -0.35% (p=0.000 n=10)
SpanLimits/AttributePerEventCountLimit-12          10.47Ki ± 0%     10.44Ki ± 0%  -0.30% (p=0.000 n=10)
SpanLimits/AttributePerLinkCountLimit-12           10.47Ki ± 0%     10.44Ki ± 0%  -0.30% (p=0.000 n=10)
SpanSetAttributesOverCapacity-12                     592.0 ± 0%       560.0 ± 0%  -5.41% (p=0.000 n=10)
StartEndSpan/AlwaysSample-12                         528.0 ± 0%       496.0 ± 0%  -6.06% (p=0.000 n=10)
StartEndSpan/NeverSample-12                          144.0 ± 0%       144.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_4/AlwaysSample-12                1040.0 ± 0%      1008.0 ± 0%  -3.08% (p=0.000 n=10)
SpanWithAttributes_4/NeverSample-12                  400.0 ± 0%       400.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_8/AlwaysSample-12               1.516Ki ± 0%     1.484Ki ± 0%  -2.06% (p=0.000 n=10)
SpanWithAttributes_8/NeverSample-12                  656.0 ± 0%       656.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all/AlwaysSample-12             1.141Ki ± 0%     1.109Ki ± 0%  -2.74% (p=0.000 n=10)
SpanWithAttributes_all/NeverSample-12                464.0 ± 0%       464.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all_2x/AlwaysSample-12          1.891Ki ± 0%     1.859Ki ± 0%  -1.65% (p=0.000 n=10)
SpanWithAttributes_all_2x/NeverSample-12             848.0 ± 0%       848.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_4/AlwaysSample-12                    1040.0 ± 0%      1008.0 ± 0%  -3.08% (p=0.000 n=10)
SpanWithEvents_4/NeverSample-12                      144.0 ± 0%       144.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_8/AlwaysSample-12                   1.641Ki ± 0%     1.609Ki ± 0%  -1.90% (p=0.000 n=10)
SpanWithEvents_8/NeverSample-12                      144.0 ± 0%       144.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithStackTrace/AlwaysSample-12        624.0 ± 0%       592.0 ± 0%  -5.13% (p=0.000 n=10)
SpanWithEvents_WithStackTrace/NeverSample-12         160.0 ± 0%       160.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithTimestamp/AlwaysSample-12         648.0 ± 0%       616.0 ± 0%  -4.94% (p=0.000 n=10)
SpanWithEvents_WithTimestamp/NeverSample-12          184.0 ± 0%       184.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_10,_spans:_10-12           0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_10,_spans:_100-12          0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_100,_spans:_10-12          0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_100,_spans:_100-12         0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorVerboseLogging-12                     9.547Ki ± 0%     9.234Ki ± 0%  -3.27% (p=0.000 n=10)
geomean                                                         ²                 -1.34%                ²
¹ all samples are equal
² summaries must be >0 to compute geomean

                                              │ private/base2.txt │          private/new2.txt           │
                                              │     allocs/op     │ allocs/op   vs base                 │
Truncate/Unlimited-12                                0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/Zero-12                                     0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/Short-12                                    0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/ASCII-12                                    0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/ValidUTF-8-12                               0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/InvalidUTF-8-12                             1.000 ± 0%     1.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/MixedUTF-8-12                               1.000 ± 0%     1.000 ± 0%       ~ (p=1.000 n=10) ¹
RecordingSpanSetAttributes/WithLimit/false-12        3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
RecordingSpanSetAttributes/WithLimit/true-12         10.00 ± 0%     10.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanEnd-12                                           0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
TraceStart/with_a_simple_span-12                     2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
TraceStart/with_several_links-12                     3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
TraceStart/with_attributes-12                        4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributeValueLengthLimit-12              41.00 ± 0%     41.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributeCountLimit-12                    38.00 ± 0%     38.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/EventCountLimit-12                        35.00 ± 0%     35.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/LinkCountLimit-12                         35.00 ± 0%     35.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributePerEventCountLimit-12            38.00 ± 0%     38.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributePerLinkCountLimit-12             38.00 ± 0%     38.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanSetAttributesOverCapacity-12                     3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
StartEndSpan/AlwaysSample-12                         2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
StartEndSpan/NeverSample-12                          2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_4/AlwaysSample-12                 4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_4/NeverSample-12                  3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_8/AlwaysSample-12                 4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_8/NeverSample-12                  3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all/AlwaysSample-12               4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all/NeverSample-12                3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all_2x/AlwaysSample-12            4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all_2x/NeverSample-12             3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_4/AlwaysSample-12                     5.000 ± 0%     5.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_4/NeverSample-12                      2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_8/AlwaysSample-12                     6.000 ± 0%     6.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_8/NeverSample-12                      2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithStackTrace/AlwaysSample-12        4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithStackTrace/NeverSample-12         3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithTimestamp/AlwaysSample-12         5.000 ± 0%     5.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithTimestamp/NeverSample-12          4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_10,_spans:_10-12           0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_10,_spans:_100-12          0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_100,_spans:_10-12          0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_100,_spans:_100-12         0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorVerboseLogging-12                       35.00 ± 0%     35.00 ± 0%       ~ (p=1.000 n=10) ¹
geomean                                                         ²               +0.00%                ²
¹ all samples are equal
² summaries must be >0 to compute geomean

See open-telemetry#6721.
jschaf added a commit to jschaf/opentelemetry-go that referenced this issue May 2, 2025
Instead of using a mutex, use atomic compare-and-swap to set the endTime.
Store unix nanoseconds as an int64 to enable atomics.

This has few nice properties:

- Span.End() no longer needs the mutex. The first call to Span.End() does an
  atomic compare-and-swap. Later calls will return early.

- We remove the isRecording method and use the public IsRecording method since
  we don't need the mutex to access endTime.

- We reduce the recordingSpan size by 32 bytes. time.Time takes 24 bytes
  compared to 8 bytes for int64 nanoseconds. We save 16 bytes each for startTime
  and endTime.

Benchstat

```
benchstat private/base2.txt private/new2.txt
goos: darwin
goarch: arm64
pkg: go.opentelemetry.io/otel/sdk/trace
cpu: Apple M2 Max
                                              │ private/base2.txt │           private/new2.txt            │
                                              │      sec/op       │    sec/op      vs base                │
Truncate/Unlimited-12                               0.2089n ±  2%   0.2090n ±  4%        ~ (p=0.698 n=10)
Truncate/Zero-12                                    0.3052n ±  1%   0.3087n ± 20%        ~ (p=0.127 n=10)
Truncate/Short-12                                   0.2081n ±  0%   0.2089n ±  1%        ~ (p=0.362 n=10)
Truncate/ASCII-12                                   0.7140n ±  2%   0.6855n ±  0%   -4.00% (p=0.000 n=10)
Truncate/ValidUTF-8-12                               1.311n ±  2%    1.303n ±  1%   -0.61% (p=0.015 n=10)
Truncate/InvalidUTF-8-12                             9.437n ±  1%    9.315n ±  3%        ~ (p=0.143 n=10)
Truncate/MixedUTF-8-12                               17.32n ±  0%    17.16n ±  2%        ~ (p=0.159 n=10)
RecordingSpanSetAttributes/WithLimit/false-12        2.080µ ±  1%    2.010µ ±  1%   -3.39% (p=0.000 n=10)
RecordingSpanSetAttributes/WithLimit/true-12         4.358µ ±  0%    4.297µ ±  0%   -1.40% (p=0.000 n=10)
SpanEnd-12                                          107.90n ± 10%    94.44n ±  1%  -12.47% (p=0.001 n=10)
TraceStart/with_a_simple_span-12                     319.5n ±  6%    293.7n ±  3%   -8.08% (p=0.000 n=10)
TraceStart/with_several_links-12                     428.3n ±  2%    411.2n ±  1%   -3.99% (p=0.000 n=10)
TraceStart/with_attributes-12                        469.6n ±  3%    430.4n ±  1%   -8.35% (p=0.000 n=10)
SpanLimits/AttributeValueLengthLimit-12              4.379µ ±  1%    4.144µ ±  1%   -5.38% (p=0.000 n=10)
SpanLimits/AttributeCountLimit-12                    4.219µ ±  2%    3.909µ ±  1%   -7.36% (p=0.000 n=10)
SpanLimits/EventCountLimit-12                        3.994µ ±  6%    3.663µ ±  1%   -8.28% (p=0.000 n=10)
SpanLimits/LinkCountLimit-12                         3.835µ ±  2%    3.619µ ±  1%   -5.63% (p=0.000 n=10)
SpanLimits/AttributePerEventCountLimit-12            4.225µ ±  3%    3.961µ ±  1%   -6.25% (p=0.000 n=10)
SpanLimits/AttributePerLinkCountLimit-12             4.218µ ±  1%    3.951µ ±  1%   -6.32% (p=0.000 n=10)
SpanSetAttributesOverCapacity-12                     1.676µ ±  2%    1.582µ ±  0%   -5.58% (p=0.000 n=10)
StartEndSpan/AlwaysSample-12                         322.3n ±  0%    279.1n ±  0%  -13.40% (p=0.000 n=10)
StartEndSpan/NeverSample-12                          153.5n ±  4%    148.1n ±  0%   -3.55% (p=0.000 n=10)
SpanWithAttributes_4/AlwaysSample-12                 527.6n ±  1%    467.7n ±  0%  -11.36% (p=0.000 n=10)
SpanWithAttributes_4/NeverSample-12                  245.1n ±  0%    227.6n ±  0%   -7.14% (p=0.000 n=10)
SpanWithAttributes_8/AlwaysSample-12                 702.7n ±  2%    638.2n ±  1%   -9.19% (p=0.000 n=10)
SpanWithAttributes_8/NeverSample-12                  336.4n ±  1%    305.0n ±  1%   -9.32% (p=0.000 n=10)
SpanWithAttributes_all/AlwaysSample-12               593.9n ±  3%    518.8n ±  1%  -12.65% (p=0.000 n=10)
SpanWithAttributes_all/NeverSample-12                267.0n ±  3%    251.6n ±  0%   -5.73% (p=0.000 n=10)
SpanWithAttributes_all_2x/AlwaysSample-12            850.2n ±  1%    749.9n ±  0%  -11.80% (p=0.000 n=10)
SpanWithAttributes_all_2x/NeverSample-12             398.4n ±  2%    350.8n ±  2%  -11.95% (p=0.000 n=10)
SpanWithEvents_4/AlwaysSample-12                     736.3n ±  9%    640.9n ±  0%  -12.96% (p=0.000 n=10)
SpanWithEvents_4/NeverSample-12                      158.1n ±  3%    149.8n ±  0%   -5.25% (p=0.000 n=10)
SpanWithEvents_8/AlwaysSample-12                    1111.5n ±  1%    995.0n ±  0%  -10.48% (p=0.000 n=10)
SpanWithEvents_8/NeverSample-12                      159.9n ±  2%    153.1n ±  0%   -4.28% (p=0.000 n=10)
SpanWithEvents_WithStackTrace/AlwaysSample-12        446.3n ±  1%    395.8n ±  0%  -11.30% (p=0.000 n=10)
SpanWithEvents_WithStackTrace/NeverSample-12         170.4n ±  1%    161.4n ±  0%   -5.25% (p=0.000 n=10)
SpanWithEvents_WithTimestamp/AlwaysSample-12         441.9n ±  1%    379.1n ±  0%  -14.19% (p=0.000 n=10)
SpanWithEvents_WithTimestamp/NeverSample-12          196.3n ±  5%    185.2n ±  1%   -5.65% (p=0.000 n=10)
TraceID_DotString-12                                 43.07n ±  1%    40.19n ±  0%   -6.69% (p=0.000 n=10)
SpanID_DotString-12                                  31.61n ±  1%    32.63n ±  0%   +3.23% (p=0.001 n=10)
SpanProcessorOnEnd/batch:_10,_spans:_10-12           163.3n ±  3%    162.3n ±  0%   -0.64% (p=0.010 n=10)
SpanProcessorOnEnd/batch:_10,_spans:_100-12          1.645µ ±  1%    1.624µ ±  0%   -1.31% (p=0.000 n=10)
SpanProcessorOnEnd/batch:_100,_spans:_10-12          162.2n ±  1%    162.5n ±  0%        ~ (p=0.587 n=10)
SpanProcessorOnEnd/batch:_100,_spans:_100-12         1.626µ ±  1%    1.623µ ±  0%        ~ (p=0.361 n=10)
SpanProcessorVerboseLogging-12                       6.795µ ±  2%    5.789µ ±  3%  -14.81% (p=0.000 n=10)
geomean                                              225.5n          211.6n         -6.19%

                                              │ private/base2.txt │           private/new2.txt            │
                                              │       B/op        │     B/op      vs base                 │
Truncate/Unlimited-12                                0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/Zero-12                                     0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/Short-12                                    0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/ASCII-12                                    0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/ValidUTF-8-12                               0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/InvalidUTF-8-12                             16.00 ± 0%       16.00 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/MixedUTF-8-12                               32.00 ± 0%       32.00 ± 0%       ~ (p=1.000 n=10) ¹
RecordingSpanSetAttributes/WithLimit/false-12      6.891Ki ± 0%     6.859Ki ± 0%  -0.45% (p=0.000 n=10)
RecordingSpanSetAttributes/WithLimit/true-12       7.023Ki ± 0%     6.992Ki ± 0%  -0.44% (p=0.000 n=10)
SpanEnd-12                                           0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
TraceStart/with_a_simple_span-12                     528.0 ± 0%       496.0 ± 0%  -6.06% (p=0.000 n=10)
TraceStart/with_several_links-12                     704.0 ± 0%       672.0 ± 0%  -4.55% (p=0.000 n=10)
TraceStart/with_attributes-12                        784.0 ± 0%       752.0 ± 0%  -4.08% (p=0.000 n=10)
SpanLimits/AttributeValueLengthLimit-12            10.56Ki ± 0%     10.53Ki ± 0%  -0.30% (p=0.000 n=10)
SpanLimits/AttributeCountLimit-12                  9.844Ki ± 0%     9.812Ki ± 0%  -0.32% (p=0.000 n=10)
SpanLimits/EventCountLimit-12                      9.422Ki ± 0%     9.391Ki ± 0%  -0.33% (p=0.000 n=10)
SpanLimits/LinkCountLimit-12                       9.031Ki ± 0%     9.000Ki ± 0%  -0.35% (p=0.000 n=10)
SpanLimits/AttributePerEventCountLimit-12          10.47Ki ± 0%     10.44Ki ± 0%  -0.30% (p=0.000 n=10)
SpanLimits/AttributePerLinkCountLimit-12           10.47Ki ± 0%     10.44Ki ± 0%  -0.30% (p=0.000 n=10)
SpanSetAttributesOverCapacity-12                     592.0 ± 0%       560.0 ± 0%  -5.41% (p=0.000 n=10)
StartEndSpan/AlwaysSample-12                         528.0 ± 0%       496.0 ± 0%  -6.06% (p=0.000 n=10)
StartEndSpan/NeverSample-12                          144.0 ± 0%       144.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_4/AlwaysSample-12                1040.0 ± 0%      1008.0 ± 0%  -3.08% (p=0.000 n=10)
SpanWithAttributes_4/NeverSample-12                  400.0 ± 0%       400.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_8/AlwaysSample-12               1.516Ki ± 0%     1.484Ki ± 0%  -2.06% (p=0.000 n=10)
SpanWithAttributes_8/NeverSample-12                  656.0 ± 0%       656.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all/AlwaysSample-12             1.141Ki ± 0%     1.109Ki ± 0%  -2.74% (p=0.000 n=10)
SpanWithAttributes_all/NeverSample-12                464.0 ± 0%       464.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all_2x/AlwaysSample-12          1.891Ki ± 0%     1.859Ki ± 0%  -1.65% (p=0.000 n=10)
SpanWithAttributes_all_2x/NeverSample-12             848.0 ± 0%       848.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_4/AlwaysSample-12                    1040.0 ± 0%      1008.0 ± 0%  -3.08% (p=0.000 n=10)
SpanWithEvents_4/NeverSample-12                      144.0 ± 0%       144.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_8/AlwaysSample-12                   1.641Ki ± 0%     1.609Ki ± 0%  -1.90% (p=0.000 n=10)
SpanWithEvents_8/NeverSample-12                      144.0 ± 0%       144.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithStackTrace/AlwaysSample-12        624.0 ± 0%       592.0 ± 0%  -5.13% (p=0.000 n=10)
SpanWithEvents_WithStackTrace/NeverSample-12         160.0 ± 0%       160.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithTimestamp/AlwaysSample-12         648.0 ± 0%       616.0 ± 0%  -4.94% (p=0.000 n=10)
SpanWithEvents_WithTimestamp/NeverSample-12          184.0 ± 0%       184.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_10,_spans:_10-12           0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_10,_spans:_100-12          0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_100,_spans:_10-12          0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_100,_spans:_100-12         0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorVerboseLogging-12                     9.547Ki ± 0%     9.234Ki ± 0%  -3.27% (p=0.000 n=10)
geomean                                                         ²                 -1.34%                ²
¹ all samples are equal
² summaries must be >0 to compute geomean

                                              │ private/base2.txt │          private/new2.txt           │
                                              │     allocs/op     │ allocs/op   vs base                 │
Truncate/Unlimited-12                                0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/Zero-12                                     0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/Short-12                                    0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/ASCII-12                                    0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/ValidUTF-8-12                               0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/InvalidUTF-8-12                             1.000 ± 0%     1.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/MixedUTF-8-12                               1.000 ± 0%     1.000 ± 0%       ~ (p=1.000 n=10) ¹
RecordingSpanSetAttributes/WithLimit/false-12        3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
RecordingSpanSetAttributes/WithLimit/true-12         10.00 ± 0%     10.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanEnd-12                                           0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
TraceStart/with_a_simple_span-12                     2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
TraceStart/with_several_links-12                     3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
TraceStart/with_attributes-12                        4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributeValueLengthLimit-12              41.00 ± 0%     41.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributeCountLimit-12                    38.00 ± 0%     38.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/EventCountLimit-12                        35.00 ± 0%     35.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/LinkCountLimit-12                         35.00 ± 0%     35.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributePerEventCountLimit-12            38.00 ± 0%     38.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributePerLinkCountLimit-12             38.00 ± 0%     38.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanSetAttributesOverCapacity-12                     3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
StartEndSpan/AlwaysSample-12                         2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
StartEndSpan/NeverSample-12                          2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_4/AlwaysSample-12                 4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_4/NeverSample-12                  3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_8/AlwaysSample-12                 4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_8/NeverSample-12                  3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all/AlwaysSample-12               4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all/NeverSample-12                3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all_2x/AlwaysSample-12            4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all_2x/NeverSample-12             3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_4/AlwaysSample-12                     5.000 ± 0%     5.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_4/NeverSample-12                      2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_8/AlwaysSample-12                     6.000 ± 0%     6.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_8/NeverSample-12                      2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithStackTrace/AlwaysSample-12        4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithStackTrace/NeverSample-12         3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithTimestamp/AlwaysSample-12         5.000 ± 0%     5.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithTimestamp/NeverSample-12          4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_10,_spans:_10-12           0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_10,_spans:_100-12          0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_100,_spans:_10-12          0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_100,_spans:_100-12         0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorVerboseLogging-12                       35.00 ± 0%     35.00 ± 0%       ~ (p=1.000 n=10) ¹
geomean                                                         ²               +0.00%                ²
¹ all samples are equal
² summaries must be >0 to compute geomean

See open-telemetry#6721.
jschaf added a commit to jschaf/opentelemetry-go that referenced this issue May 2, 2025
Instead of using a mutex, use atomic compare-and-swap to set the endTime.
Store unix nanoseconds as an int64 to enable atomics.

This has few nice properties:

- Span.End() no longer needs the mutex. The first call to Span.End() does an
  atomic compare-and-swap. Later calls will return early.

- We remove the isRecording method and use the public IsRecording method since
  we don't need the mutex to access endTime.

- We reduce the recordingSpan size by 32 bytes. time.Time takes 24 bytes
  compared to 8 bytes for int64 nanoseconds. We save 16 bytes each for startTime
  and endTime.

Benchstat

```
benchstat private/base2.txt private/new2.txt
goos: darwin
goarch: arm64
pkg: go.opentelemetry.io/otel/sdk/trace
cpu: Apple M2 Max
                                              │ private/base2.txt │           private/new2.txt            │
                                              │      sec/op       │    sec/op      vs base                │
Truncate/Unlimited-12                               0.2089n ±  2%   0.2090n ±  4%        ~ (p=0.698 n=10)
Truncate/Zero-12                                    0.3052n ±  1%   0.3087n ± 20%        ~ (p=0.127 n=10)
Truncate/Short-12                                   0.2081n ±  0%   0.2089n ±  1%        ~ (p=0.362 n=10)
Truncate/ASCII-12                                   0.7140n ±  2%   0.6855n ±  0%   -4.00% (p=0.000 n=10)
Truncate/ValidUTF-8-12                               1.311n ±  2%    1.303n ±  1%   -0.61% (p=0.015 n=10)
Truncate/InvalidUTF-8-12                             9.437n ±  1%    9.315n ±  3%        ~ (p=0.143 n=10)
Truncate/MixedUTF-8-12                               17.32n ±  0%    17.16n ±  2%        ~ (p=0.159 n=10)
RecordingSpanSetAttributes/WithLimit/false-12        2.080µ ±  1%    2.010µ ±  1%   -3.39% (p=0.000 n=10)
RecordingSpanSetAttributes/WithLimit/true-12         4.358µ ±  0%    4.297µ ±  0%   -1.40% (p=0.000 n=10)
SpanEnd-12                                          107.90n ± 10%    94.44n ±  1%  -12.47% (p=0.001 n=10)
TraceStart/with_a_simple_span-12                     319.5n ±  6%    293.7n ±  3%   -8.08% (p=0.000 n=10)
TraceStart/with_several_links-12                     428.3n ±  2%    411.2n ±  1%   -3.99% (p=0.000 n=10)
TraceStart/with_attributes-12                        469.6n ±  3%    430.4n ±  1%   -8.35% (p=0.000 n=10)
SpanLimits/AttributeValueLengthLimit-12              4.379µ ±  1%    4.144µ ±  1%   -5.38% (p=0.000 n=10)
SpanLimits/AttributeCountLimit-12                    4.219µ ±  2%    3.909µ ±  1%   -7.36% (p=0.000 n=10)
SpanLimits/EventCountLimit-12                        3.994µ ±  6%    3.663µ ±  1%   -8.28% (p=0.000 n=10)
SpanLimits/LinkCountLimit-12                         3.835µ ±  2%    3.619µ ±  1%   -5.63% (p=0.000 n=10)
SpanLimits/AttributePerEventCountLimit-12            4.225µ ±  3%    3.961µ ±  1%   -6.25% (p=0.000 n=10)
SpanLimits/AttributePerLinkCountLimit-12             4.218µ ±  1%    3.951µ ±  1%   -6.32% (p=0.000 n=10)
SpanSetAttributesOverCapacity-12                     1.676µ ±  2%    1.582µ ±  0%   -5.58% (p=0.000 n=10)
StartEndSpan/AlwaysSample-12                         322.3n ±  0%    279.1n ±  0%  -13.40% (p=0.000 n=10)
StartEndSpan/NeverSample-12                          153.5n ±  4%    148.1n ±  0%   -3.55% (p=0.000 n=10)
SpanWithAttributes_4/AlwaysSample-12                 527.6n ±  1%    467.7n ±  0%  -11.36% (p=0.000 n=10)
SpanWithAttributes_4/NeverSample-12                  245.1n ±  0%    227.6n ±  0%   -7.14% (p=0.000 n=10)
SpanWithAttributes_8/AlwaysSample-12                 702.7n ±  2%    638.2n ±  1%   -9.19% (p=0.000 n=10)
SpanWithAttributes_8/NeverSample-12                  336.4n ±  1%    305.0n ±  1%   -9.32% (p=0.000 n=10)
SpanWithAttributes_all/AlwaysSample-12               593.9n ±  3%    518.8n ±  1%  -12.65% (p=0.000 n=10)
SpanWithAttributes_all/NeverSample-12                267.0n ±  3%    251.6n ±  0%   -5.73% (p=0.000 n=10)
SpanWithAttributes_all_2x/AlwaysSample-12            850.2n ±  1%    749.9n ±  0%  -11.80% (p=0.000 n=10)
SpanWithAttributes_all_2x/NeverSample-12             398.4n ±  2%    350.8n ±  2%  -11.95% (p=0.000 n=10)
SpanWithEvents_4/AlwaysSample-12                     736.3n ±  9%    640.9n ±  0%  -12.96% (p=0.000 n=10)
SpanWithEvents_4/NeverSample-12                      158.1n ±  3%    149.8n ±  0%   -5.25% (p=0.000 n=10)
SpanWithEvents_8/AlwaysSample-12                    1111.5n ±  1%    995.0n ±  0%  -10.48% (p=0.000 n=10)
SpanWithEvents_8/NeverSample-12                      159.9n ±  2%    153.1n ±  0%   -4.28% (p=0.000 n=10)
SpanWithEvents_WithStackTrace/AlwaysSample-12        446.3n ±  1%    395.8n ±  0%  -11.30% (p=0.000 n=10)
SpanWithEvents_WithStackTrace/NeverSample-12         170.4n ±  1%    161.4n ±  0%   -5.25% (p=0.000 n=10)
SpanWithEvents_WithTimestamp/AlwaysSample-12         441.9n ±  1%    379.1n ±  0%  -14.19% (p=0.000 n=10)
SpanWithEvents_WithTimestamp/NeverSample-12          196.3n ±  5%    185.2n ±  1%   -5.65% (p=0.000 n=10)
TraceID_DotString-12                                 43.07n ±  1%    40.19n ±  0%   -6.69% (p=0.000 n=10)
SpanID_DotString-12                                  31.61n ±  1%    32.63n ±  0%   +3.23% (p=0.001 n=10)
SpanProcessorOnEnd/batch:_10,_spans:_10-12           163.3n ±  3%    162.3n ±  0%   -0.64% (p=0.010 n=10)
SpanProcessorOnEnd/batch:_10,_spans:_100-12          1.645µ ±  1%    1.624µ ±  0%   -1.31% (p=0.000 n=10)
SpanProcessorOnEnd/batch:_100,_spans:_10-12          162.2n ±  1%    162.5n ±  0%        ~ (p=0.587 n=10)
SpanProcessorOnEnd/batch:_100,_spans:_100-12         1.626µ ±  1%    1.623µ ±  0%        ~ (p=0.361 n=10)
SpanProcessorVerboseLogging-12                       6.795µ ±  2%    5.789µ ±  3%  -14.81% (p=0.000 n=10)
geomean                                              225.5n          211.6n         -6.19%

                                              │ private/base2.txt │           private/new2.txt            │
                                              │       B/op        │     B/op      vs base                 │
Truncate/Unlimited-12                                0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/Zero-12                                     0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/Short-12                                    0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/ASCII-12                                    0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/ValidUTF-8-12                               0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/InvalidUTF-8-12                             16.00 ± 0%       16.00 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/MixedUTF-8-12                               32.00 ± 0%       32.00 ± 0%       ~ (p=1.000 n=10) ¹
RecordingSpanSetAttributes/WithLimit/false-12      6.891Ki ± 0%     6.859Ki ± 0%  -0.45% (p=0.000 n=10)
RecordingSpanSetAttributes/WithLimit/true-12       7.023Ki ± 0%     6.992Ki ± 0%  -0.44% (p=0.000 n=10)
SpanEnd-12                                           0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
TraceStart/with_a_simple_span-12                     528.0 ± 0%       496.0 ± 0%  -6.06% (p=0.000 n=10)
TraceStart/with_several_links-12                     704.0 ± 0%       672.0 ± 0%  -4.55% (p=0.000 n=10)
TraceStart/with_attributes-12                        784.0 ± 0%       752.0 ± 0%  -4.08% (p=0.000 n=10)
SpanLimits/AttributeValueLengthLimit-12            10.56Ki ± 0%     10.53Ki ± 0%  -0.30% (p=0.000 n=10)
SpanLimits/AttributeCountLimit-12                  9.844Ki ± 0%     9.812Ki ± 0%  -0.32% (p=0.000 n=10)
SpanLimits/EventCountLimit-12                      9.422Ki ± 0%     9.391Ki ± 0%  -0.33% (p=0.000 n=10)
SpanLimits/LinkCountLimit-12                       9.031Ki ± 0%     9.000Ki ± 0%  -0.35% (p=0.000 n=10)
SpanLimits/AttributePerEventCountLimit-12          10.47Ki ± 0%     10.44Ki ± 0%  -0.30% (p=0.000 n=10)
SpanLimits/AttributePerLinkCountLimit-12           10.47Ki ± 0%     10.44Ki ± 0%  -0.30% (p=0.000 n=10)
SpanSetAttributesOverCapacity-12                     592.0 ± 0%       560.0 ± 0%  -5.41% (p=0.000 n=10)
StartEndSpan/AlwaysSample-12                         528.0 ± 0%       496.0 ± 0%  -6.06% (p=0.000 n=10)
StartEndSpan/NeverSample-12                          144.0 ± 0%       144.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_4/AlwaysSample-12                1040.0 ± 0%      1008.0 ± 0%  -3.08% (p=0.000 n=10)
SpanWithAttributes_4/NeverSample-12                  400.0 ± 0%       400.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_8/AlwaysSample-12               1.516Ki ± 0%     1.484Ki ± 0%  -2.06% (p=0.000 n=10)
SpanWithAttributes_8/NeverSample-12                  656.0 ± 0%       656.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all/AlwaysSample-12             1.141Ki ± 0%     1.109Ki ± 0%  -2.74% (p=0.000 n=10)
SpanWithAttributes_all/NeverSample-12                464.0 ± 0%       464.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all_2x/AlwaysSample-12          1.891Ki ± 0%     1.859Ki ± 0%  -1.65% (p=0.000 n=10)
SpanWithAttributes_all_2x/NeverSample-12             848.0 ± 0%       848.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_4/AlwaysSample-12                    1040.0 ± 0%      1008.0 ± 0%  -3.08% (p=0.000 n=10)
SpanWithEvents_4/NeverSample-12                      144.0 ± 0%       144.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_8/AlwaysSample-12                   1.641Ki ± 0%     1.609Ki ± 0%  -1.90% (p=0.000 n=10)
SpanWithEvents_8/NeverSample-12                      144.0 ± 0%       144.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithStackTrace/AlwaysSample-12        624.0 ± 0%       592.0 ± 0%  -5.13% (p=0.000 n=10)
SpanWithEvents_WithStackTrace/NeverSample-12         160.0 ± 0%       160.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithTimestamp/AlwaysSample-12         648.0 ± 0%       616.0 ± 0%  -4.94% (p=0.000 n=10)
SpanWithEvents_WithTimestamp/NeverSample-12          184.0 ± 0%       184.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_10,_spans:_10-12           0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_10,_spans:_100-12          0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_100,_spans:_10-12          0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_100,_spans:_100-12         0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorVerboseLogging-12                     9.547Ki ± 0%     9.234Ki ± 0%  -3.27% (p=0.000 n=10)
geomean                                                         ²                 -1.34%                ²
¹ all samples are equal
² summaries must be >0 to compute geomean

                                              │ private/base2.txt │          private/new2.txt           │
                                              │     allocs/op     │ allocs/op   vs base                 │
Truncate/Unlimited-12                                0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/Zero-12                                     0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/Short-12                                    0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/ASCII-12                                    0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/ValidUTF-8-12                               0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/InvalidUTF-8-12                             1.000 ± 0%     1.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/MixedUTF-8-12                               1.000 ± 0%     1.000 ± 0%       ~ (p=1.000 n=10) ¹
RecordingSpanSetAttributes/WithLimit/false-12        3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
RecordingSpanSetAttributes/WithLimit/true-12         10.00 ± 0%     10.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanEnd-12                                           0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
TraceStart/with_a_simple_span-12                     2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
TraceStart/with_several_links-12                     3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
TraceStart/with_attributes-12                        4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributeValueLengthLimit-12              41.00 ± 0%     41.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributeCountLimit-12                    38.00 ± 0%     38.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/EventCountLimit-12                        35.00 ± 0%     35.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/LinkCountLimit-12                         35.00 ± 0%     35.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributePerEventCountLimit-12            38.00 ± 0%     38.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributePerLinkCountLimit-12             38.00 ± 0%     38.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanSetAttributesOverCapacity-12                     3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
StartEndSpan/AlwaysSample-12                         2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
StartEndSpan/NeverSample-12                          2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_4/AlwaysSample-12                 4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_4/NeverSample-12                  3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_8/AlwaysSample-12                 4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_8/NeverSample-12                  3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all/AlwaysSample-12               4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all/NeverSample-12                3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all_2x/AlwaysSample-12            4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all_2x/NeverSample-12             3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_4/AlwaysSample-12                     5.000 ± 0%     5.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_4/NeverSample-12                      2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_8/AlwaysSample-12                     6.000 ± 0%     6.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_8/NeverSample-12                      2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithStackTrace/AlwaysSample-12        4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithStackTrace/NeverSample-12         3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithTimestamp/AlwaysSample-12         5.000 ± 0%     5.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithTimestamp/NeverSample-12          4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_10,_spans:_10-12           0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_10,_spans:_100-12          0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_100,_spans:_10-12          0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_100,_spans:_100-12         0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorVerboseLogging-12                       35.00 ± 0%     35.00 ± 0%       ~ (p=1.000 n=10) ¹
geomean                                                         ²               +0.00%                ²
¹ all samples are equal
² summaries must be >0 to compute geomean
```

See open-telemetry#6721.
jschaf added a commit to jschaf/opentelemetry-go that referenced this issue May 2, 2025
Instead of using a mutex, use atomic compare-and-swap to set the endTime.
Store unix nanoseconds as an int64 to enable atomics.

This has few nice properties:

- Span.End() no longer needs the mutex. The first call to Span.End() does an
  atomic compare-and-swap. Later calls will return early.

- We remove the isRecording method and use the public IsRecording method since
  we don't need the mutex to access endTime.

- We reduce the recordingSpan size by 32 bytes. time.Time takes 24 bytes
  compared to 8 bytes for int64 nanoseconds. We save 16 bytes each for startTime
  and endTime.

Benchstat

```
benchstat private/base2.txt private/new2.txt
goos: darwin
goarch: arm64
pkg: go.opentelemetry.io/otel/sdk/trace
cpu: Apple M2 Max
                                              │ private/base2.txt │           private/new2.txt            │
                                              │      sec/op       │    sec/op      vs base                │
Truncate/Unlimited-12                               0.2089n ±  2%   0.2090n ±  4%        ~ (p=0.698 n=10)
Truncate/Zero-12                                    0.3052n ±  1%   0.3087n ± 20%        ~ (p=0.127 n=10)
Truncate/Short-12                                   0.2081n ±  0%   0.2089n ±  1%        ~ (p=0.362 n=10)
Truncate/ASCII-12                                   0.7140n ±  2%   0.6855n ±  0%   -4.00% (p=0.000 n=10)
Truncate/ValidUTF-8-12                               1.311n ±  2%    1.303n ±  1%   -0.61% (p=0.015 n=10)
Truncate/InvalidUTF-8-12                             9.437n ±  1%    9.315n ±  3%        ~ (p=0.143 n=10)
Truncate/MixedUTF-8-12                               17.32n ±  0%    17.16n ±  2%        ~ (p=0.159 n=10)
RecordingSpanSetAttributes/WithLimit/false-12        2.080µ ±  1%    2.010µ ±  1%   -3.39% (p=0.000 n=10)
RecordingSpanSetAttributes/WithLimit/true-12         4.358µ ±  0%    4.297µ ±  0%   -1.40% (p=0.000 n=10)
SpanEnd-12                                          107.90n ± 10%    94.44n ±  1%  -12.47% (p=0.001 n=10)
TraceStart/with_a_simple_span-12                     319.5n ±  6%    293.7n ±  3%   -8.08% (p=0.000 n=10)
TraceStart/with_several_links-12                     428.3n ±  2%    411.2n ±  1%   -3.99% (p=0.000 n=10)
TraceStart/with_attributes-12                        469.6n ±  3%    430.4n ±  1%   -8.35% (p=0.000 n=10)
SpanLimits/AttributeValueLengthLimit-12              4.379µ ±  1%    4.144µ ±  1%   -5.38% (p=0.000 n=10)
SpanLimits/AttributeCountLimit-12                    4.219µ ±  2%    3.909µ ±  1%   -7.36% (p=0.000 n=10)
SpanLimits/EventCountLimit-12                        3.994µ ±  6%    3.663µ ±  1%   -8.28% (p=0.000 n=10)
SpanLimits/LinkCountLimit-12                         3.835µ ±  2%    3.619µ ±  1%   -5.63% (p=0.000 n=10)
SpanLimits/AttributePerEventCountLimit-12            4.225µ ±  3%    3.961µ ±  1%   -6.25% (p=0.000 n=10)
SpanLimits/AttributePerLinkCountLimit-12             4.218µ ±  1%    3.951µ ±  1%   -6.32% (p=0.000 n=10)
SpanSetAttributesOverCapacity-12                     1.676µ ±  2%    1.582µ ±  0%   -5.58% (p=0.000 n=10)
StartEndSpan/AlwaysSample-12                         322.3n ±  0%    279.1n ±  0%  -13.40% (p=0.000 n=10)
StartEndSpan/NeverSample-12                          153.5n ±  4%    148.1n ±  0%   -3.55% (p=0.000 n=10)
SpanWithAttributes_4/AlwaysSample-12                 527.6n ±  1%    467.7n ±  0%  -11.36% (p=0.000 n=10)
SpanWithAttributes_4/NeverSample-12                  245.1n ±  0%    227.6n ±  0%   -7.14% (p=0.000 n=10)
SpanWithAttributes_8/AlwaysSample-12                 702.7n ±  2%    638.2n ±  1%   -9.19% (p=0.000 n=10)
SpanWithAttributes_8/NeverSample-12                  336.4n ±  1%    305.0n ±  1%   -9.32% (p=0.000 n=10)
SpanWithAttributes_all/AlwaysSample-12               593.9n ±  3%    518.8n ±  1%  -12.65% (p=0.000 n=10)
SpanWithAttributes_all/NeverSample-12                267.0n ±  3%    251.6n ±  0%   -5.73% (p=0.000 n=10)
SpanWithAttributes_all_2x/AlwaysSample-12            850.2n ±  1%    749.9n ±  0%  -11.80% (p=0.000 n=10)
SpanWithAttributes_all_2x/NeverSample-12             398.4n ±  2%    350.8n ±  2%  -11.95% (p=0.000 n=10)
SpanWithEvents_4/AlwaysSample-12                     736.3n ±  9%    640.9n ±  0%  -12.96% (p=0.000 n=10)
SpanWithEvents_4/NeverSample-12                      158.1n ±  3%    149.8n ±  0%   -5.25% (p=0.000 n=10)
SpanWithEvents_8/AlwaysSample-12                    1111.5n ±  1%    995.0n ±  0%  -10.48% (p=0.000 n=10)
SpanWithEvents_8/NeverSample-12                      159.9n ±  2%    153.1n ±  0%   -4.28% (p=0.000 n=10)
SpanWithEvents_WithStackTrace/AlwaysSample-12        446.3n ±  1%    395.8n ±  0%  -11.30% (p=0.000 n=10)
SpanWithEvents_WithStackTrace/NeverSample-12         170.4n ±  1%    161.4n ±  0%   -5.25% (p=0.000 n=10)
SpanWithEvents_WithTimestamp/AlwaysSample-12         441.9n ±  1%    379.1n ±  0%  -14.19% (p=0.000 n=10)
SpanWithEvents_WithTimestamp/NeverSample-12          196.3n ±  5%    185.2n ±  1%   -5.65% (p=0.000 n=10)
TraceID_DotString-12                                 43.07n ±  1%    40.19n ±  0%   -6.69% (p=0.000 n=10)
SpanID_DotString-12                                  31.61n ±  1%    32.63n ±  0%   +3.23% (p=0.001 n=10)
SpanProcessorOnEnd/batch:_10,_spans:_10-12           163.3n ±  3%    162.3n ±  0%   -0.64% (p=0.010 n=10)
SpanProcessorOnEnd/batch:_10,_spans:_100-12          1.645µ ±  1%    1.624µ ±  0%   -1.31% (p=0.000 n=10)
SpanProcessorOnEnd/batch:_100,_spans:_10-12          162.2n ±  1%    162.5n ±  0%        ~ (p=0.587 n=10)
SpanProcessorOnEnd/batch:_100,_spans:_100-12         1.626µ ±  1%    1.623µ ±  0%        ~ (p=0.361 n=10)
SpanProcessorVerboseLogging-12                       6.795µ ±  2%    5.789µ ±  3%  -14.81% (p=0.000 n=10)
geomean                                              225.5n          211.6n         -6.19%

                                              │ private/base2.txt │           private/new2.txt            │
                                              │       B/op        │     B/op      vs base                 │
Truncate/Unlimited-12                                0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/Zero-12                                     0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/Short-12                                    0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/ASCII-12                                    0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/ValidUTF-8-12                               0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/InvalidUTF-8-12                             16.00 ± 0%       16.00 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/MixedUTF-8-12                               32.00 ± 0%       32.00 ± 0%       ~ (p=1.000 n=10) ¹
RecordingSpanSetAttributes/WithLimit/false-12      6.891Ki ± 0%     6.859Ki ± 0%  -0.45% (p=0.000 n=10)
RecordingSpanSetAttributes/WithLimit/true-12       7.023Ki ± 0%     6.992Ki ± 0%  -0.44% (p=0.000 n=10)
SpanEnd-12                                           0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
TraceStart/with_a_simple_span-12                     528.0 ± 0%       496.0 ± 0%  -6.06% (p=0.000 n=10)
TraceStart/with_several_links-12                     704.0 ± 0%       672.0 ± 0%  -4.55% (p=0.000 n=10)
TraceStart/with_attributes-12                        784.0 ± 0%       752.0 ± 0%  -4.08% (p=0.000 n=10)
SpanLimits/AttributeValueLengthLimit-12            10.56Ki ± 0%     10.53Ki ± 0%  -0.30% (p=0.000 n=10)
SpanLimits/AttributeCountLimit-12                  9.844Ki ± 0%     9.812Ki ± 0%  -0.32% (p=0.000 n=10)
SpanLimits/EventCountLimit-12                      9.422Ki ± 0%     9.391Ki ± 0%  -0.33% (p=0.000 n=10)
SpanLimits/LinkCountLimit-12                       9.031Ki ± 0%     9.000Ki ± 0%  -0.35% (p=0.000 n=10)
SpanLimits/AttributePerEventCountLimit-12          10.47Ki ± 0%     10.44Ki ± 0%  -0.30% (p=0.000 n=10)
SpanLimits/AttributePerLinkCountLimit-12           10.47Ki ± 0%     10.44Ki ± 0%  -0.30% (p=0.000 n=10)
SpanSetAttributesOverCapacity-12                     592.0 ± 0%       560.0 ± 0%  -5.41% (p=0.000 n=10)
StartEndSpan/AlwaysSample-12                         528.0 ± 0%       496.0 ± 0%  -6.06% (p=0.000 n=10)
StartEndSpan/NeverSample-12                          144.0 ± 0%       144.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_4/AlwaysSample-12                1040.0 ± 0%      1008.0 ± 0%  -3.08% (p=0.000 n=10)
SpanWithAttributes_4/NeverSample-12                  400.0 ± 0%       400.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_8/AlwaysSample-12               1.516Ki ± 0%     1.484Ki ± 0%  -2.06% (p=0.000 n=10)
SpanWithAttributes_8/NeverSample-12                  656.0 ± 0%       656.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all/AlwaysSample-12             1.141Ki ± 0%     1.109Ki ± 0%  -2.74% (p=0.000 n=10)
SpanWithAttributes_all/NeverSample-12                464.0 ± 0%       464.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all_2x/AlwaysSample-12          1.891Ki ± 0%     1.859Ki ± 0%  -1.65% (p=0.000 n=10)
SpanWithAttributes_all_2x/NeverSample-12             848.0 ± 0%       848.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_4/AlwaysSample-12                    1040.0 ± 0%      1008.0 ± 0%  -3.08% (p=0.000 n=10)
SpanWithEvents_4/NeverSample-12                      144.0 ± 0%       144.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_8/AlwaysSample-12                   1.641Ki ± 0%     1.609Ki ± 0%  -1.90% (p=0.000 n=10)
SpanWithEvents_8/NeverSample-12                      144.0 ± 0%       144.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithStackTrace/AlwaysSample-12        624.0 ± 0%       592.0 ± 0%  -5.13% (p=0.000 n=10)
SpanWithEvents_WithStackTrace/NeverSample-12         160.0 ± 0%       160.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithTimestamp/AlwaysSample-12         648.0 ± 0%       616.0 ± 0%  -4.94% (p=0.000 n=10)
SpanWithEvents_WithTimestamp/NeverSample-12          184.0 ± 0%       184.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_10,_spans:_10-12           0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_10,_spans:_100-12          0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_100,_spans:_10-12          0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_100,_spans:_100-12         0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorVerboseLogging-12                     9.547Ki ± 0%     9.234Ki ± 0%  -3.27% (p=0.000 n=10)
geomean                                                         ²                 -1.34%                ²
¹ all samples are equal
² summaries must be >0 to compute geomean

                                              │ private/base2.txt │          private/new2.txt           │
                                              │     allocs/op     │ allocs/op   vs base                 │
Truncate/Unlimited-12                                0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/Zero-12                                     0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/Short-12                                    0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/ASCII-12                                    0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/ValidUTF-8-12                               0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/InvalidUTF-8-12                             1.000 ± 0%     1.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/MixedUTF-8-12                               1.000 ± 0%     1.000 ± 0%       ~ (p=1.000 n=10) ¹
RecordingSpanSetAttributes/WithLimit/false-12        3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
RecordingSpanSetAttributes/WithLimit/true-12         10.00 ± 0%     10.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanEnd-12                                           0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
TraceStart/with_a_simple_span-12                     2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
TraceStart/with_several_links-12                     3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
TraceStart/with_attributes-12                        4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributeValueLengthLimit-12              41.00 ± 0%     41.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributeCountLimit-12                    38.00 ± 0%     38.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/EventCountLimit-12                        35.00 ± 0%     35.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/LinkCountLimit-12                         35.00 ± 0%     35.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributePerEventCountLimit-12            38.00 ± 0%     38.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributePerLinkCountLimit-12             38.00 ± 0%     38.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanSetAttributesOverCapacity-12                     3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
StartEndSpan/AlwaysSample-12                         2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
StartEndSpan/NeverSample-12                          2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_4/AlwaysSample-12                 4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_4/NeverSample-12                  3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_8/AlwaysSample-12                 4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_8/NeverSample-12                  3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all/AlwaysSample-12               4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all/NeverSample-12                3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all_2x/AlwaysSample-12            4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all_2x/NeverSample-12             3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_4/AlwaysSample-12                     5.000 ± 0%     5.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_4/NeverSample-12                      2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_8/AlwaysSample-12                     6.000 ± 0%     6.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_8/NeverSample-12                      2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithStackTrace/AlwaysSample-12        4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithStackTrace/NeverSample-12         3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithTimestamp/AlwaysSample-12         5.000 ± 0%     5.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithTimestamp/NeverSample-12          4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_10,_spans:_10-12           0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_10,_spans:_100-12          0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_100,_spans:_10-12          0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_100,_spans:_100-12         0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorVerboseLogging-12                       35.00 ± 0%     35.00 ± 0%       ~ (p=1.000 n=10) ¹
geomean                                                         ²               +0.00%                ²
¹ all samples are equal
² summaries must be >0 to compute geomean
```

See open-telemetry#6721.
jschaf added a commit to jschaf/opentelemetry-go that referenced this issue May 2, 2025
Instead of using a mutex, use atomic compare-and-swap to set the endTime.
Store unix nanoseconds as an int64 to enable atomics.

This has few nice properties:

- Span.End() no longer needs the mutex. The first call to Span.End() does an
  atomic compare-and-swap. Later calls will return early.

- We remove the isRecording method and use the public IsRecording method since
  we don't need the mutex to access endTime.

- We reduce the recordingSpan size by 32 bytes. time.Time takes 24 bytes
  compared to 8 bytes for int64 nanoseconds. We save 16 bytes each for startTime
  and endTime.

Benchstat

```
benchstat private/base2.txt private/new2.txt
goos: darwin
goarch: arm64
pkg: go.opentelemetry.io/otel/sdk/trace
cpu: Apple M2 Max
                                              │ private/base2.txt │           private/new2.txt            │
                                              │      sec/op       │    sec/op      vs base                │
Truncate/Unlimited-12                               0.2089n ±  2%   0.2090n ±  4%        ~ (p=0.698 n=10)
Truncate/Zero-12                                    0.3052n ±  1%   0.3087n ± 20%        ~ (p=0.127 n=10)
Truncate/Short-12                                   0.2081n ±  0%   0.2089n ±  1%        ~ (p=0.362 n=10)
Truncate/ASCII-12                                   0.7140n ±  2%   0.6855n ±  0%   -4.00% (p=0.000 n=10)
Truncate/ValidUTF-8-12                               1.311n ±  2%    1.303n ±  1%   -0.61% (p=0.015 n=10)
Truncate/InvalidUTF-8-12                             9.437n ±  1%    9.315n ±  3%        ~ (p=0.143 n=10)
Truncate/MixedUTF-8-12                               17.32n ±  0%    17.16n ±  2%        ~ (p=0.159 n=10)
RecordingSpanSetAttributes/WithLimit/false-12        2.080µ ±  1%    2.010µ ±  1%   -3.39% (p=0.000 n=10)
RecordingSpanSetAttributes/WithLimit/true-12         4.358µ ±  0%    4.297µ ±  0%   -1.40% (p=0.000 n=10)
SpanEnd-12                                          107.90n ± 10%    94.44n ±  1%  -12.47% (p=0.001 n=10)
TraceStart/with_a_simple_span-12                     319.5n ±  6%    293.7n ±  3%   -8.08% (p=0.000 n=10)
TraceStart/with_several_links-12                     428.3n ±  2%    411.2n ±  1%   -3.99% (p=0.000 n=10)
TraceStart/with_attributes-12                        469.6n ±  3%    430.4n ±  1%   -8.35% (p=0.000 n=10)
SpanLimits/AttributeValueLengthLimit-12              4.379µ ±  1%    4.144µ ±  1%   -5.38% (p=0.000 n=10)
SpanLimits/AttributeCountLimit-12                    4.219µ ±  2%    3.909µ ±  1%   -7.36% (p=0.000 n=10)
SpanLimits/EventCountLimit-12                        3.994µ ±  6%    3.663µ ±  1%   -8.28% (p=0.000 n=10)
SpanLimits/LinkCountLimit-12                         3.835µ ±  2%    3.619µ ±  1%   -5.63% (p=0.000 n=10)
SpanLimits/AttributePerEventCountLimit-12            4.225µ ±  3%    3.961µ ±  1%   -6.25% (p=0.000 n=10)
SpanLimits/AttributePerLinkCountLimit-12             4.218µ ±  1%    3.951µ ±  1%   -6.32% (p=0.000 n=10)
SpanSetAttributesOverCapacity-12                     1.676µ ±  2%    1.582µ ±  0%   -5.58% (p=0.000 n=10)
StartEndSpan/AlwaysSample-12                         322.3n ±  0%    279.1n ±  0%  -13.40% (p=0.000 n=10)
StartEndSpan/NeverSample-12                          153.5n ±  4%    148.1n ±  0%   -3.55% (p=0.000 n=10)
SpanWithAttributes_4/AlwaysSample-12                 527.6n ±  1%    467.7n ±  0%  -11.36% (p=0.000 n=10)
SpanWithAttributes_4/NeverSample-12                  245.1n ±  0%    227.6n ±  0%   -7.14% (p=0.000 n=10)
SpanWithAttributes_8/AlwaysSample-12                 702.7n ±  2%    638.2n ±  1%   -9.19% (p=0.000 n=10)
SpanWithAttributes_8/NeverSample-12                  336.4n ±  1%    305.0n ±  1%   -9.32% (p=0.000 n=10)
SpanWithAttributes_all/AlwaysSample-12               593.9n ±  3%    518.8n ±  1%  -12.65% (p=0.000 n=10)
SpanWithAttributes_all/NeverSample-12                267.0n ±  3%    251.6n ±  0%   -5.73% (p=0.000 n=10)
SpanWithAttributes_all_2x/AlwaysSample-12            850.2n ±  1%    749.9n ±  0%  -11.80% (p=0.000 n=10)
SpanWithAttributes_all_2x/NeverSample-12             398.4n ±  2%    350.8n ±  2%  -11.95% (p=0.000 n=10)
SpanWithEvents_4/AlwaysSample-12                     736.3n ±  9%    640.9n ±  0%  -12.96% (p=0.000 n=10)
SpanWithEvents_4/NeverSample-12                      158.1n ±  3%    149.8n ±  0%   -5.25% (p=0.000 n=10)
SpanWithEvents_8/AlwaysSample-12                    1111.5n ±  1%    995.0n ±  0%  -10.48% (p=0.000 n=10)
SpanWithEvents_8/NeverSample-12                      159.9n ±  2%    153.1n ±  0%   -4.28% (p=0.000 n=10)
SpanWithEvents_WithStackTrace/AlwaysSample-12        446.3n ±  1%    395.8n ±  0%  -11.30% (p=0.000 n=10)
SpanWithEvents_WithStackTrace/NeverSample-12         170.4n ±  1%    161.4n ±  0%   -5.25% (p=0.000 n=10)
SpanWithEvents_WithTimestamp/AlwaysSample-12         441.9n ±  1%    379.1n ±  0%  -14.19% (p=0.000 n=10)
SpanWithEvents_WithTimestamp/NeverSample-12          196.3n ±  5%    185.2n ±  1%   -5.65% (p=0.000 n=10)
TraceID_DotString-12                                 43.07n ±  1%    40.19n ±  0%   -6.69% (p=0.000 n=10)
SpanID_DotString-12                                  31.61n ±  1%    32.63n ±  0%   +3.23% (p=0.001 n=10)
SpanProcessorOnEnd/batch:_10,_spans:_10-12           163.3n ±  3%    162.3n ±  0%   -0.64% (p=0.010 n=10)
SpanProcessorOnEnd/batch:_10,_spans:_100-12          1.645µ ±  1%    1.624µ ±  0%   -1.31% (p=0.000 n=10)
SpanProcessorOnEnd/batch:_100,_spans:_10-12          162.2n ±  1%    162.5n ±  0%        ~ (p=0.587 n=10)
SpanProcessorOnEnd/batch:_100,_spans:_100-12         1.626µ ±  1%    1.623µ ±  0%        ~ (p=0.361 n=10)
SpanProcessorVerboseLogging-12                       6.795µ ±  2%    5.789µ ±  3%  -14.81% (p=0.000 n=10)
geomean                                              225.5n          211.6n         -6.19%

                                              │ private/base2.txt │           private/new2.txt            │
                                              │       B/op        │     B/op      vs base                 │
Truncate/Unlimited-12                                0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/Zero-12                                     0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/Short-12                                    0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/ASCII-12                                    0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/ValidUTF-8-12                               0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/InvalidUTF-8-12                             16.00 ± 0%       16.00 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/MixedUTF-8-12                               32.00 ± 0%       32.00 ± 0%       ~ (p=1.000 n=10) ¹
RecordingSpanSetAttributes/WithLimit/false-12      6.891Ki ± 0%     6.859Ki ± 0%  -0.45% (p=0.000 n=10)
RecordingSpanSetAttributes/WithLimit/true-12       7.023Ki ± 0%     6.992Ki ± 0%  -0.44% (p=0.000 n=10)
SpanEnd-12                                           0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
TraceStart/with_a_simple_span-12                     528.0 ± 0%       496.0 ± 0%  -6.06% (p=0.000 n=10)
TraceStart/with_several_links-12                     704.0 ± 0%       672.0 ± 0%  -4.55% (p=0.000 n=10)
TraceStart/with_attributes-12                        784.0 ± 0%       752.0 ± 0%  -4.08% (p=0.000 n=10)
SpanLimits/AttributeValueLengthLimit-12            10.56Ki ± 0%     10.53Ki ± 0%  -0.30% (p=0.000 n=10)
SpanLimits/AttributeCountLimit-12                  9.844Ki ± 0%     9.812Ki ± 0%  -0.32% (p=0.000 n=10)
SpanLimits/EventCountLimit-12                      9.422Ki ± 0%     9.391Ki ± 0%  -0.33% (p=0.000 n=10)
SpanLimits/LinkCountLimit-12                       9.031Ki ± 0%     9.000Ki ± 0%  -0.35% (p=0.000 n=10)
SpanLimits/AttributePerEventCountLimit-12          10.47Ki ± 0%     10.44Ki ± 0%  -0.30% (p=0.000 n=10)
SpanLimits/AttributePerLinkCountLimit-12           10.47Ki ± 0%     10.44Ki ± 0%  -0.30% (p=0.000 n=10)
SpanSetAttributesOverCapacity-12                     592.0 ± 0%       560.0 ± 0%  -5.41% (p=0.000 n=10)
StartEndSpan/AlwaysSample-12                         528.0 ± 0%       496.0 ± 0%  -6.06% (p=0.000 n=10)
StartEndSpan/NeverSample-12                          144.0 ± 0%       144.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_4/AlwaysSample-12                1040.0 ± 0%      1008.0 ± 0%  -3.08% (p=0.000 n=10)
SpanWithAttributes_4/NeverSample-12                  400.0 ± 0%       400.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_8/AlwaysSample-12               1.516Ki ± 0%     1.484Ki ± 0%  -2.06% (p=0.000 n=10)
SpanWithAttributes_8/NeverSample-12                  656.0 ± 0%       656.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all/AlwaysSample-12             1.141Ki ± 0%     1.109Ki ± 0%  -2.74% (p=0.000 n=10)
SpanWithAttributes_all/NeverSample-12                464.0 ± 0%       464.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all_2x/AlwaysSample-12          1.891Ki ± 0%     1.859Ki ± 0%  -1.65% (p=0.000 n=10)
SpanWithAttributes_all_2x/NeverSample-12             848.0 ± 0%       848.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_4/AlwaysSample-12                    1040.0 ± 0%      1008.0 ± 0%  -3.08% (p=0.000 n=10)
SpanWithEvents_4/NeverSample-12                      144.0 ± 0%       144.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_8/AlwaysSample-12                   1.641Ki ± 0%     1.609Ki ± 0%  -1.90% (p=0.000 n=10)
SpanWithEvents_8/NeverSample-12                      144.0 ± 0%       144.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithStackTrace/AlwaysSample-12        624.0 ± 0%       592.0 ± 0%  -5.13% (p=0.000 n=10)
SpanWithEvents_WithStackTrace/NeverSample-12         160.0 ± 0%       160.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithTimestamp/AlwaysSample-12         648.0 ± 0%       616.0 ± 0%  -4.94% (p=0.000 n=10)
SpanWithEvents_WithTimestamp/NeverSample-12          184.0 ± 0%       184.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_10,_spans:_10-12           0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_10,_spans:_100-12          0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_100,_spans:_10-12          0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_100,_spans:_100-12         0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorVerboseLogging-12                     9.547Ki ± 0%     9.234Ki ± 0%  -3.27% (p=0.000 n=10)
geomean                                                         ²                 -1.34%                ²
¹ all samples are equal
² summaries must be >0 to compute geomean

                                              │ private/base2.txt │          private/new2.txt           │
                                              │     allocs/op     │ allocs/op   vs base                 │
Truncate/Unlimited-12                                0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/Zero-12                                     0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/Short-12                                    0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/ASCII-12                                    0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/ValidUTF-8-12                               0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/InvalidUTF-8-12                             1.000 ± 0%     1.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/MixedUTF-8-12                               1.000 ± 0%     1.000 ± 0%       ~ (p=1.000 n=10) ¹
RecordingSpanSetAttributes/WithLimit/false-12        3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
RecordingSpanSetAttributes/WithLimit/true-12         10.00 ± 0%     10.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanEnd-12                                           0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
TraceStart/with_a_simple_span-12                     2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
TraceStart/with_several_links-12                     3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
TraceStart/with_attributes-12                        4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributeValueLengthLimit-12              41.00 ± 0%     41.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributeCountLimit-12                    38.00 ± 0%     38.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/EventCountLimit-12                        35.00 ± 0%     35.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/LinkCountLimit-12                         35.00 ± 0%     35.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributePerEventCountLimit-12            38.00 ± 0%     38.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributePerLinkCountLimit-12             38.00 ± 0%     38.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanSetAttributesOverCapacity-12                     3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
StartEndSpan/AlwaysSample-12                         2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
StartEndSpan/NeverSample-12                          2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_4/AlwaysSample-12                 4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_4/NeverSample-12                  3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_8/AlwaysSample-12                 4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_8/NeverSample-12                  3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all/AlwaysSample-12               4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all/NeverSample-12                3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all_2x/AlwaysSample-12            4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all_2x/NeverSample-12             3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_4/AlwaysSample-12                     5.000 ± 0%     5.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_4/NeverSample-12                      2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_8/AlwaysSample-12                     6.000 ± 0%     6.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_8/NeverSample-12                      2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithStackTrace/AlwaysSample-12        4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithStackTrace/NeverSample-12         3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithTimestamp/AlwaysSample-12         5.000 ± 0%     5.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithTimestamp/NeverSample-12          4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_10,_spans:_10-12           0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_10,_spans:_100-12          0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_100,_spans:_10-12          0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_100,_spans:_100-12         0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorVerboseLogging-12                       35.00 ± 0%     35.00 ± 0%       ~ (p=1.000 n=10) ¹
geomean                                                         ²               +0.00%                ²
¹ all samples are equal
² summaries must be >0 to compute geomean
```

See open-telemetry#6721.
jschaf added a commit to jschaf/opentelemetry-go that referenced this issue May 2, 2025
Instead of using a mutex, use atomic compare-and-swap to set the endTime.
Store unix nanoseconds as an int64 to enable atomics.

This has few nice properties:

- Span.End() no longer needs the mutex. The first call to Span.End() does an
  atomic compare-and-swap. Later calls will return early.

- We remove the isRecording method and use the public IsRecording method since
  we don't need the mutex to access endTime.

- We reduce the recordingSpan size by 32 bytes. time.Time takes 24 bytes
  compared to 8 bytes for int64 nanoseconds. We save 16 bytes each for startTime
  and endTime.

Benchstat

```
benchstat private/base2.txt private/new2.txt
goos: darwin
goarch: arm64
pkg: go.opentelemetry.io/otel/sdk/trace
cpu: Apple M2 Max
                                              │ private/base2.txt │           private/new2.txt            │
                                              │      sec/op       │    sec/op      vs base                │
Truncate/Unlimited-12                               0.2089n ±  2%   0.2090n ±  4%        ~ (p=0.698 n=10)
Truncate/Zero-12                                    0.3052n ±  1%   0.3087n ± 20%        ~ (p=0.127 n=10)
Truncate/Short-12                                   0.2081n ±  0%   0.2089n ±  1%        ~ (p=0.362 n=10)
Truncate/ASCII-12                                   0.7140n ±  2%   0.6855n ±  0%   -4.00% (p=0.000 n=10)
Truncate/ValidUTF-8-12                               1.311n ±  2%    1.303n ±  1%   -0.61% (p=0.015 n=10)
Truncate/InvalidUTF-8-12                             9.437n ±  1%    9.315n ±  3%        ~ (p=0.143 n=10)
Truncate/MixedUTF-8-12                               17.32n ±  0%    17.16n ±  2%        ~ (p=0.159 n=10)
RecordingSpanSetAttributes/WithLimit/false-12        2.080µ ±  1%    2.010µ ±  1%   -3.39% (p=0.000 n=10)
RecordingSpanSetAttributes/WithLimit/true-12         4.358µ ±  0%    4.297µ ±  0%   -1.40% (p=0.000 n=10)
SpanEnd-12                                          107.90n ± 10%    94.44n ±  1%  -12.47% (p=0.001 n=10)
TraceStart/with_a_simple_span-12                     319.5n ±  6%    293.7n ±  3%   -8.08% (p=0.000 n=10)
TraceStart/with_several_links-12                     428.3n ±  2%    411.2n ±  1%   -3.99% (p=0.000 n=10)
TraceStart/with_attributes-12                        469.6n ±  3%    430.4n ±  1%   -8.35% (p=0.000 n=10)
SpanLimits/AttributeValueLengthLimit-12              4.379µ ±  1%    4.144µ ±  1%   -5.38% (p=0.000 n=10)
SpanLimits/AttributeCountLimit-12                    4.219µ ±  2%    3.909µ ±  1%   -7.36% (p=0.000 n=10)
SpanLimits/EventCountLimit-12                        3.994µ ±  6%    3.663µ ±  1%   -8.28% (p=0.000 n=10)
SpanLimits/LinkCountLimit-12                         3.835µ ±  2%    3.619µ ±  1%   -5.63% (p=0.000 n=10)
SpanLimits/AttributePerEventCountLimit-12            4.225µ ±  3%    3.961µ ±  1%   -6.25% (p=0.000 n=10)
SpanLimits/AttributePerLinkCountLimit-12             4.218µ ±  1%    3.951µ ±  1%   -6.32% (p=0.000 n=10)
SpanSetAttributesOverCapacity-12                     1.676µ ±  2%    1.582µ ±  0%   -5.58% (p=0.000 n=10)
StartEndSpan/AlwaysSample-12                         322.3n ±  0%    279.1n ±  0%  -13.40% (p=0.000 n=10)
StartEndSpan/NeverSample-12                          153.5n ±  4%    148.1n ±  0%   -3.55% (p=0.000 n=10)
SpanWithAttributes_4/AlwaysSample-12                 527.6n ±  1%    467.7n ±  0%  -11.36% (p=0.000 n=10)
SpanWithAttributes_4/NeverSample-12                  245.1n ±  0%    227.6n ±  0%   -7.14% (p=0.000 n=10)
SpanWithAttributes_8/AlwaysSample-12                 702.7n ±  2%    638.2n ±  1%   -9.19% (p=0.000 n=10)
SpanWithAttributes_8/NeverSample-12                  336.4n ±  1%    305.0n ±  1%   -9.32% (p=0.000 n=10)
SpanWithAttributes_all/AlwaysSample-12               593.9n ±  3%    518.8n ±  1%  -12.65% (p=0.000 n=10)
SpanWithAttributes_all/NeverSample-12                267.0n ±  3%    251.6n ±  0%   -5.73% (p=0.000 n=10)
SpanWithAttributes_all_2x/AlwaysSample-12            850.2n ±  1%    749.9n ±  0%  -11.80% (p=0.000 n=10)
SpanWithAttributes_all_2x/NeverSample-12             398.4n ±  2%    350.8n ±  2%  -11.95% (p=0.000 n=10)
SpanWithEvents_4/AlwaysSample-12                     736.3n ±  9%    640.9n ±  0%  -12.96% (p=0.000 n=10)
SpanWithEvents_4/NeverSample-12                      158.1n ±  3%    149.8n ±  0%   -5.25% (p=0.000 n=10)
SpanWithEvents_8/AlwaysSample-12                    1111.5n ±  1%    995.0n ±  0%  -10.48% (p=0.000 n=10)
SpanWithEvents_8/NeverSample-12                      159.9n ±  2%    153.1n ±  0%   -4.28% (p=0.000 n=10)
SpanWithEvents_WithStackTrace/AlwaysSample-12        446.3n ±  1%    395.8n ±  0%  -11.30% (p=0.000 n=10)
SpanWithEvents_WithStackTrace/NeverSample-12         170.4n ±  1%    161.4n ±  0%   -5.25% (p=0.000 n=10)
SpanWithEvents_WithTimestamp/AlwaysSample-12         441.9n ±  1%    379.1n ±  0%  -14.19% (p=0.000 n=10)
SpanWithEvents_WithTimestamp/NeverSample-12          196.3n ±  5%    185.2n ±  1%   -5.65% (p=0.000 n=10)
TraceID_DotString-12                                 43.07n ±  1%    40.19n ±  0%   -6.69% (p=0.000 n=10)
SpanID_DotString-12                                  31.61n ±  1%    32.63n ±  0%   +3.23% (p=0.001 n=10)
SpanProcessorOnEnd/batch:_10,_spans:_10-12           163.3n ±  3%    162.3n ±  0%   -0.64% (p=0.010 n=10)
SpanProcessorOnEnd/batch:_10,_spans:_100-12          1.645µ ±  1%    1.624µ ±  0%   -1.31% (p=0.000 n=10)
SpanProcessorOnEnd/batch:_100,_spans:_10-12          162.2n ±  1%    162.5n ±  0%        ~ (p=0.587 n=10)
SpanProcessorOnEnd/batch:_100,_spans:_100-12         1.626µ ±  1%    1.623µ ±  0%        ~ (p=0.361 n=10)
SpanProcessorVerboseLogging-12                       6.795µ ±  2%    5.789µ ±  3%  -14.81% (p=0.000 n=10)
geomean                                              225.5n          211.6n         -6.19%

                                              │ private/base2.txt │           private/new2.txt            │
                                              │       B/op        │     B/op      vs base                 │
Truncate/Unlimited-12                                0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/Zero-12                                     0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/Short-12                                    0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/ASCII-12                                    0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/ValidUTF-8-12                               0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/InvalidUTF-8-12                             16.00 ± 0%       16.00 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/MixedUTF-8-12                               32.00 ± 0%       32.00 ± 0%       ~ (p=1.000 n=10) ¹
RecordingSpanSetAttributes/WithLimit/false-12      6.891Ki ± 0%     6.859Ki ± 0%  -0.45% (p=0.000 n=10)
RecordingSpanSetAttributes/WithLimit/true-12       7.023Ki ± 0%     6.992Ki ± 0%  -0.44% (p=0.000 n=10)
SpanEnd-12                                           0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
TraceStart/with_a_simple_span-12                     528.0 ± 0%       496.0 ± 0%  -6.06% (p=0.000 n=10)
TraceStart/with_several_links-12                     704.0 ± 0%       672.0 ± 0%  -4.55% (p=0.000 n=10)
TraceStart/with_attributes-12                        784.0 ± 0%       752.0 ± 0%  -4.08% (p=0.000 n=10)
SpanLimits/AttributeValueLengthLimit-12            10.56Ki ± 0%     10.53Ki ± 0%  -0.30% (p=0.000 n=10)
SpanLimits/AttributeCountLimit-12                  9.844Ki ± 0%     9.812Ki ± 0%  -0.32% (p=0.000 n=10)
SpanLimits/EventCountLimit-12                      9.422Ki ± 0%     9.391Ki ± 0%  -0.33% (p=0.000 n=10)
SpanLimits/LinkCountLimit-12                       9.031Ki ± 0%     9.000Ki ± 0%  -0.35% (p=0.000 n=10)
SpanLimits/AttributePerEventCountLimit-12          10.47Ki ± 0%     10.44Ki ± 0%  -0.30% (p=0.000 n=10)
SpanLimits/AttributePerLinkCountLimit-12           10.47Ki ± 0%     10.44Ki ± 0%  -0.30% (p=0.000 n=10)
SpanSetAttributesOverCapacity-12                     592.0 ± 0%       560.0 ± 0%  -5.41% (p=0.000 n=10)
StartEndSpan/AlwaysSample-12                         528.0 ± 0%       496.0 ± 0%  -6.06% (p=0.000 n=10)
StartEndSpan/NeverSample-12                          144.0 ± 0%       144.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_4/AlwaysSample-12                1040.0 ± 0%      1008.0 ± 0%  -3.08% (p=0.000 n=10)
SpanWithAttributes_4/NeverSample-12                  400.0 ± 0%       400.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_8/AlwaysSample-12               1.516Ki ± 0%     1.484Ki ± 0%  -2.06% (p=0.000 n=10)
SpanWithAttributes_8/NeverSample-12                  656.0 ± 0%       656.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all/AlwaysSample-12             1.141Ki ± 0%     1.109Ki ± 0%  -2.74% (p=0.000 n=10)
SpanWithAttributes_all/NeverSample-12                464.0 ± 0%       464.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all_2x/AlwaysSample-12          1.891Ki ± 0%     1.859Ki ± 0%  -1.65% (p=0.000 n=10)
SpanWithAttributes_all_2x/NeverSample-12             848.0 ± 0%       848.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_4/AlwaysSample-12                    1040.0 ± 0%      1008.0 ± 0%  -3.08% (p=0.000 n=10)
SpanWithEvents_4/NeverSample-12                      144.0 ± 0%       144.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_8/AlwaysSample-12                   1.641Ki ± 0%     1.609Ki ± 0%  -1.90% (p=0.000 n=10)
SpanWithEvents_8/NeverSample-12                      144.0 ± 0%       144.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithStackTrace/AlwaysSample-12        624.0 ± 0%       592.0 ± 0%  -5.13% (p=0.000 n=10)
SpanWithEvents_WithStackTrace/NeverSample-12         160.0 ± 0%       160.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithTimestamp/AlwaysSample-12         648.0 ± 0%       616.0 ± 0%  -4.94% (p=0.000 n=10)
SpanWithEvents_WithTimestamp/NeverSample-12          184.0 ± 0%       184.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_10,_spans:_10-12           0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_10,_spans:_100-12          0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_100,_spans:_10-12          0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_100,_spans:_100-12         0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorVerboseLogging-12                     9.547Ki ± 0%     9.234Ki ± 0%  -3.27% (p=0.000 n=10)
geomean                                                         ²                 -1.34%                ²
¹ all samples are equal
² summaries must be >0 to compute geomean

                                              │ private/base2.txt │          private/new2.txt           │
                                              │     allocs/op     │ allocs/op   vs base                 │
Truncate/Unlimited-12                                0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/Zero-12                                     0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/Short-12                                    0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/ASCII-12                                    0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/ValidUTF-8-12                               0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/InvalidUTF-8-12                             1.000 ± 0%     1.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/MixedUTF-8-12                               1.000 ± 0%     1.000 ± 0%       ~ (p=1.000 n=10) ¹
RecordingSpanSetAttributes/WithLimit/false-12        3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
RecordingSpanSetAttributes/WithLimit/true-12         10.00 ± 0%     10.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanEnd-12                                           0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
TraceStart/with_a_simple_span-12                     2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
TraceStart/with_several_links-12                     3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
TraceStart/with_attributes-12                        4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributeValueLengthLimit-12              41.00 ± 0%     41.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributeCountLimit-12                    38.00 ± 0%     38.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/EventCountLimit-12                        35.00 ± 0%     35.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/LinkCountLimit-12                         35.00 ± 0%     35.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributePerEventCountLimit-12            38.00 ± 0%     38.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributePerLinkCountLimit-12             38.00 ± 0%     38.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanSetAttributesOverCapacity-12                     3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
StartEndSpan/AlwaysSample-12                         2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
StartEndSpan/NeverSample-12                          2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_4/AlwaysSample-12                 4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_4/NeverSample-12                  3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_8/AlwaysSample-12                 4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_8/NeverSample-12                  3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all/AlwaysSample-12               4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all/NeverSample-12                3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all_2x/AlwaysSample-12            4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all_2x/NeverSample-12             3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_4/AlwaysSample-12                     5.000 ± 0%     5.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_4/NeverSample-12                      2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_8/AlwaysSample-12                     6.000 ± 0%     6.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_8/NeverSample-12                      2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithStackTrace/AlwaysSample-12        4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithStackTrace/NeverSample-12         3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithTimestamp/AlwaysSample-12         5.000 ± 0%     5.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithTimestamp/NeverSample-12          4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_10,_spans:_10-12           0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_10,_spans:_100-12          0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_100,_spans:_10-12          0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_100,_spans:_100-12         0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorVerboseLogging-12                       35.00 ± 0%     35.00 ± 0%       ~ (p=1.000 n=10) ¹
geomean                                                         ²               +0.00%                ²
¹ all samples are equal
² summaries must be >0 to compute geomean
```

See open-telemetry#6721.
jschaf added a commit to jschaf/opentelemetry-go that referenced this issue May 6, 2025
Instead of using a mutex, use atomic compare-and-swap to set the endTime.
Store unix nanoseconds as an int64 to enable atomics.

This has few nice properties:

- Span.End() no longer needs the mutex. The first call to Span.End() does an
  atomic compare-and-swap. Later calls will return early.

- We remove the isRecording method and use the public IsRecording method since
  we don't need the mutex to access endTime.

- We reduce the recordingSpan size by 32 bytes. time.Time takes 24 bytes
  compared to 8 bytes for int64 nanoseconds. We save 16 bytes each for startTime
  and endTime.

Benchstat

```
benchstat private/base2.txt private/new2.txt
goos: darwin
goarch: arm64
pkg: go.opentelemetry.io/otel/sdk/trace
cpu: Apple M2 Max
                                              │ private/base2.txt │           private/new2.txt            │
                                              │      sec/op       │    sec/op      vs base                │
Truncate/Unlimited-12                               0.2089n ±  2%   0.2090n ±  4%        ~ (p=0.698 n=10)
Truncate/Zero-12                                    0.3052n ±  1%   0.3087n ± 20%        ~ (p=0.127 n=10)
Truncate/Short-12                                   0.2081n ±  0%   0.2089n ±  1%        ~ (p=0.362 n=10)
Truncate/ASCII-12                                   0.7140n ±  2%   0.6855n ±  0%   -4.00% (p=0.000 n=10)
Truncate/ValidUTF-8-12                               1.311n ±  2%    1.303n ±  1%   -0.61% (p=0.015 n=10)
Truncate/InvalidUTF-8-12                             9.437n ±  1%    9.315n ±  3%        ~ (p=0.143 n=10)
Truncate/MixedUTF-8-12                               17.32n ±  0%    17.16n ±  2%        ~ (p=0.159 n=10)
RecordingSpanSetAttributes/WithLimit/false-12        2.080µ ±  1%    2.010µ ±  1%   -3.39% (p=0.000 n=10)
RecordingSpanSetAttributes/WithLimit/true-12         4.358µ ±  0%    4.297µ ±  0%   -1.40% (p=0.000 n=10)
SpanEnd-12                                          107.90n ± 10%    94.44n ±  1%  -12.47% (p=0.001 n=10)
TraceStart/with_a_simple_span-12                     319.5n ±  6%    293.7n ±  3%   -8.08% (p=0.000 n=10)
TraceStart/with_several_links-12                     428.3n ±  2%    411.2n ±  1%   -3.99% (p=0.000 n=10)
TraceStart/with_attributes-12                        469.6n ±  3%    430.4n ±  1%   -8.35% (p=0.000 n=10)
SpanLimits/AttributeValueLengthLimit-12              4.379µ ±  1%    4.144µ ±  1%   -5.38% (p=0.000 n=10)
SpanLimits/AttributeCountLimit-12                    4.219µ ±  2%    3.909µ ±  1%   -7.36% (p=0.000 n=10)
SpanLimits/EventCountLimit-12                        3.994µ ±  6%    3.663µ ±  1%   -8.28% (p=0.000 n=10)
SpanLimits/LinkCountLimit-12                         3.835µ ±  2%    3.619µ ±  1%   -5.63% (p=0.000 n=10)
SpanLimits/AttributePerEventCountLimit-12            4.225µ ±  3%    3.961µ ±  1%   -6.25% (p=0.000 n=10)
SpanLimits/AttributePerLinkCountLimit-12             4.218µ ±  1%    3.951µ ±  1%   -6.32% (p=0.000 n=10)
SpanSetAttributesOverCapacity-12                     1.676µ ±  2%    1.582µ ±  0%   -5.58% (p=0.000 n=10)
StartEndSpan/AlwaysSample-12                         322.3n ±  0%    279.1n ±  0%  -13.40% (p=0.000 n=10)
StartEndSpan/NeverSample-12                          153.5n ±  4%    148.1n ±  0%   -3.55% (p=0.000 n=10)
SpanWithAttributes_4/AlwaysSample-12                 527.6n ±  1%    467.7n ±  0%  -11.36% (p=0.000 n=10)
SpanWithAttributes_4/NeverSample-12                  245.1n ±  0%    227.6n ±  0%   -7.14% (p=0.000 n=10)
SpanWithAttributes_8/AlwaysSample-12                 702.7n ±  2%    638.2n ±  1%   -9.19% (p=0.000 n=10)
SpanWithAttributes_8/NeverSample-12                  336.4n ±  1%    305.0n ±  1%   -9.32% (p=0.000 n=10)
SpanWithAttributes_all/AlwaysSample-12               593.9n ±  3%    518.8n ±  1%  -12.65% (p=0.000 n=10)
SpanWithAttributes_all/NeverSample-12                267.0n ±  3%    251.6n ±  0%   -5.73% (p=0.000 n=10)
SpanWithAttributes_all_2x/AlwaysSample-12            850.2n ±  1%    749.9n ±  0%  -11.80% (p=0.000 n=10)
SpanWithAttributes_all_2x/NeverSample-12             398.4n ±  2%    350.8n ±  2%  -11.95% (p=0.000 n=10)
SpanWithEvents_4/AlwaysSample-12                     736.3n ±  9%    640.9n ±  0%  -12.96% (p=0.000 n=10)
SpanWithEvents_4/NeverSample-12                      158.1n ±  3%    149.8n ±  0%   -5.25% (p=0.000 n=10)
SpanWithEvents_8/AlwaysSample-12                    1111.5n ±  1%    995.0n ±  0%  -10.48% (p=0.000 n=10)
SpanWithEvents_8/NeverSample-12                      159.9n ±  2%    153.1n ±  0%   -4.28% (p=0.000 n=10)
SpanWithEvents_WithStackTrace/AlwaysSample-12        446.3n ±  1%    395.8n ±  0%  -11.30% (p=0.000 n=10)
SpanWithEvents_WithStackTrace/NeverSample-12         170.4n ±  1%    161.4n ±  0%   -5.25% (p=0.000 n=10)
SpanWithEvents_WithTimestamp/AlwaysSample-12         441.9n ±  1%    379.1n ±  0%  -14.19% (p=0.000 n=10)
SpanWithEvents_WithTimestamp/NeverSample-12          196.3n ±  5%    185.2n ±  1%   -5.65% (p=0.000 n=10)
TraceID_DotString-12                                 43.07n ±  1%    40.19n ±  0%   -6.69% (p=0.000 n=10)
SpanID_DotString-12                                  31.61n ±  1%    32.63n ±  0%   +3.23% (p=0.001 n=10)
SpanProcessorOnEnd/batch:_10,_spans:_10-12           163.3n ±  3%    162.3n ±  0%   -0.64% (p=0.010 n=10)
SpanProcessorOnEnd/batch:_10,_spans:_100-12          1.645µ ±  1%    1.624µ ±  0%   -1.31% (p=0.000 n=10)
SpanProcessorOnEnd/batch:_100,_spans:_10-12          162.2n ±  1%    162.5n ±  0%        ~ (p=0.587 n=10)
SpanProcessorOnEnd/batch:_100,_spans:_100-12         1.626µ ±  1%    1.623µ ±  0%        ~ (p=0.361 n=10)
SpanProcessorVerboseLogging-12                       6.795µ ±  2%    5.789µ ±  3%  -14.81% (p=0.000 n=10)
geomean                                              225.5n          211.6n         -6.19%

                                              │ private/base2.txt │           private/new2.txt            │
                                              │       B/op        │     B/op      vs base                 │
Truncate/Unlimited-12                                0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/Zero-12                                     0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/Short-12                                    0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/ASCII-12                                    0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/ValidUTF-8-12                               0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/InvalidUTF-8-12                             16.00 ± 0%       16.00 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/MixedUTF-8-12                               32.00 ± 0%       32.00 ± 0%       ~ (p=1.000 n=10) ¹
RecordingSpanSetAttributes/WithLimit/false-12      6.891Ki ± 0%     6.859Ki ± 0%  -0.45% (p=0.000 n=10)
RecordingSpanSetAttributes/WithLimit/true-12       7.023Ki ± 0%     6.992Ki ± 0%  -0.44% (p=0.000 n=10)
SpanEnd-12                                           0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
TraceStart/with_a_simple_span-12                     528.0 ± 0%       496.0 ± 0%  -6.06% (p=0.000 n=10)
TraceStart/with_several_links-12                     704.0 ± 0%       672.0 ± 0%  -4.55% (p=0.000 n=10)
TraceStart/with_attributes-12                        784.0 ± 0%       752.0 ± 0%  -4.08% (p=0.000 n=10)
SpanLimits/AttributeValueLengthLimit-12            10.56Ki ± 0%     10.53Ki ± 0%  -0.30% (p=0.000 n=10)
SpanLimits/AttributeCountLimit-12                  9.844Ki ± 0%     9.812Ki ± 0%  -0.32% (p=0.000 n=10)
SpanLimits/EventCountLimit-12                      9.422Ki ± 0%     9.391Ki ± 0%  -0.33% (p=0.000 n=10)
SpanLimits/LinkCountLimit-12                       9.031Ki ± 0%     9.000Ki ± 0%  -0.35% (p=0.000 n=10)
SpanLimits/AttributePerEventCountLimit-12          10.47Ki ± 0%     10.44Ki ± 0%  -0.30% (p=0.000 n=10)
SpanLimits/AttributePerLinkCountLimit-12           10.47Ki ± 0%     10.44Ki ± 0%  -0.30% (p=0.000 n=10)
SpanSetAttributesOverCapacity-12                     592.0 ± 0%       560.0 ± 0%  -5.41% (p=0.000 n=10)
StartEndSpan/AlwaysSample-12                         528.0 ± 0%       496.0 ± 0%  -6.06% (p=0.000 n=10)
StartEndSpan/NeverSample-12                          144.0 ± 0%       144.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_4/AlwaysSample-12                1040.0 ± 0%      1008.0 ± 0%  -3.08% (p=0.000 n=10)
SpanWithAttributes_4/NeverSample-12                  400.0 ± 0%       400.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_8/AlwaysSample-12               1.516Ki ± 0%     1.484Ki ± 0%  -2.06% (p=0.000 n=10)
SpanWithAttributes_8/NeverSample-12                  656.0 ± 0%       656.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all/AlwaysSample-12             1.141Ki ± 0%     1.109Ki ± 0%  -2.74% (p=0.000 n=10)
SpanWithAttributes_all/NeverSample-12                464.0 ± 0%       464.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all_2x/AlwaysSample-12          1.891Ki ± 0%     1.859Ki ± 0%  -1.65% (p=0.000 n=10)
SpanWithAttributes_all_2x/NeverSample-12             848.0 ± 0%       848.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_4/AlwaysSample-12                    1040.0 ± 0%      1008.0 ± 0%  -3.08% (p=0.000 n=10)
SpanWithEvents_4/NeverSample-12                      144.0 ± 0%       144.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_8/AlwaysSample-12                   1.641Ki ± 0%     1.609Ki ± 0%  -1.90% (p=0.000 n=10)
SpanWithEvents_8/NeverSample-12                      144.0 ± 0%       144.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithStackTrace/AlwaysSample-12        624.0 ± 0%       592.0 ± 0%  -5.13% (p=0.000 n=10)
SpanWithEvents_WithStackTrace/NeverSample-12         160.0 ± 0%       160.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithTimestamp/AlwaysSample-12         648.0 ± 0%       616.0 ± 0%  -4.94% (p=0.000 n=10)
SpanWithEvents_WithTimestamp/NeverSample-12          184.0 ± 0%       184.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_10,_spans:_10-12           0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_10,_spans:_100-12          0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_100,_spans:_10-12          0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_100,_spans:_100-12         0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorVerboseLogging-12                     9.547Ki ± 0%     9.234Ki ± 0%  -3.27% (p=0.000 n=10)
geomean                                                         ²                 -1.34%                ²
¹ all samples are equal
² summaries must be >0 to compute geomean

                                              │ private/base2.txt │          private/new2.txt           │
                                              │     allocs/op     │ allocs/op   vs base                 │
Truncate/Unlimited-12                                0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/Zero-12                                     0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/Short-12                                    0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/ASCII-12                                    0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/ValidUTF-8-12                               0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/InvalidUTF-8-12                             1.000 ± 0%     1.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/MixedUTF-8-12                               1.000 ± 0%     1.000 ± 0%       ~ (p=1.000 n=10) ¹
RecordingSpanSetAttributes/WithLimit/false-12        3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
RecordingSpanSetAttributes/WithLimit/true-12         10.00 ± 0%     10.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanEnd-12                                           0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
TraceStart/with_a_simple_span-12                     2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
TraceStart/with_several_links-12                     3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
TraceStart/with_attributes-12                        4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributeValueLengthLimit-12              41.00 ± 0%     41.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributeCountLimit-12                    38.00 ± 0%     38.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/EventCountLimit-12                        35.00 ± 0%     35.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/LinkCountLimit-12                         35.00 ± 0%     35.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributePerEventCountLimit-12            38.00 ± 0%     38.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributePerLinkCountLimit-12             38.00 ± 0%     38.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanSetAttributesOverCapacity-12                     3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
StartEndSpan/AlwaysSample-12                         2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
StartEndSpan/NeverSample-12                          2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_4/AlwaysSample-12                 4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_4/NeverSample-12                  3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_8/AlwaysSample-12                 4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_8/NeverSample-12                  3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all/AlwaysSample-12               4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all/NeverSample-12                3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all_2x/AlwaysSample-12            4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all_2x/NeverSample-12             3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_4/AlwaysSample-12                     5.000 ± 0%     5.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_4/NeverSample-12                      2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_8/AlwaysSample-12                     6.000 ± 0%     6.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_8/NeverSample-12                      2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithStackTrace/AlwaysSample-12        4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithStackTrace/NeverSample-12         3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithTimestamp/AlwaysSample-12         5.000 ± 0%     5.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithTimestamp/NeverSample-12          4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_10,_spans:_10-12           0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_10,_spans:_100-12          0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_100,_spans:_10-12          0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_100,_spans:_100-12         0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorVerboseLogging-12                       35.00 ± 0%     35.00 ± 0%       ~ (p=1.000 n=10) ¹
geomean                                                         ²               +0.00%                ²
¹ all samples are equal
² summaries must be >0 to compute geomean
```

See open-telemetry#6721.
jschaf added a commit to jschaf/opentelemetry-go that referenced this issue May 6, 2025
Instead of using a mutex, use atomic compare-and-swap to set the endTime.
Store unix nanoseconds as an int64 to enable atomics.

This has few nice properties:

- Span.End() no longer needs the mutex. The first call to Span.End() does an
  atomic compare-and-swap. Later calls will return early.

- We remove the isRecording method and use the public IsRecording method since
  we don't need the mutex to access endTime.

- We reduce the recordingSpan size by 32 bytes. time.Time takes 24 bytes
  compared to 8 bytes for int64 nanoseconds. We save 16 bytes each for startTime
  and endTime.

Benchstat

```
benchstat private/base2.txt private/new2.txt
goos: darwin
goarch: arm64
pkg: go.opentelemetry.io/otel/sdk/trace
cpu: Apple M2 Max
                                              │ private/base2.txt │           private/new2.txt            │
                                              │      sec/op       │    sec/op      vs base                │
Truncate/Unlimited-12                               0.2089n ±  2%   0.2090n ±  4%        ~ (p=0.698 n=10)
Truncate/Zero-12                                    0.3052n ±  1%   0.3087n ± 20%        ~ (p=0.127 n=10)
Truncate/Short-12                                   0.2081n ±  0%   0.2089n ±  1%        ~ (p=0.362 n=10)
Truncate/ASCII-12                                   0.7140n ±  2%   0.6855n ±  0%   -4.00% (p=0.000 n=10)
Truncate/ValidUTF-8-12                               1.311n ±  2%    1.303n ±  1%   -0.61% (p=0.015 n=10)
Truncate/InvalidUTF-8-12                             9.437n ±  1%    9.315n ±  3%        ~ (p=0.143 n=10)
Truncate/MixedUTF-8-12                               17.32n ±  0%    17.16n ±  2%        ~ (p=0.159 n=10)
RecordingSpanSetAttributes/WithLimit/false-12        2.080µ ±  1%    2.010µ ±  1%   -3.39% (p=0.000 n=10)
RecordingSpanSetAttributes/WithLimit/true-12         4.358µ ±  0%    4.297µ ±  0%   -1.40% (p=0.000 n=10)
SpanEnd-12                                          107.90n ± 10%    94.44n ±  1%  -12.47% (p=0.001 n=10)
TraceStart/with_a_simple_span-12                     319.5n ±  6%    293.7n ±  3%   -8.08% (p=0.000 n=10)
TraceStart/with_several_links-12                     428.3n ±  2%    411.2n ±  1%   -3.99% (p=0.000 n=10)
TraceStart/with_attributes-12                        469.6n ±  3%    430.4n ±  1%   -8.35% (p=0.000 n=10)
SpanLimits/AttributeValueLengthLimit-12              4.379µ ±  1%    4.144µ ±  1%   -5.38% (p=0.000 n=10)
SpanLimits/AttributeCountLimit-12                    4.219µ ±  2%    3.909µ ±  1%   -7.36% (p=0.000 n=10)
SpanLimits/EventCountLimit-12                        3.994µ ±  6%    3.663µ ±  1%   -8.28% (p=0.000 n=10)
SpanLimits/LinkCountLimit-12                         3.835µ ±  2%    3.619µ ±  1%   -5.63% (p=0.000 n=10)
SpanLimits/AttributePerEventCountLimit-12            4.225µ ±  3%    3.961µ ±  1%   -6.25% (p=0.000 n=10)
SpanLimits/AttributePerLinkCountLimit-12             4.218µ ±  1%    3.951µ ±  1%   -6.32% (p=0.000 n=10)
SpanSetAttributesOverCapacity-12                     1.676µ ±  2%    1.582µ ±  0%   -5.58% (p=0.000 n=10)
StartEndSpan/AlwaysSample-12                         322.3n ±  0%    279.1n ±  0%  -13.40% (p=0.000 n=10)
StartEndSpan/NeverSample-12                          153.5n ±  4%    148.1n ±  0%   -3.55% (p=0.000 n=10)
SpanWithAttributes_4/AlwaysSample-12                 527.6n ±  1%    467.7n ±  0%  -11.36% (p=0.000 n=10)
SpanWithAttributes_4/NeverSample-12                  245.1n ±  0%    227.6n ±  0%   -7.14% (p=0.000 n=10)
SpanWithAttributes_8/AlwaysSample-12                 702.7n ±  2%    638.2n ±  1%   -9.19% (p=0.000 n=10)
SpanWithAttributes_8/NeverSample-12                  336.4n ±  1%    305.0n ±  1%   -9.32% (p=0.000 n=10)
SpanWithAttributes_all/AlwaysSample-12               593.9n ±  3%    518.8n ±  1%  -12.65% (p=0.000 n=10)
SpanWithAttributes_all/NeverSample-12                267.0n ±  3%    251.6n ±  0%   -5.73% (p=0.000 n=10)
SpanWithAttributes_all_2x/AlwaysSample-12            850.2n ±  1%    749.9n ±  0%  -11.80% (p=0.000 n=10)
SpanWithAttributes_all_2x/NeverSample-12             398.4n ±  2%    350.8n ±  2%  -11.95% (p=0.000 n=10)
SpanWithEvents_4/AlwaysSample-12                     736.3n ±  9%    640.9n ±  0%  -12.96% (p=0.000 n=10)
SpanWithEvents_4/NeverSample-12                      158.1n ±  3%    149.8n ±  0%   -5.25% (p=0.000 n=10)
SpanWithEvents_8/AlwaysSample-12                    1111.5n ±  1%    995.0n ±  0%  -10.48% (p=0.000 n=10)
SpanWithEvents_8/NeverSample-12                      159.9n ±  2%    153.1n ±  0%   -4.28% (p=0.000 n=10)
SpanWithEvents_WithStackTrace/AlwaysSample-12        446.3n ±  1%    395.8n ±  0%  -11.30% (p=0.000 n=10)
SpanWithEvents_WithStackTrace/NeverSample-12         170.4n ±  1%    161.4n ±  0%   -5.25% (p=0.000 n=10)
SpanWithEvents_WithTimestamp/AlwaysSample-12         441.9n ±  1%    379.1n ±  0%  -14.19% (p=0.000 n=10)
SpanWithEvents_WithTimestamp/NeverSample-12          196.3n ±  5%    185.2n ±  1%   -5.65% (p=0.000 n=10)
TraceID_DotString-12                                 43.07n ±  1%    40.19n ±  0%   -6.69% (p=0.000 n=10)
SpanID_DotString-12                                  31.61n ±  1%    32.63n ±  0%   +3.23% (p=0.001 n=10)
SpanProcessorOnEnd/batch:_10,_spans:_10-12           163.3n ±  3%    162.3n ±  0%   -0.64% (p=0.010 n=10)
SpanProcessorOnEnd/batch:_10,_spans:_100-12          1.645µ ±  1%    1.624µ ±  0%   -1.31% (p=0.000 n=10)
SpanProcessorOnEnd/batch:_100,_spans:_10-12          162.2n ±  1%    162.5n ±  0%        ~ (p=0.587 n=10)
SpanProcessorOnEnd/batch:_100,_spans:_100-12         1.626µ ±  1%    1.623µ ±  0%        ~ (p=0.361 n=10)
SpanProcessorVerboseLogging-12                       6.795µ ±  2%    5.789µ ±  3%  -14.81% (p=0.000 n=10)
geomean                                              225.5n          211.6n         -6.19%

                                              │ private/base2.txt │           private/new2.txt            │
                                              │       B/op        │     B/op      vs base                 │
Truncate/Unlimited-12                                0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/Zero-12                                     0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/Short-12                                    0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/ASCII-12                                    0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/ValidUTF-8-12                               0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/InvalidUTF-8-12                             16.00 ± 0%       16.00 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/MixedUTF-8-12                               32.00 ± 0%       32.00 ± 0%       ~ (p=1.000 n=10) ¹
RecordingSpanSetAttributes/WithLimit/false-12      6.891Ki ± 0%     6.859Ki ± 0%  -0.45% (p=0.000 n=10)
RecordingSpanSetAttributes/WithLimit/true-12       7.023Ki ± 0%     6.992Ki ± 0%  -0.44% (p=0.000 n=10)
SpanEnd-12                                           0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
TraceStart/with_a_simple_span-12                     528.0 ± 0%       496.0 ± 0%  -6.06% (p=0.000 n=10)
TraceStart/with_several_links-12                     704.0 ± 0%       672.0 ± 0%  -4.55% (p=0.000 n=10)
TraceStart/with_attributes-12                        784.0 ± 0%       752.0 ± 0%  -4.08% (p=0.000 n=10)
SpanLimits/AttributeValueLengthLimit-12            10.56Ki ± 0%     10.53Ki ± 0%  -0.30% (p=0.000 n=10)
SpanLimits/AttributeCountLimit-12                  9.844Ki ± 0%     9.812Ki ± 0%  -0.32% (p=0.000 n=10)
SpanLimits/EventCountLimit-12                      9.422Ki ± 0%     9.391Ki ± 0%  -0.33% (p=0.000 n=10)
SpanLimits/LinkCountLimit-12                       9.031Ki ± 0%     9.000Ki ± 0%  -0.35% (p=0.000 n=10)
SpanLimits/AttributePerEventCountLimit-12          10.47Ki ± 0%     10.44Ki ± 0%  -0.30% (p=0.000 n=10)
SpanLimits/AttributePerLinkCountLimit-12           10.47Ki ± 0%     10.44Ki ± 0%  -0.30% (p=0.000 n=10)
SpanSetAttributesOverCapacity-12                     592.0 ± 0%       560.0 ± 0%  -5.41% (p=0.000 n=10)
StartEndSpan/AlwaysSample-12                         528.0 ± 0%       496.0 ± 0%  -6.06% (p=0.000 n=10)
StartEndSpan/NeverSample-12                          144.0 ± 0%       144.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_4/AlwaysSample-12                1040.0 ± 0%      1008.0 ± 0%  -3.08% (p=0.000 n=10)
SpanWithAttributes_4/NeverSample-12                  400.0 ± 0%       400.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_8/AlwaysSample-12               1.516Ki ± 0%     1.484Ki ± 0%  -2.06% (p=0.000 n=10)
SpanWithAttributes_8/NeverSample-12                  656.0 ± 0%       656.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all/AlwaysSample-12             1.141Ki ± 0%     1.109Ki ± 0%  -2.74% (p=0.000 n=10)
SpanWithAttributes_all/NeverSample-12                464.0 ± 0%       464.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all_2x/AlwaysSample-12          1.891Ki ± 0%     1.859Ki ± 0%  -1.65% (p=0.000 n=10)
SpanWithAttributes_all_2x/NeverSample-12             848.0 ± 0%       848.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_4/AlwaysSample-12                    1040.0 ± 0%      1008.0 ± 0%  -3.08% (p=0.000 n=10)
SpanWithEvents_4/NeverSample-12                      144.0 ± 0%       144.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_8/AlwaysSample-12                   1.641Ki ± 0%     1.609Ki ± 0%  -1.90% (p=0.000 n=10)
SpanWithEvents_8/NeverSample-12                      144.0 ± 0%       144.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithStackTrace/AlwaysSample-12        624.0 ± 0%       592.0 ± 0%  -5.13% (p=0.000 n=10)
SpanWithEvents_WithStackTrace/NeverSample-12         160.0 ± 0%       160.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithTimestamp/AlwaysSample-12         648.0 ± 0%       616.0 ± 0%  -4.94% (p=0.000 n=10)
SpanWithEvents_WithTimestamp/NeverSample-12          184.0 ± 0%       184.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_10,_spans:_10-12           0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_10,_spans:_100-12          0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_100,_spans:_10-12          0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_100,_spans:_100-12         0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorVerboseLogging-12                     9.547Ki ± 0%     9.234Ki ± 0%  -3.27% (p=0.000 n=10)
geomean                                                         ²                 -1.34%                ²
¹ all samples are equal
² summaries must be >0 to compute geomean

                                              │ private/base2.txt │          private/new2.txt           │
                                              │     allocs/op     │ allocs/op   vs base                 │
Truncate/Unlimited-12                                0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/Zero-12                                     0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/Short-12                                    0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/ASCII-12                                    0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/ValidUTF-8-12                               0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/InvalidUTF-8-12                             1.000 ± 0%     1.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/MixedUTF-8-12                               1.000 ± 0%     1.000 ± 0%       ~ (p=1.000 n=10) ¹
RecordingSpanSetAttributes/WithLimit/false-12        3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
RecordingSpanSetAttributes/WithLimit/true-12         10.00 ± 0%     10.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanEnd-12                                           0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
TraceStart/with_a_simple_span-12                     2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
TraceStart/with_several_links-12                     3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
TraceStart/with_attributes-12                        4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributeValueLengthLimit-12              41.00 ± 0%     41.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributeCountLimit-12                    38.00 ± 0%     38.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/EventCountLimit-12                        35.00 ± 0%     35.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/LinkCountLimit-12                         35.00 ± 0%     35.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributePerEventCountLimit-12            38.00 ± 0%     38.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributePerLinkCountLimit-12             38.00 ± 0%     38.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanSetAttributesOverCapacity-12                     3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
StartEndSpan/AlwaysSample-12                         2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
StartEndSpan/NeverSample-12                          2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_4/AlwaysSample-12                 4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_4/NeverSample-12                  3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_8/AlwaysSample-12                 4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_8/NeverSample-12                  3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all/AlwaysSample-12               4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all/NeverSample-12                3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all_2x/AlwaysSample-12            4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all_2x/NeverSample-12             3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_4/AlwaysSample-12                     5.000 ± 0%     5.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_4/NeverSample-12                      2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_8/AlwaysSample-12                     6.000 ± 0%     6.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_8/NeverSample-12                      2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithStackTrace/AlwaysSample-12        4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithStackTrace/NeverSample-12         3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithTimestamp/AlwaysSample-12         5.000 ± 0%     5.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithTimestamp/NeverSample-12          4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_10,_spans:_10-12           0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_10,_spans:_100-12          0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_100,_spans:_10-12          0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_100,_spans:_100-12         0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorVerboseLogging-12                       35.00 ± 0%     35.00 ± 0%       ~ (p=1.000 n=10) ¹
geomean                                                         ²               +0.00%                ²
¹ all samples are equal
² summaries must be >0 to compute geomean
```

See open-telemetry#6721.
@jschaf
Copy link
Contributor Author

jschaf commented May 6, 2025

@dmathieu Sent the first PR: #6730

@pellared pellared added the area:trace Part of OpenTelemetry tracing label May 13, 2025
@jschaf jschaf closed this as completed May 15, 2025
@pellared
Copy link
Member

@jschaf, why has this issue been closed?

@jschaf
Copy link
Contributor Author

jschaf commented May 15, 2025

I figured the cost-benefit wasn't worth it. @dmathieu said the absolute speedup of the atomics PR was small—the other optimizations are even smaller.

I'm happy to reopen if y'all are interested. I've already implemented them in my experimental code, so it's not a big lift.

@dmathieu
Copy link
Member

I think looking at your other proposals would be nice.

@jschaf jschaf reopened this May 16, 2025
jschaf added a commit to jschaf/opentelemetry-go that referenced this issue May 16, 2025
With specialized routines, we can avoid the allocation of hex.DecodeString
since we know the structure of the IDs.

We can use `==` instead of bytes.Equal for arrays. From the Go [spec]:

> Array types are comparable if their array element types are comparable. Two
> array values are equal if their corresponding element values are equal. The
> elements are compared in ascending index order, and comparison stops as soon
> as two element values differ (or all elements have been compared).

[spec]: https://go.dev/ref/spec#Comparison_operators

Issue: open-telemetry#6721
jschaf added a commit to jschaf/opentelemetry-go that referenced this issue May 16, 2025
With specialized routines, we can avoid the allocation of hex.DecodeString
since we know the structure of the IDs.

We can use `==` instead of bytes.Equal for arrays. From the Go [spec]:

> Array types are comparable if their array element types are comparable. Two
> array values are equal if their corresponding element values are equal. The
> elements are compared in ascending index order, and comparison stops as soon
> as two element values differ (or all elements have been compared).

[spec]: https://go.dev/ref/spec#Comparison_operators

### Benchstat

To generate:
```sh
mkdir private
cd sdk
go test -run=xxxxMatchNothingxxxx -bench=. -count=10 go.opentelemetry.io/otel/sdk/trace -timeout=30m | tee ../private/base.txt
go test -run=xxxxMatchNothingxxxx -bench=. -count=10 go.opentelemetry.io/otel/sdk/trace -timeout=30m | tee ../private/new.txt
benchstat ../private/base.txt ../private/new.txt
```

Results:
```
goos: darwin
goarch: arm64
pkg: go.opentelemetry.io/otel/sdk/trace
cpu: Apple M2 Max
                                              │ ../private/base.txt │          ../private/new1.txt          │
                                              │       sec/op        │    sec/op      vs base                │
Truncate/Unlimited-12                                 0.2086n ±  1%   0.2140n ±  3%   +2.59% (p=0.017 n=10)
Truncate/Zero-12                                      0.3048n ±  0%   0.3070n ±  1%   +0.71% (p=0.014 n=10)
Truncate/Short-12                                     0.2083n ±  2%   0.2097n ±  1%        ~ (p=0.148 n=10)
Truncate/ASCII-12                                     0.6870n ±  0%   0.6855n ±  0%        ~ (p=0.493 n=10)
Truncate/ValidUTF-8-12                                 1.298n ±  0%    1.302n ±  1%   +0.31% (p=0.003 n=10)
Truncate/InvalidUTF-8-12                               9.457n ±  0%    9.420n ±  1%        ~ (p=0.529 n=10)
Truncate/MixedUTF-8-12                                 17.30n ±  1%    17.29n ±  0%        ~ (p=0.359 n=10)
RecordingSpanSetAttributes/WithLimit/false-12          2.055µ ±  1%    2.082µ ±  9%   +1.29% (p=0.014 n=10)
RecordingSpanSetAttributes/WithLimit/true-12           4.368µ ±  0%    4.364µ ±  0%   -0.08% (p=0.049 n=10)
SpanEnd-12                                             72.57n ± 17%    73.75n ± 16%        ~ (p=0.853 n=10)
TraceStart/with_a_simple_span-12                       320.1n ± 10%    314.6n ± 10%        ~ (p=0.165 n=10)
TraceStart/with_several_links-12                       432.7n ±  2%    429.4n ±  1%        ~ (p=0.063 n=10)
TraceStart/with_attributes-12                          477.3n ±  1%    468.1n ±  6%   -1.94% (p=0.005 n=10)
SpanLimits/AttributeValueLengthLimit-12                4.401µ ±  1%    4.439µ ±  2%        ~ (p=0.089 n=10)
SpanLimits/AttributeCountLimit-12                      4.125µ ±  1%    4.151µ ±  1%   +0.62% (p=0.014 n=10)
SpanLimits/EventCountLimit-12                          3.900µ ±  2%    3.935µ ±  1%   +0.88% (p=0.023 n=10)
SpanLimits/LinkCountLimit-12                           3.870µ ±  2%    3.901µ ±  1%        ~ (p=0.148 n=10)
SpanLimits/AttributePerEventCountLimit-12              4.212µ ±  1%    4.243µ ±  1%   +0.75% (p=0.008 n=10)
SpanLimits/AttributePerLinkCountLimit-12               4.200µ ±  1%    4.224µ ±  0%   +0.57% (p=0.041 n=10)
SpanSetAttributesOverCapacity-12                       1.661µ ±  1%    1.653µ ±  0%   -0.48% (p=0.049 n=10)
StartEndSpan/AlwaysSample-12                           317.9n ±  0%    316.5n ±  0%   -0.44% (p=0.007 n=10)
StartEndSpan/NeverSample-12                            152.3n ±  0%    152.0n ±  0%   -0.23% (p=0.005 n=10)
SpanWithAttributes_4/AlwaysSample-12                   527.2n ±  0%    532.4n ±  1%   +1.00% (p=0.000 n=10)
SpanWithAttributes_4/NeverSample-12                    240.6n ±  0%    241.6n ±  0%   +0.46% (p=0.000 n=10)
SpanWithAttributes_8/AlwaysSample-12                   704.5n ±  0%    718.3n ±  1%   +1.97% (p=0.000 n=10)
SpanWithAttributes_8/NeverSample-12                    325.0n ±  0%    327.2n ±  1%   +0.68% (p=0.000 n=10)
SpanWithAttributes_all/AlwaysSample-12                 576.8n ±  0%    584.7n ±  1%   +1.37% (p=0.000 n=10)
SpanWithAttributes_all/NeverSample-12                  264.6n ±  1%    263.3n ±  0%   -0.47% (p=0.045 n=10)
SpanWithAttributes_all_2x/AlwaysSample-12              818.6n ±  1%    834.9n ±  0%   +1.98% (p=0.000 n=10)
SpanWithAttributes_all_2x/NeverSample-12               378.3n ±  0%    382.9n ±  1%   +1.23% (p=0.000 n=10)
SpanWithEvents_4/AlwaysSample-12                       715.1n ±  1%    721.1n ±  0%   +0.83% (p=0.003 n=10)
SpanWithEvents_4/NeverSample-12                        156.1n ±  1%    155.1n ±  1%   -0.64% (p=0.002 n=10)
SpanWithEvents_8/AlwaysSample-12                       1.098µ ±  0%    1.104µ ±  0%   +0.55% (p=0.000 n=10)
SpanWithEvents_8/NeverSample-12                        158.8n ±  0%    158.6n ±  1%        ~ (p=0.288 n=10)
SpanWithEvents_WithStackTrace/AlwaysSample-12          438.8n ±  0%    438.5n ±  0%        ~ (p=0.868 n=10)
SpanWithEvents_WithStackTrace/NeverSample-12           168.2n ±  1%    167.4n ±  1%   -0.48% (p=0.014 n=10)
SpanWithEvents_WithTimestamp/AlwaysSample-12           430.6n ±  0%    432.9n ±  0%   +0.53% (p=0.001 n=10)
SpanWithEvents_WithTimestamp/NeverSample-12            193.7n ±  0%    190.1n ±  1%   -1.91% (p=0.000 n=10)
TraceID_DotString-12                                   42.37n ±  0%    24.80n ±  0%  -41.45% (p=0.000 n=10)
SpanID_DotString-12                                    31.30n ±  0%    17.22n ±  0%  -44.98% (p=0.000 n=10)
SpanProcessorOnEnd/batch:_10,_spans:_10-12             163.3n ±  0%    163.4n ±  0%        ~ (p=0.120 n=10)
SpanProcessorOnEnd/batch:_10,_spans:_100-12            1.639µ ±  0%    1.635µ ±  0%   -0.27% (p=0.000 n=10)
SpanProcessorOnEnd/batch:_100,_spans:_10-12            163.3n ±  0%    163.2n ±  0%        ~ (p=0.115 n=10)
SpanProcessorOnEnd/batch:_100,_spans:_100-12           1.636µ ±  0%    1.635µ ±  1%        ~ (p=0.509 n=10)
SpanProcessorVerboseLogging-12                         6.769µ ±  2%    6.600µ ±  2%   -2.49% (p=0.030 n=10)
geomean                                                221.4n          216.4n         -2.29%

                                              │ ../private/base.txt │          ../private/new1.txt          │
                                              │        B/op         │     B/op      vs base                 │
Truncate/Unlimited-12                                  0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/Zero-12                                       0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/Short-12                                      0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/ASCII-12                                      0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/ValidUTF-8-12                                 0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/InvalidUTF-8-12                               16.00 ± 0%       16.00 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/MixedUTF-8-12                                 32.00 ± 0%       32.00 ± 0%       ~ (p=1.000 n=10) ¹
RecordingSpanSetAttributes/WithLimit/false-12        6.891Ki ± 0%     6.891Ki ± 0%       ~ (p=1.000 n=10) ¹
RecordingSpanSetAttributes/WithLimit/true-12         7.023Ki ± 0%     7.023Ki ± 0%       ~ (p=1.000 n=10) ¹
SpanEnd-12                                             0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
TraceStart/with_a_simple_span-12                       528.0 ± 0%       528.0 ± 0%       ~ (p=1.000 n=10) ¹
TraceStart/with_several_links-12                       704.0 ± 0%       704.0 ± 0%       ~ (p=1.000 n=10) ¹
TraceStart/with_attributes-12                          784.0 ± 0%       784.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributeValueLengthLimit-12              10.56Ki ± 0%     10.56Ki ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributeCountLimit-12                    9.844Ki ± 0%     9.844Ki ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/EventCountLimit-12                        9.422Ki ± 0%     9.422Ki ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/LinkCountLimit-12                         9.031Ki ± 0%     9.031Ki ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributePerEventCountLimit-12            10.47Ki ± 0%     10.47Ki ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributePerLinkCountLimit-12             10.47Ki ± 0%     10.47Ki ± 0%       ~ (p=1.000 n=10) ¹
SpanSetAttributesOverCapacity-12                       592.0 ± 0%       592.0 ± 0%       ~ (p=1.000 n=10) ¹
StartEndSpan/AlwaysSample-12                           528.0 ± 0%       528.0 ± 0%       ~ (p=1.000 n=10) ¹
StartEndSpan/NeverSample-12                            144.0 ± 0%       144.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_4/AlwaysSample-12                 1.016Ki ± 0%     1.016Ki ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_4/NeverSample-12                    400.0 ± 0%       400.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_8/AlwaysSample-12                 1.516Ki ± 0%     1.516Ki ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_8/NeverSample-12                    656.0 ± 0%       656.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all/AlwaysSample-12               1.141Ki ± 0%     1.141Ki ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all/NeverSample-12                  464.0 ± 0%       464.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all_2x/AlwaysSample-12            1.891Ki ± 0%     1.891Ki ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all_2x/NeverSample-12               848.0 ± 0%       848.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_4/AlwaysSample-12                     1.016Ki ± 0%     1.016Ki ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_4/NeverSample-12                        144.0 ± 0%       144.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_8/AlwaysSample-12                     1.641Ki ± 0%     1.641Ki ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_8/NeverSample-12                        144.0 ± 0%       144.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithStackTrace/AlwaysSample-12          624.0 ± 0%       624.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithStackTrace/NeverSample-12           160.0 ± 0%       160.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithTimestamp/AlwaysSample-12           648.0 ± 0%       648.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithTimestamp/NeverSample-12            184.0 ± 0%       184.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_10,_spans:_10-12             0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_10,_spans:_100-12            0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_100,_spans:_10-12            0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_100,_spans:_100-12           0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorVerboseLogging-12                       9.547Ki ± 0%     9.547Ki ± 0%       ~ (p=1.000 n=10) ¹
geomean                                                           ²                 +0.00%                ²
¹ all samples are equal
² summaries must be >0 to compute geomean

                                              │ ../private/base.txt │         ../private/new1.txt         │
                                              │      allocs/op      │ allocs/op   vs base                 │
Truncate/Unlimited-12                                  0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/Zero-12                                       0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/Short-12                                      0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/ASCII-12                                      0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/ValidUTF-8-12                                 0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/InvalidUTF-8-12                               1.000 ± 0%     1.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/MixedUTF-8-12                                 1.000 ± 0%     1.000 ± 0%       ~ (p=1.000 n=10) ¹
RecordingSpanSetAttributes/WithLimit/false-12          3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
RecordingSpanSetAttributes/WithLimit/true-12           10.00 ± 0%     10.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanEnd-12                                             0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
TraceStart/with_a_simple_span-12                       2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
TraceStart/with_several_links-12                       3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
TraceStart/with_attributes-12                          4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributeValueLengthLimit-12                41.00 ± 0%     41.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributeCountLimit-12                      38.00 ± 0%     38.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/EventCountLimit-12                          35.00 ± 0%     35.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/LinkCountLimit-12                           35.00 ± 0%     35.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributePerEventCountLimit-12              38.00 ± 0%     38.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributePerLinkCountLimit-12               38.00 ± 0%     38.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanSetAttributesOverCapacity-12                       3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
StartEndSpan/AlwaysSample-12                           2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
StartEndSpan/NeverSample-12                            2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_4/AlwaysSample-12                   4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_4/NeverSample-12                    3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_8/AlwaysSample-12                   4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_8/NeverSample-12                    3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all/AlwaysSample-12                 4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all/NeverSample-12                  3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all_2x/AlwaysSample-12              4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all_2x/NeverSample-12               3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_4/AlwaysSample-12                       5.000 ± 0%     5.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_4/NeverSample-12                        2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_8/AlwaysSample-12                       6.000 ± 0%     6.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_8/NeverSample-12                        2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithStackTrace/AlwaysSample-12          4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithStackTrace/NeverSample-12           3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithTimestamp/AlwaysSample-12           5.000 ± 0%     5.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithTimestamp/NeverSample-12            4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_10,_spans:_10-12             0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_10,_spans:_100-12            0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_100,_spans:_10-12            0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_100,_spans:_100-12           0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorVerboseLogging-12                         35.00 ± 0%     35.00 ± 0%       ~ (p=1.000 n=10) ¹
geomean                                                           ²               +0.00%                ²
¹ all samples are equal
² summaries must be >0 to compute geomean
```

Issue: open-telemetry#6721
jschaf added a commit to jschaf/opentelemetry-go that referenced this issue May 16, 2025
With specialized routines, we can avoid the allocation of hex.DecodeString
since we know the structure of the IDs.

We can use `==` instead of bytes.Equal for arrays. From the Go [spec]:

> Array types are comparable if their array element types are comparable. Two
> array values are equal if their corresponding element values are equal. The
> elements are compared in ascending index order, and comparison stops as soon
> as two element values differ (or all elements have been compared).

[spec]: https://go.dev/ref/spec#Comparison_operators

### Benchstat

To generate:
```sh
mkdir private
cd sdk
go test -run=xxxxMatchNothingxxxx -bench=. -count=10 go.opentelemetry.io/otel/sdk/trace -timeout=30m | tee ../private/base.txt
go test -run=xxxxMatchNothingxxxx -bench=. -count=10 go.opentelemetry.io/otel/sdk/trace -timeout=30m | tee ../private/new.txt
benchstat ../private/base.txt ../private/new.txt
```

Results:
```
goos: darwin
goarch: arm64
pkg: go.opentelemetry.io/otel/sdk/trace
cpu: Apple M2 Max
                                              │ ../private/base.txt │          ../private/new.txt          │
                                              │       sec/op        │    sec/op      vs base                │
Truncate/Unlimited-12                                 0.2086n ±  1%   0.2140n ±  3%   +2.59% (p=0.017 n=10)
Truncate/Zero-12                                      0.3048n ±  0%   0.3070n ±  1%   +0.71% (p=0.014 n=10)
Truncate/Short-12                                     0.2083n ±  2%   0.2097n ±  1%        ~ (p=0.148 n=10)
Truncate/ASCII-12                                     0.6870n ±  0%   0.6855n ±  0%        ~ (p=0.493 n=10)
Truncate/ValidUTF-8-12                                 1.298n ±  0%    1.302n ±  1%   +0.31% (p=0.003 n=10)
Truncate/InvalidUTF-8-12                               9.457n ±  0%    9.420n ±  1%        ~ (p=0.529 n=10)
Truncate/MixedUTF-8-12                                 17.30n ±  1%    17.29n ±  0%        ~ (p=0.359 n=10)
RecordingSpanSetAttributes/WithLimit/false-12          2.055µ ±  1%    2.082µ ±  9%   +1.29% (p=0.014 n=10)
RecordingSpanSetAttributes/WithLimit/true-12           4.368µ ±  0%    4.364µ ±  0%   -0.08% (p=0.049 n=10)
SpanEnd-12                                             72.57n ± 17%    73.75n ± 16%        ~ (p=0.853 n=10)
TraceStart/with_a_simple_span-12                       320.1n ± 10%    314.6n ± 10%        ~ (p=0.165 n=10)
TraceStart/with_several_links-12                       432.7n ±  2%    429.4n ±  1%        ~ (p=0.063 n=10)
TraceStart/with_attributes-12                          477.3n ±  1%    468.1n ±  6%   -1.94% (p=0.005 n=10)
SpanLimits/AttributeValueLengthLimit-12                4.401µ ±  1%    4.439µ ±  2%        ~ (p=0.089 n=10)
SpanLimits/AttributeCountLimit-12                      4.125µ ±  1%    4.151µ ±  1%   +0.62% (p=0.014 n=10)
SpanLimits/EventCountLimit-12                          3.900µ ±  2%    3.935µ ±  1%   +0.88% (p=0.023 n=10)
SpanLimits/LinkCountLimit-12                           3.870µ ±  2%    3.901µ ±  1%        ~ (p=0.148 n=10)
SpanLimits/AttributePerEventCountLimit-12              4.212µ ±  1%    4.243µ ±  1%   +0.75% (p=0.008 n=10)
SpanLimits/AttributePerLinkCountLimit-12               4.200µ ±  1%    4.224µ ±  0%   +0.57% (p=0.041 n=10)
SpanSetAttributesOverCapacity-12                       1.661µ ±  1%    1.653µ ±  0%   -0.48% (p=0.049 n=10)
StartEndSpan/AlwaysSample-12                           317.9n ±  0%    316.5n ±  0%   -0.44% (p=0.007 n=10)
StartEndSpan/NeverSample-12                            152.3n ±  0%    152.0n ±  0%   -0.23% (p=0.005 n=10)
SpanWithAttributes_4/AlwaysSample-12                   527.2n ±  0%    532.4n ±  1%   +1.00% (p=0.000 n=10)
SpanWithAttributes_4/NeverSample-12                    240.6n ±  0%    241.6n ±  0%   +0.46% (p=0.000 n=10)
SpanWithAttributes_8/AlwaysSample-12                   704.5n ±  0%    718.3n ±  1%   +1.97% (p=0.000 n=10)
SpanWithAttributes_8/NeverSample-12                    325.0n ±  0%    327.2n ±  1%   +0.68% (p=0.000 n=10)
SpanWithAttributes_all/AlwaysSample-12                 576.8n ±  0%    584.7n ±  1%   +1.37% (p=0.000 n=10)
SpanWithAttributes_all/NeverSample-12                  264.6n ±  1%    263.3n ±  0%   -0.47% (p=0.045 n=10)
SpanWithAttributes_all_2x/AlwaysSample-12              818.6n ±  1%    834.9n ±  0%   +1.98% (p=0.000 n=10)
SpanWithAttributes_all_2x/NeverSample-12               378.3n ±  0%    382.9n ±  1%   +1.23% (p=0.000 n=10)
SpanWithEvents_4/AlwaysSample-12                       715.1n ±  1%    721.1n ±  0%   +0.83% (p=0.003 n=10)
SpanWithEvents_4/NeverSample-12                        156.1n ±  1%    155.1n ±  1%   -0.64% (p=0.002 n=10)
SpanWithEvents_8/AlwaysSample-12                       1.098µ ±  0%    1.104µ ±  0%   +0.55% (p=0.000 n=10)
SpanWithEvents_8/NeverSample-12                        158.8n ±  0%    158.6n ±  1%        ~ (p=0.288 n=10)
SpanWithEvents_WithStackTrace/AlwaysSample-12          438.8n ±  0%    438.5n ±  0%        ~ (p=0.868 n=10)
SpanWithEvents_WithStackTrace/NeverSample-12           168.2n ±  1%    167.4n ±  1%   -0.48% (p=0.014 n=10)
SpanWithEvents_WithTimestamp/AlwaysSample-12           430.6n ±  0%    432.9n ±  0%   +0.53% (p=0.001 n=10)
SpanWithEvents_WithTimestamp/NeverSample-12            193.7n ±  0%    190.1n ±  1%   -1.91% (p=0.000 n=10)
TraceID_DotString-12                                   42.37n ±  0%    24.80n ±  0%  -41.45% (p=0.000 n=10)
SpanID_DotString-12                                    31.30n ±  0%    17.22n ±  0%  -44.98% (p=0.000 n=10)
SpanProcessorOnEnd/batch:_10,_spans:_10-12             163.3n ±  0%    163.4n ±  0%        ~ (p=0.120 n=10)
SpanProcessorOnEnd/batch:_10,_spans:_100-12            1.639µ ±  0%    1.635µ ±  0%   -0.27% (p=0.000 n=10)
SpanProcessorOnEnd/batch:_100,_spans:_10-12            163.3n ±  0%    163.2n ±  0%        ~ (p=0.115 n=10)
SpanProcessorOnEnd/batch:_100,_spans:_100-12           1.636µ ±  0%    1.635µ ±  1%        ~ (p=0.509 n=10)
SpanProcessorVerboseLogging-12                         6.769µ ±  2%    6.600µ ±  2%   -2.49% (p=0.030 n=10)
geomean                                                221.4n          216.4n         -2.29%

                                              │ ../private/base.txt │          ../private/new.txt          │
                                              │        B/op         │     B/op      vs base                 │
Truncate/Unlimited-12                                  0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/Zero-12                                       0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/Short-12                                      0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/ASCII-12                                      0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/ValidUTF-8-12                                 0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/InvalidUTF-8-12                               16.00 ± 0%       16.00 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/MixedUTF-8-12                                 32.00 ± 0%       32.00 ± 0%       ~ (p=1.000 n=10) ¹
RecordingSpanSetAttributes/WithLimit/false-12        6.891Ki ± 0%     6.891Ki ± 0%       ~ (p=1.000 n=10) ¹
RecordingSpanSetAttributes/WithLimit/true-12         7.023Ki ± 0%     7.023Ki ± 0%       ~ (p=1.000 n=10) ¹
SpanEnd-12                                             0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
TraceStart/with_a_simple_span-12                       528.0 ± 0%       528.0 ± 0%       ~ (p=1.000 n=10) ¹
TraceStart/with_several_links-12                       704.0 ± 0%       704.0 ± 0%       ~ (p=1.000 n=10) ¹
TraceStart/with_attributes-12                          784.0 ± 0%       784.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributeValueLengthLimit-12              10.56Ki ± 0%     10.56Ki ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributeCountLimit-12                    9.844Ki ± 0%     9.844Ki ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/EventCountLimit-12                        9.422Ki ± 0%     9.422Ki ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/LinkCountLimit-12                         9.031Ki ± 0%     9.031Ki ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributePerEventCountLimit-12            10.47Ki ± 0%     10.47Ki ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributePerLinkCountLimit-12             10.47Ki ± 0%     10.47Ki ± 0%       ~ (p=1.000 n=10) ¹
SpanSetAttributesOverCapacity-12                       592.0 ± 0%       592.0 ± 0%       ~ (p=1.000 n=10) ¹
StartEndSpan/AlwaysSample-12                           528.0 ± 0%       528.0 ± 0%       ~ (p=1.000 n=10) ¹
StartEndSpan/NeverSample-12                            144.0 ± 0%       144.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_4/AlwaysSample-12                 1.016Ki ± 0%     1.016Ki ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_4/NeverSample-12                    400.0 ± 0%       400.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_8/AlwaysSample-12                 1.516Ki ± 0%     1.516Ki ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_8/NeverSample-12                    656.0 ± 0%       656.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all/AlwaysSample-12               1.141Ki ± 0%     1.141Ki ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all/NeverSample-12                  464.0 ± 0%       464.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all_2x/AlwaysSample-12            1.891Ki ± 0%     1.891Ki ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all_2x/NeverSample-12               848.0 ± 0%       848.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_4/AlwaysSample-12                     1.016Ki ± 0%     1.016Ki ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_4/NeverSample-12                        144.0 ± 0%       144.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_8/AlwaysSample-12                     1.641Ki ± 0%     1.641Ki ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_8/NeverSample-12                        144.0 ± 0%       144.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithStackTrace/AlwaysSample-12          624.0 ± 0%       624.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithStackTrace/NeverSample-12           160.0 ± 0%       160.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithTimestamp/AlwaysSample-12           648.0 ± 0%       648.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithTimestamp/NeverSample-12            184.0 ± 0%       184.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_10,_spans:_10-12             0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_10,_spans:_100-12            0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_100,_spans:_10-12            0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_100,_spans:_100-12           0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorVerboseLogging-12                       9.547Ki ± 0%     9.547Ki ± 0%       ~ (p=1.000 n=10) ¹
geomean                                                           ²                 +0.00%                ²
¹ all samples are equal
² summaries must be >0 to compute geomean

                                              │ ../private/base.txt │         ../private/new.txt         │
                                              │      allocs/op      │ allocs/op   vs base                 │
Truncate/Unlimited-12                                  0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/Zero-12                                       0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/Short-12                                      0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/ASCII-12                                      0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/ValidUTF-8-12                                 0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/InvalidUTF-8-12                               1.000 ± 0%     1.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/MixedUTF-8-12                                 1.000 ± 0%     1.000 ± 0%       ~ (p=1.000 n=10) ¹
RecordingSpanSetAttributes/WithLimit/false-12          3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
RecordingSpanSetAttributes/WithLimit/true-12           10.00 ± 0%     10.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanEnd-12                                             0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
TraceStart/with_a_simple_span-12                       2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
TraceStart/with_several_links-12                       3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
TraceStart/with_attributes-12                          4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributeValueLengthLimit-12                41.00 ± 0%     41.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributeCountLimit-12                      38.00 ± 0%     38.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/EventCountLimit-12                          35.00 ± 0%     35.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/LinkCountLimit-12                           35.00 ± 0%     35.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributePerEventCountLimit-12              38.00 ± 0%     38.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributePerLinkCountLimit-12               38.00 ± 0%     38.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanSetAttributesOverCapacity-12                       3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
StartEndSpan/AlwaysSample-12                           2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
StartEndSpan/NeverSample-12                            2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_4/AlwaysSample-12                   4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_4/NeverSample-12                    3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_8/AlwaysSample-12                   4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_8/NeverSample-12                    3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all/AlwaysSample-12                 4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all/NeverSample-12                  3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all_2x/AlwaysSample-12              4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all_2x/NeverSample-12               3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_4/AlwaysSample-12                       5.000 ± 0%     5.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_4/NeverSample-12                        2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_8/AlwaysSample-12                       6.000 ± 0%     6.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_8/NeverSample-12                        2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithStackTrace/AlwaysSample-12          4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithStackTrace/NeverSample-12           3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithTimestamp/AlwaysSample-12           5.000 ± 0%     5.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithTimestamp/NeverSample-12            4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_10,_spans:_10-12             0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_10,_spans:_100-12            0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_100,_spans:_10-12            0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_100,_spans:_100-12           0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorVerboseLogging-12                         35.00 ± 0%     35.00 ± 0%       ~ (p=1.000 n=10) ¹
geomean                                                           ²               +0.00%                ²
¹ all samples are equal
² summaries must be >0 to compute geomean
```

Issue: open-telemetry#6721
jschaf added a commit to jschaf/opentelemetry-go that referenced this issue May 16, 2025
With specialized routines, we can avoid the allocation of hex.DecodeString
since we know the structure of the IDs.

We can use `==` instead of bytes.Equal for arrays. From the Go [spec]:

> Array types are comparable if their array element types are comparable. Two
> array values are equal if their corresponding element values are equal. The
> elements are compared in ascending index order, and comparison stops as soon
> as two element values differ (or all elements have been compared).

[spec]: https://go.dev/ref/spec#Comparison_operators

### Benchstat

To generate:
```sh
mkdir private
cd sdk
go test -run=xxxxMatchNothingxxxx -bench=. -count=10 go.opentelemetry.io/otel/sdk/trace -timeout=30m | tee ../private/base.txt
go test -run=xxxxMatchNothingxxxx -bench=. -count=10 go.opentelemetry.io/otel/sdk/trace -timeout=30m | tee ../private/new.txt
benchstat ../private/base.txt ../private/new.txt
```

Results:
```
goos: darwin
goarch: arm64
pkg: go.opentelemetry.io/otel/sdk/trace
cpu: Apple M2 Max
                                              │ ../private/base.txt │          ../private/new.txt          │
                                              │       sec/op        │    sec/op      vs base                │
Truncate/Unlimited-12                                 0.2086n ±  1%   0.2140n ±  3%   +2.59% (p=0.017 n=10)
Truncate/Zero-12                                      0.3048n ±  0%   0.3070n ±  1%   +0.71% (p=0.014 n=10)
Truncate/Short-12                                     0.2083n ±  2%   0.2097n ±  1%        ~ (p=0.148 n=10)
Truncate/ASCII-12                                     0.6870n ±  0%   0.6855n ±  0%        ~ (p=0.493 n=10)
Truncate/ValidUTF-8-12                                 1.298n ±  0%    1.302n ±  1%   +0.31% (p=0.003 n=10)
Truncate/InvalidUTF-8-12                               9.457n ±  0%    9.420n ±  1%        ~ (p=0.529 n=10)
Truncate/MixedUTF-8-12                                 17.30n ±  1%    17.29n ±  0%        ~ (p=0.359 n=10)
RecordingSpanSetAttributes/WithLimit/false-12          2.055µ ±  1%    2.082µ ±  9%   +1.29% (p=0.014 n=10)
RecordingSpanSetAttributes/WithLimit/true-12           4.368µ ±  0%    4.364µ ±  0%   -0.08% (p=0.049 n=10)
SpanEnd-12                                             72.57n ± 17%    73.75n ± 16%        ~ (p=0.853 n=10)
TraceStart/with_a_simple_span-12                       320.1n ± 10%    314.6n ± 10%        ~ (p=0.165 n=10)
TraceStart/with_several_links-12                       432.7n ±  2%    429.4n ±  1%        ~ (p=0.063 n=10)
TraceStart/with_attributes-12                          477.3n ±  1%    468.1n ±  6%   -1.94% (p=0.005 n=10)
SpanLimits/AttributeValueLengthLimit-12                4.401µ ±  1%    4.439µ ±  2%        ~ (p=0.089 n=10)
SpanLimits/AttributeCountLimit-12                      4.125µ ±  1%    4.151µ ±  1%   +0.62% (p=0.014 n=10)
SpanLimits/EventCountLimit-12                          3.900µ ±  2%    3.935µ ±  1%   +0.88% (p=0.023 n=10)
SpanLimits/LinkCountLimit-12                           3.870µ ±  2%    3.901µ ±  1%        ~ (p=0.148 n=10)
SpanLimits/AttributePerEventCountLimit-12              4.212µ ±  1%    4.243µ ±  1%   +0.75% (p=0.008 n=10)
SpanLimits/AttributePerLinkCountLimit-12               4.200µ ±  1%    4.224µ ±  0%   +0.57% (p=0.041 n=10)
SpanSetAttributesOverCapacity-12                       1.661µ ±  1%    1.653µ ±  0%   -0.48% (p=0.049 n=10)
StartEndSpan/AlwaysSample-12                           317.9n ±  0%    316.5n ±  0%   -0.44% (p=0.007 n=10)
StartEndSpan/NeverSample-12                            152.3n ±  0%    152.0n ±  0%   -0.23% (p=0.005 n=10)
SpanWithAttributes_4/AlwaysSample-12                   527.2n ±  0%    532.4n ±  1%   +1.00% (p=0.000 n=10)
SpanWithAttributes_4/NeverSample-12                    240.6n ±  0%    241.6n ±  0%   +0.46% (p=0.000 n=10)
SpanWithAttributes_8/AlwaysSample-12                   704.5n ±  0%    718.3n ±  1%   +1.97% (p=0.000 n=10)
SpanWithAttributes_8/NeverSample-12                    325.0n ±  0%    327.2n ±  1%   +0.68% (p=0.000 n=10)
SpanWithAttributes_all/AlwaysSample-12                 576.8n ±  0%    584.7n ±  1%   +1.37% (p=0.000 n=10)
SpanWithAttributes_all/NeverSample-12                  264.6n ±  1%    263.3n ±  0%   -0.47% (p=0.045 n=10)
SpanWithAttributes_all_2x/AlwaysSample-12              818.6n ±  1%    834.9n ±  0%   +1.98% (p=0.000 n=10)
SpanWithAttributes_all_2x/NeverSample-12               378.3n ±  0%    382.9n ±  1%   +1.23% (p=0.000 n=10)
SpanWithEvents_4/AlwaysSample-12                       715.1n ±  1%    721.1n ±  0%   +0.83% (p=0.003 n=10)
SpanWithEvents_4/NeverSample-12                        156.1n ±  1%    155.1n ±  1%   -0.64% (p=0.002 n=10)
SpanWithEvents_8/AlwaysSample-12                       1.098µ ±  0%    1.104µ ±  0%   +0.55% (p=0.000 n=10)
SpanWithEvents_8/NeverSample-12                        158.8n ±  0%    158.6n ±  1%        ~ (p=0.288 n=10)
SpanWithEvents_WithStackTrace/AlwaysSample-12          438.8n ±  0%    438.5n ±  0%        ~ (p=0.868 n=10)
SpanWithEvents_WithStackTrace/NeverSample-12           168.2n ±  1%    167.4n ±  1%   -0.48% (p=0.014 n=10)
SpanWithEvents_WithTimestamp/AlwaysSample-12           430.6n ±  0%    432.9n ±  0%   +0.53% (p=0.001 n=10)
SpanWithEvents_WithTimestamp/NeverSample-12            193.7n ±  0%    190.1n ±  1%   -1.91% (p=0.000 n=10)
TraceID_DotString-12                                   42.37n ±  0%    24.80n ±  0%  -41.45% (p=0.000 n=10)
SpanID_DotString-12                                    31.30n ±  0%    17.22n ±  0%  -44.98% (p=0.000 n=10)
SpanProcessorOnEnd/batch:_10,_spans:_10-12             163.3n ±  0%    163.4n ±  0%        ~ (p=0.120 n=10)
SpanProcessorOnEnd/batch:_10,_spans:_100-12            1.639µ ±  0%    1.635µ ±  0%   -0.27% (p=0.000 n=10)
SpanProcessorOnEnd/batch:_100,_spans:_10-12            163.3n ±  0%    163.2n ±  0%        ~ (p=0.115 n=10)
SpanProcessorOnEnd/batch:_100,_spans:_100-12           1.636µ ±  0%    1.635µ ±  1%        ~ (p=0.509 n=10)
SpanProcessorVerboseLogging-12                         6.769µ ±  2%    6.600µ ±  2%   -2.49% (p=0.030 n=10)
geomean                                                221.4n          216.4n         -2.29%

                                              │ ../private/base.txt │          ../private/new.txt          │
                                              │        B/op         │     B/op      vs base                 │
Truncate/Unlimited-12                                  0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/Zero-12                                       0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/Short-12                                      0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/ASCII-12                                      0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/ValidUTF-8-12                                 0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/InvalidUTF-8-12                               16.00 ± 0%       16.00 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/MixedUTF-8-12                                 32.00 ± 0%       32.00 ± 0%       ~ (p=1.000 n=10) ¹
RecordingSpanSetAttributes/WithLimit/false-12        6.891Ki ± 0%     6.891Ki ± 0%       ~ (p=1.000 n=10) ¹
RecordingSpanSetAttributes/WithLimit/true-12         7.023Ki ± 0%     7.023Ki ± 0%       ~ (p=1.000 n=10) ¹
SpanEnd-12                                             0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
TraceStart/with_a_simple_span-12                       528.0 ± 0%       528.0 ± 0%       ~ (p=1.000 n=10) ¹
TraceStart/with_several_links-12                       704.0 ± 0%       704.0 ± 0%       ~ (p=1.000 n=10) ¹
TraceStart/with_attributes-12                          784.0 ± 0%       784.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributeValueLengthLimit-12              10.56Ki ± 0%     10.56Ki ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributeCountLimit-12                    9.844Ki ± 0%     9.844Ki ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/EventCountLimit-12                        9.422Ki ± 0%     9.422Ki ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/LinkCountLimit-12                         9.031Ki ± 0%     9.031Ki ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributePerEventCountLimit-12            10.47Ki ± 0%     10.47Ki ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributePerLinkCountLimit-12             10.47Ki ± 0%     10.47Ki ± 0%       ~ (p=1.000 n=10) ¹
SpanSetAttributesOverCapacity-12                       592.0 ± 0%       592.0 ± 0%       ~ (p=1.000 n=10) ¹
StartEndSpan/AlwaysSample-12                           528.0 ± 0%       528.0 ± 0%       ~ (p=1.000 n=10) ¹
StartEndSpan/NeverSample-12                            144.0 ± 0%       144.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_4/AlwaysSample-12                 1.016Ki ± 0%     1.016Ki ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_4/NeverSample-12                    400.0 ± 0%       400.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_8/AlwaysSample-12                 1.516Ki ± 0%     1.516Ki ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_8/NeverSample-12                    656.0 ± 0%       656.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all/AlwaysSample-12               1.141Ki ± 0%     1.141Ki ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all/NeverSample-12                  464.0 ± 0%       464.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all_2x/AlwaysSample-12            1.891Ki ± 0%     1.891Ki ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all_2x/NeverSample-12               848.0 ± 0%       848.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_4/AlwaysSample-12                     1.016Ki ± 0%     1.016Ki ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_4/NeverSample-12                        144.0 ± 0%       144.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_8/AlwaysSample-12                     1.641Ki ± 0%     1.641Ki ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_8/NeverSample-12                        144.0 ± 0%       144.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithStackTrace/AlwaysSample-12          624.0 ± 0%       624.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithStackTrace/NeverSample-12           160.0 ± 0%       160.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithTimestamp/AlwaysSample-12           648.0 ± 0%       648.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithTimestamp/NeverSample-12            184.0 ± 0%       184.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_10,_spans:_10-12             0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_10,_spans:_100-12            0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_100,_spans:_10-12            0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_100,_spans:_100-12           0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorVerboseLogging-12                       9.547Ki ± 0%     9.547Ki ± 0%       ~ (p=1.000 n=10) ¹
geomean                                                           ²                 +0.00%                ²
¹ all samples are equal
² summaries must be >0 to compute geomean

                                              │ ../private/base.txt │         ../private/new.txt         │
                                              │      allocs/op      │ allocs/op   vs base                 │
Truncate/Unlimited-12                                  0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/Zero-12                                       0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/Short-12                                      0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/ASCII-12                                      0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/ValidUTF-8-12                                 0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/InvalidUTF-8-12                               1.000 ± 0%     1.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/MixedUTF-8-12                                 1.000 ± 0%     1.000 ± 0%       ~ (p=1.000 n=10) ¹
RecordingSpanSetAttributes/WithLimit/false-12          3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
RecordingSpanSetAttributes/WithLimit/true-12           10.00 ± 0%     10.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanEnd-12                                             0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
TraceStart/with_a_simple_span-12                       2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
TraceStart/with_several_links-12                       3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
TraceStart/with_attributes-12                          4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributeValueLengthLimit-12                41.00 ± 0%     41.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributeCountLimit-12                      38.00 ± 0%     38.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/EventCountLimit-12                          35.00 ± 0%     35.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/LinkCountLimit-12                           35.00 ± 0%     35.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributePerEventCountLimit-12              38.00 ± 0%     38.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributePerLinkCountLimit-12               38.00 ± 0%     38.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanSetAttributesOverCapacity-12                       3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
StartEndSpan/AlwaysSample-12                           2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
StartEndSpan/NeverSample-12                            2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_4/AlwaysSample-12                   4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_4/NeverSample-12                    3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_8/AlwaysSample-12                   4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_8/NeverSample-12                    3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all/AlwaysSample-12                 4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all/NeverSample-12                  3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all_2x/AlwaysSample-12              4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all_2x/NeverSample-12               3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_4/AlwaysSample-12                       5.000 ± 0%     5.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_4/NeverSample-12                        2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_8/AlwaysSample-12                       6.000 ± 0%     6.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_8/NeverSample-12                        2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithStackTrace/AlwaysSample-12          4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithStackTrace/NeverSample-12           3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithTimestamp/AlwaysSample-12           5.000 ± 0%     5.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithTimestamp/NeverSample-12            4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_10,_spans:_10-12             0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_10,_spans:_100-12            0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_100,_spans:_10-12            0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_100,_spans:_100-12           0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorVerboseLogging-12                         35.00 ± 0%     35.00 ± 0%       ~ (p=1.000 n=10) ¹
geomean                                                           ²               +0.00%                ²
¹ all samples are equal
² summaries must be >0 to compute geomean
```

Issue: open-telemetry#6721
@jschaf
Copy link
Contributor Author

jschaf commented May 16, 2025

Sent #6791 for optimization 1: inline hex encoding and decoding.

Speeds up the string method by 1.8x.

TraceID_DotString-12                                   42.37n ±  0%    24.80n ±  0%  -41.45% (p=0.000 n=10)
SpanID_DotString-12                                    31.30n ±  0%    17.22n ±  0%  -44.98% (p=0.000 n=10)

jschaf added a commit to jschaf/opentelemetry-go that referenced this issue May 17, 2025
With specialized routines, we can avoid the allocation of hex.DecodeString
since we know the structure of the IDs.

We can use `==` instead of bytes.Equal for arrays. From the Go [spec]:

> Array types are comparable if their array element types are comparable. Two
> array values are equal if their corresponding element values are equal. The
> elements are compared in ascending index order, and comparison stops as soon
> as two element values differ (or all elements have been compared).

[spec]: https://go.dev/ref/spec#Comparison_operators

### Benchstat

To generate:
```sh
mkdir private
cd sdk
go test -run=xxxxMatchNothingxxxx -bench=. -count=10 go.opentelemetry.io/otel/sdk/trace -timeout=30m | tee ../private/base.txt
go test -run=xxxxMatchNothingxxxx -bench=. -count=10 go.opentelemetry.io/otel/sdk/trace -timeout=30m | tee ../private/new.txt
benchstat ../private/base.txt ../private/new.txt
```

Results:
```
goos: darwin
goarch: arm64
pkg: go.opentelemetry.io/otel/sdk/trace
cpu: Apple M2 Max
                                              │ ../private/base.txt │          ../private/new.txt          │
                                              │       sec/op        │    sec/op      vs base                │
Truncate/Unlimited-12                                 0.2086n ±  1%   0.2140n ±  3%   +2.59% (p=0.017 n=10)
Truncate/Zero-12                                      0.3048n ±  0%   0.3070n ±  1%   +0.71% (p=0.014 n=10)
Truncate/Short-12                                     0.2083n ±  2%   0.2097n ±  1%        ~ (p=0.148 n=10)
Truncate/ASCII-12                                     0.6870n ±  0%   0.6855n ±  0%        ~ (p=0.493 n=10)
Truncate/ValidUTF-8-12                                 1.298n ±  0%    1.302n ±  1%   +0.31% (p=0.003 n=10)
Truncate/InvalidUTF-8-12                               9.457n ±  0%    9.420n ±  1%        ~ (p=0.529 n=10)
Truncate/MixedUTF-8-12                                 17.30n ±  1%    17.29n ±  0%        ~ (p=0.359 n=10)
RecordingSpanSetAttributes/WithLimit/false-12          2.055µ ±  1%    2.082µ ±  9%   +1.29% (p=0.014 n=10)
RecordingSpanSetAttributes/WithLimit/true-12           4.368µ ±  0%    4.364µ ±  0%   -0.08% (p=0.049 n=10)
SpanEnd-12                                             72.57n ± 17%    73.75n ± 16%        ~ (p=0.853 n=10)
TraceStart/with_a_simple_span-12                       320.1n ± 10%    314.6n ± 10%        ~ (p=0.165 n=10)
TraceStart/with_several_links-12                       432.7n ±  2%    429.4n ±  1%        ~ (p=0.063 n=10)
TraceStart/with_attributes-12                          477.3n ±  1%    468.1n ±  6%   -1.94% (p=0.005 n=10)
SpanLimits/AttributeValueLengthLimit-12                4.401µ ±  1%    4.439µ ±  2%        ~ (p=0.089 n=10)
SpanLimits/AttributeCountLimit-12                      4.125µ ±  1%    4.151µ ±  1%   +0.62% (p=0.014 n=10)
SpanLimits/EventCountLimit-12                          3.900µ ±  2%    3.935µ ±  1%   +0.88% (p=0.023 n=10)
SpanLimits/LinkCountLimit-12                           3.870µ ±  2%    3.901µ ±  1%        ~ (p=0.148 n=10)
SpanLimits/AttributePerEventCountLimit-12              4.212µ ±  1%    4.243µ ±  1%   +0.75% (p=0.008 n=10)
SpanLimits/AttributePerLinkCountLimit-12               4.200µ ±  1%    4.224µ ±  0%   +0.57% (p=0.041 n=10)
SpanSetAttributesOverCapacity-12                       1.661µ ±  1%    1.653µ ±  0%   -0.48% (p=0.049 n=10)
StartEndSpan/AlwaysSample-12                           317.9n ±  0%    316.5n ±  0%   -0.44% (p=0.007 n=10)
StartEndSpan/NeverSample-12                            152.3n ±  0%    152.0n ±  0%   -0.23% (p=0.005 n=10)
SpanWithAttributes_4/AlwaysSample-12                   527.2n ±  0%    532.4n ±  1%   +1.00% (p=0.000 n=10)
SpanWithAttributes_4/NeverSample-12                    240.6n ±  0%    241.6n ±  0%   +0.46% (p=0.000 n=10)
SpanWithAttributes_8/AlwaysSample-12                   704.5n ±  0%    718.3n ±  1%   +1.97% (p=0.000 n=10)
SpanWithAttributes_8/NeverSample-12                    325.0n ±  0%    327.2n ±  1%   +0.68% (p=0.000 n=10)
SpanWithAttributes_all/AlwaysSample-12                 576.8n ±  0%    584.7n ±  1%   +1.37% (p=0.000 n=10)
SpanWithAttributes_all/NeverSample-12                  264.6n ±  1%    263.3n ±  0%   -0.47% (p=0.045 n=10)
SpanWithAttributes_all_2x/AlwaysSample-12              818.6n ±  1%    834.9n ±  0%   +1.98% (p=0.000 n=10)
SpanWithAttributes_all_2x/NeverSample-12               378.3n ±  0%    382.9n ±  1%   +1.23% (p=0.000 n=10)
SpanWithEvents_4/AlwaysSample-12                       715.1n ±  1%    721.1n ±  0%   +0.83% (p=0.003 n=10)
SpanWithEvents_4/NeverSample-12                        156.1n ±  1%    155.1n ±  1%   -0.64% (p=0.002 n=10)
SpanWithEvents_8/AlwaysSample-12                       1.098µ ±  0%    1.104µ ±  0%   +0.55% (p=0.000 n=10)
SpanWithEvents_8/NeverSample-12                        158.8n ±  0%    158.6n ±  1%        ~ (p=0.288 n=10)
SpanWithEvents_WithStackTrace/AlwaysSample-12          438.8n ±  0%    438.5n ±  0%        ~ (p=0.868 n=10)
SpanWithEvents_WithStackTrace/NeverSample-12           168.2n ±  1%    167.4n ±  1%   -0.48% (p=0.014 n=10)
SpanWithEvents_WithTimestamp/AlwaysSample-12           430.6n ±  0%    432.9n ±  0%   +0.53% (p=0.001 n=10)
SpanWithEvents_WithTimestamp/NeverSample-12            193.7n ±  0%    190.1n ±  1%   -1.91% (p=0.000 n=10)
TraceID_DotString-12                                   42.37n ±  0%    24.80n ±  0%  -41.45% (p=0.000 n=10)
SpanID_DotString-12                                    31.30n ±  0%    17.22n ±  0%  -44.98% (p=0.000 n=10)
SpanProcessorOnEnd/batch:_10,_spans:_10-12             163.3n ±  0%    163.4n ±  0%        ~ (p=0.120 n=10)
SpanProcessorOnEnd/batch:_10,_spans:_100-12            1.639µ ±  0%    1.635µ ±  0%   -0.27% (p=0.000 n=10)
SpanProcessorOnEnd/batch:_100,_spans:_10-12            163.3n ±  0%    163.2n ±  0%        ~ (p=0.115 n=10)
SpanProcessorOnEnd/batch:_100,_spans:_100-12           1.636µ ±  0%    1.635µ ±  1%        ~ (p=0.509 n=10)
SpanProcessorVerboseLogging-12                         6.769µ ±  2%    6.600µ ±  2%   -2.49% (p=0.030 n=10)
geomean                                                221.4n          216.4n         -2.29%

                                              │ ../private/base.txt │          ../private/new.txt          │
                                              │        B/op         │     B/op      vs base                 │
Truncate/Unlimited-12                                  0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/Zero-12                                       0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/Short-12                                      0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/ASCII-12                                      0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/ValidUTF-8-12                                 0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/InvalidUTF-8-12                               16.00 ± 0%       16.00 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/MixedUTF-8-12                                 32.00 ± 0%       32.00 ± 0%       ~ (p=1.000 n=10) ¹
RecordingSpanSetAttributes/WithLimit/false-12        6.891Ki ± 0%     6.891Ki ± 0%       ~ (p=1.000 n=10) ¹
RecordingSpanSetAttributes/WithLimit/true-12         7.023Ki ± 0%     7.023Ki ± 0%       ~ (p=1.000 n=10) ¹
SpanEnd-12                                             0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
TraceStart/with_a_simple_span-12                       528.0 ± 0%       528.0 ± 0%       ~ (p=1.000 n=10) ¹
TraceStart/with_several_links-12                       704.0 ± 0%       704.0 ± 0%       ~ (p=1.000 n=10) ¹
TraceStart/with_attributes-12                          784.0 ± 0%       784.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributeValueLengthLimit-12              10.56Ki ± 0%     10.56Ki ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributeCountLimit-12                    9.844Ki ± 0%     9.844Ki ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/EventCountLimit-12                        9.422Ki ± 0%     9.422Ki ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/LinkCountLimit-12                         9.031Ki ± 0%     9.031Ki ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributePerEventCountLimit-12            10.47Ki ± 0%     10.47Ki ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributePerLinkCountLimit-12             10.47Ki ± 0%     10.47Ki ± 0%       ~ (p=1.000 n=10) ¹
SpanSetAttributesOverCapacity-12                       592.0 ± 0%       592.0 ± 0%       ~ (p=1.000 n=10) ¹
StartEndSpan/AlwaysSample-12                           528.0 ± 0%       528.0 ± 0%       ~ (p=1.000 n=10) ¹
StartEndSpan/NeverSample-12                            144.0 ± 0%       144.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_4/AlwaysSample-12                 1.016Ki ± 0%     1.016Ki ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_4/NeverSample-12                    400.0 ± 0%       400.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_8/AlwaysSample-12                 1.516Ki ± 0%     1.516Ki ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_8/NeverSample-12                    656.0 ± 0%       656.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all/AlwaysSample-12               1.141Ki ± 0%     1.141Ki ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all/NeverSample-12                  464.0 ± 0%       464.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all_2x/AlwaysSample-12            1.891Ki ± 0%     1.891Ki ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all_2x/NeverSample-12               848.0 ± 0%       848.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_4/AlwaysSample-12                     1.016Ki ± 0%     1.016Ki ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_4/NeverSample-12                        144.0 ± 0%       144.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_8/AlwaysSample-12                     1.641Ki ± 0%     1.641Ki ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_8/NeverSample-12                        144.0 ± 0%       144.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithStackTrace/AlwaysSample-12          624.0 ± 0%       624.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithStackTrace/NeverSample-12           160.0 ± 0%       160.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithTimestamp/AlwaysSample-12           648.0 ± 0%       648.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithTimestamp/NeverSample-12            184.0 ± 0%       184.0 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_10,_spans:_10-12             0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_10,_spans:_100-12            0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_100,_spans:_10-12            0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_100,_spans:_100-12           0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorVerboseLogging-12                       9.547Ki ± 0%     9.547Ki ± 0%       ~ (p=1.000 n=10) ¹
geomean                                                           ²                 +0.00%                ²
¹ all samples are equal
² summaries must be >0 to compute geomean

                                              │ ../private/base.txt │         ../private/new.txt         │
                                              │      allocs/op      │ allocs/op   vs base                 │
Truncate/Unlimited-12                                  0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/Zero-12                                       0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/Short-12                                      0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/ASCII-12                                      0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/ValidUTF-8-12                                 0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/InvalidUTF-8-12                               1.000 ± 0%     1.000 ± 0%       ~ (p=1.000 n=10) ¹
Truncate/MixedUTF-8-12                                 1.000 ± 0%     1.000 ± 0%       ~ (p=1.000 n=10) ¹
RecordingSpanSetAttributes/WithLimit/false-12          3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
RecordingSpanSetAttributes/WithLimit/true-12           10.00 ± 0%     10.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanEnd-12                                             0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
TraceStart/with_a_simple_span-12                       2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
TraceStart/with_several_links-12                       3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
TraceStart/with_attributes-12                          4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributeValueLengthLimit-12                41.00 ± 0%     41.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributeCountLimit-12                      38.00 ± 0%     38.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/EventCountLimit-12                          35.00 ± 0%     35.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/LinkCountLimit-12                           35.00 ± 0%     35.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributePerEventCountLimit-12              38.00 ± 0%     38.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanLimits/AttributePerLinkCountLimit-12               38.00 ± 0%     38.00 ± 0%       ~ (p=1.000 n=10) ¹
SpanSetAttributesOverCapacity-12                       3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
StartEndSpan/AlwaysSample-12                           2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
StartEndSpan/NeverSample-12                            2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_4/AlwaysSample-12                   4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_4/NeverSample-12                    3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_8/AlwaysSample-12                   4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_8/NeverSample-12                    3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all/AlwaysSample-12                 4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all/NeverSample-12                  3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all_2x/AlwaysSample-12              4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithAttributes_all_2x/NeverSample-12               3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_4/AlwaysSample-12                       5.000 ± 0%     5.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_4/NeverSample-12                        2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_8/AlwaysSample-12                       6.000 ± 0%     6.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_8/NeverSample-12                        2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithStackTrace/AlwaysSample-12          4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithStackTrace/NeverSample-12           3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithTimestamp/AlwaysSample-12           5.000 ± 0%     5.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanWithEvents_WithTimestamp/NeverSample-12            4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_10,_spans:_10-12             0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_10,_spans:_100-12            0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_100,_spans:_10-12            0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorOnEnd/batch:_100,_spans:_100-12           0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
SpanProcessorVerboseLogging-12                         35.00 ± 0%     35.00 ± 0%       ~ (p=1.000 n=10) ¹
geomean                                                           ²               +0.00%                ²
¹ all samples are equal
² summaries must be >0 to compute geomean
```

### Benchstate for parsing

```
goos: darwin
goarch: arm64
pkg: go.opentelemetry.io/otel/sdk/trace
cpu: Apple M2 Max
                  │ ../private/base_hex.txt │       ../private/new_hex.txt        │
                  │         sec/op          │   sec/op     vs base                │
TraceIDFromHex-12               56.47n ± 0%   15.96n ± 0%  -71.74% (p=0.000 n=10)
SpanIDFromHex-12               34.680n ± 0%   8.742n ± 1%  -74.79% (p=0.000 n=10)
geomean                         44.26n        11.81n       -73.31%

                  │ ../private/base_hex.txt │         ../private/new_hex.txt          │
                  │          B/op           │    B/op     vs base                     │
TraceIDFromHex-12                16.00 ± 0%    0.00 ± 0%  -100.00% (p=0.000 n=10)
SpanIDFromHex-12                 8.000 ± 0%   0.000 ± 0%  -100.00% (p=0.000 n=10)
geomean                          11.31                    ?                       ¹ ²
¹ summaries must be >0 to compute geomean
² ratios must be >0 to compute geomean

                  │ ../private/base_hex.txt │         ../private/new_hex.txt          │
                  │        allocs/op        │ allocs/op   vs base                     │
TraceIDFromHex-12                1.000 ± 0%   0.000 ± 0%  -100.00% (p=0.000 n=10)
SpanIDFromHex-12                 1.000 ± 0%   0.000 ± 0%  -100.00% (p=0.000 n=10)
geomean                          1.000                    ?                       ¹ ²
¹ summaries must be >0 to compute geomean
² ratios must be >0 to compute geomean
```

Issue: open-telemetry#6721
@jschaf
Copy link
Contributor Author

jschaf commented May 17, 2025

Added a benchmark for parsing the hex. It's about 4x faster and doesn't allocate.

goos: darwin
goarch: arm64
pkg: go.opentelemetry.io/otel/sdk/trace
cpu: Apple M2 Max
                  │ ../private/base_hex.txt │       ../private/new_hex.txt        │
                  │         sec/op          │   sec/op     vs base                │
TraceIDFromHex-12               56.47n ± 0%   15.96n ± 0%  -71.74% (p=0.000 n=10)
SpanIDFromHex-12               34.680n ± 0%   8.742n ± 1%  -74.79% (p=0.000 n=10)
geomean                         44.26n        11.81n       -73.31%

                  │ ../private/base_hex.txt │         ../private/new_hex.txt          │
                  │          B/op           │    B/op     vs base                     │
TraceIDFromHex-12                16.00 ± 0%    0.00 ± 0%  -100.00% (p=0.000 n=10)
SpanIDFromHex-12                 8.000 ± 0%   0.000 ± 0%  -100.00% (p=0.000 n=10)
geomean                          11.31                    ?                       ¹ ²
¹ summaries must be >0 to compute geomean
² ratios must be >0 to compute geomean

                  │ ../private/base_hex.txt │         ../private/new_hex.txt          │
                  │        allocs/op        │ allocs/op   vs base                     │
TraceIDFromHex-12                1.000 ± 0%   0.000 ± 0%  -100.00% (p=0.000 n=10)
SpanIDFromHex-12                 1.000 ± 0%   0.000 ± 0%  -100.00% (p=0.000 n=10)
geomean                          1.000                    ?                       ¹ ²
¹ summaries must be >0 to compute geomean
² ratios must be >0 to compute geomean

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area:trace Part of OpenTelemetry tracing enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants