Skip to content

perf(spanner): short-circuit trace_call when tracing is inactive - #18356

Merged
olavloite merged 1 commit into
mainfrom
spanner-short-circuit-tracing
Sep 28, 2026
Merged

olavloite merged 1 commit into
mainfrom
spanner-short-circuit-tracing

Conversation

@olavloite

@olavloite olavloite commented Sep 12, 2026 •

Copy link
Copy Markdown
Contributor

Skip building the trace attribute dictionary and creating spans in
trace_call when OpenTelemetry is not configured or uses a no-op tracer.
This reduces overhead by ~4.8 µs per call (~10 µs per query).

If a valid ambient span is present in the caller's context, a child span
is still started on the no-op tracer to prevent Spanner-internal attributes
and events from attaching to the parent span.

Also update observability_options validation to check Mapping.

@olavloite
olavloite requested a review from a team as a code owner September 12, 2026 16:07

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a fast-path optimization in OpenTelemetry tracing for Google Cloud Spanner, bypassing attribute dictionary construction and span creation when a no-op tracer is active. It also expands type checking for observability options to support general mappings and adds comprehensive unit tests. The review feedback suggests further simplifying the fast-path implementation to eliminate nested context manager overhead when tracing is inactive, and recommends streamlining type checks by using isinstance(observability_options, Mapping) instead of checking for both dict and Mapping.

@olavloite
olavloite force-pushed the spanner-short-circuit-tracing branch from de84a9d to ab4c846 Compare September 13, 2026 09:50
@olavloite

Copy link
Copy Markdown
Contributor Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a fast-path optimization in trace_call to bypass attribute dictionary construction and span creation when a no-op tracer is active or no TracerProvider is registered. Feedback on the changes highlights two critical issues: first, the helper _is_tracer_noop should check _real_tracer instead of _tracer on ProxyTracer to correctly handle lazy initialization; second, the unit tests should assign to the private _tracer attribute instead of the read-only _real_tracer property to avoid raising an AttributeError at runtime.

Skip building the trace attribute dictionary and creating spans in
`trace_call` when OpenTelemetry is not configured or uses a no-op tracer.
This reduces overhead by ~4.8 µs per call (~10 µs per query).

If a valid ambient span is present in the caller's context, a child span
is still started on the no-op tracer to prevent Spanner-internal attributes
and events from attaching to the parent span.

Also update `observability_options` validation to check `Mapping`.
@olavloite
olavloite force-pushed the spanner-short-circuit-tracing branch from ab4c846 to 2b5821a Compare September 13, 2026 10:08
@olavloite

Copy link
Copy Markdown
Contributor Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a fast-path optimization in the OpenTelemetry tracing implementation for Google Cloud Spanner. When no TracerProvider is registered or a no-op tracer is active, the code now skips attribute dictionary construction and span creation entirely, yielding a non-recording span or an invalid span instead. Additionally, observability_options type checking was updated to support any Mapping subclass. Comprehensive unit tests were added to verify these changes under various tracing configurations. There are no review comments, and I have no feedback to provide.

@olavloite olavloite added kokoro:force-run Add this label to force Kokoro to re-run the tests. and removed kokoro:force-run Add this label to force Kokoro to re-run the tests. labels Sep 13, 2026
@yoshi-kokoro yoshi-kokoro removed the kokoro:force-run Add this label to force Kokoro to re-run the tests. label Sep 13, 2026
@uditdasari

Copy link
Copy Markdown
Contributor

Could you please share the benchmark? The code path I see is one trace_call per single-use query, so I'm curious what makes up the ~10 µs.

@olavloite

Copy link
Copy Markdown
Contributor Author

Could you please share the benchmark? The code path I see is one trace_call per single-use query, so I'm curious what makes up the ~10 µs.

Many of these changes are so small that we do not run separate benchmarks for them (this is one such example). Instead, this is more about shaving away a few microseconds everywhere you can find them, as in a single-threaded language like Python, that makes a much bigger difference for overall throughput than in multi-threaded languages. The 10us in this case purely an estimate. The overall picture is clearer when you take all of these together and compare with what the performance was before (see screenshots shared separately).

@olavloite
olavloite merged commit 58031be into main Sep 28, 2026
47 checks passed
@olavloite
olavloite deleted the spanner-short-circuit-tracing branch September 28, 2026 17:22
parthea pushed a commit that referenced this pull request Nov 12, 2026
🤖 I have created a release *beep* *boop*
---


##
[3.72.0](google-cloud-spanner-v3.71.0...google-cloud-spanner-v3.72.0)
(2026-11-12)


### Features

* **dbapi:** wire timeout parameter through Connection to execute_sql
([#18484](#18484))
([98fc304](98fc304))
* declare Python3.15 support
([8775794](8775794))
* **spanner:** auth login support for Spanner Omni endpoints
([#18273](#18273))
([9e0548d](9e0548d))
* update API sources and regenerate
([#18797](#18797))
([be4d954](be4d954))


### Bug Fixes

* **google-cloud-spanner:** clear buffered DDL statements on rollback
and flush on autocommit
([#18636](#18636))
([15d6a2c](15d6a2c))
* **google-cloud-spanner:** do not replay DDL statements on transaction
retry
([#18625](#18625))
([78b9da2](78b9da2))
* **spanner:** correctly wrap async streaming calls in metrics
interceptor
([#18581](#18581))
([2d19b0a](2d19b0a))
* **spanner:** eliminate duplicate metrics capture and measure full
streaming latency
([#18605](#18605))
([a7678fd](a7678fd))
* **spanner:** record streaming operation completion when stream
finishes
([#18704](#18704))
([ddeae47](ddeae47))
* **spanner:** release transaction lock if inline begin fails
([#18409](#18409))
([dd24029](dd24029))
* **spanner:** stop deleting multiplexed sessions on rotation and close
([#18332](#18332))
([c38e960](c38e960))


### Performance Improvements

* **spanner:** add fast-path for multiplexed session acquisition
([#18317](#18317))
([9569b39](9569b39))
* **spanner:** avoid allocating empty RequestOptions on read and query
paths
([#18422](#18422))
([3743ff0](3743ff0))
* **spanner:** build ExecuteSqlRequest on the raw protobuf message
([#18379](#18379))
([6d91fec](6d91fec))
* **spanner:** eliminate redundant tracing span in run_in_transaction
([#18357](#18357))
([181e26a](181e26a))
* **spanner:** optimize built-in metrics hot path and harden concurrency
([#18329](#18329))
([f2a791f](f2a791f))
* **spanner:** optimize query option merging and prevent in-place
mutation
([#18358](#18358))
([8cb3c6a](8cb3c6a))
* **spanner:** optimize query parameter encoding with direct type
dispatch
([#18359](#18359))
([f06497c](f06497c))
* **spanner:** optimize query result decoding and type resolution
([#18330](#18330))
([ce72986](ce72986))
* **spanner:** optimize request ID header generation and retry closures
([#18408](#18408))
([ad03b95](ad03b95))
* **spanner:** optimize row popping in StreamedResultSet
([#18316](#18316))
([e66103d](e66103d))
* **spanner:** optimize single-chunk results and single-row lookups
([#18602](#18602))
([05b3775](05b3775))
* **spanner:** prune lock and begin event allocations on single-use
snapshots
([#18420](#18420))
([ab56473](ab56473))
* **spanner:** short-circuit trace_call when tracing is inactive
([#18356](#18356))
([58031be](58031be))
* **spanner:** support PartialResultSet.last with background stream
draining
([#18320](#18320))
([80efd63](80efd63))


### Documentation

* fix typos
([#18979](#18979))
([5c8baeb](5c8baeb))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants