Skip to content

perf: Add more tracing spans into startup path#11965

Merged
anthonyshew merged 15 commits intomainfrom
perf/tracing-startup-instrumentation
Feb 23, 2026
Merged

perf: Add more tracing spans into startup path#11965
anthonyshew merged 15 commits intomainfrom
perf/tracing-startup-instrumentation

Conversation

@anthonyshew
Copy link
Copy Markdown
Contributor

@anthonyshew anthonyshew commented Feb 23, 2026

Summary

  • --profile previously had no visibility into pre-execution phases, making it impossible to diagnose startup overhead
  • Adds info-level tracing spans to every significant phase between process start and task execution
  • All spans appear in both the chrome trace JSON and the generated markdown summary

What this revealed

On this repo with turbo run check-types --skip-infer --profile:

Phase Time %
visit (task execution) 767.8ms 79.5%
build_http_client (TLS init) 96.5ms 10.0%
new_from_gix_index (git index) 48.5ms 5.0%
compile_globs 38.0ms 3.9%
find_untracked_files 30.9ms 3.2%
fetch (cache I/O) 28.0ms 2.9%

TLS initialization alone accounts for 10% of the non-execution overhead — even when remote caching is disabled. This data wasn't visible before.

Testing

Verified --profile=profile.json produces spans for all new instrumentation points. The .json.md summary correctly reports self-time and call trees for the new spans.

…very

Three targeted optimizations to the turbo run hot path:

1. Engine builder: Cache turbo.json chain per package and move the
   visited check before the expensive task_definition() call. The
   chain only depends on the package name, so multiple tasks in the
   same package reuse the cached result.

2. Task visitor: Defer env() computation to non-dry-run branches.
   The execution environment is unused during dry runs, avoiding
   per-task RwLock acquisition and env var map cloning.

3. find_untracked_files: Replace Mutex<Vec> with per-thread local
   buffers flushed via mpsc channel on drop, eliminating per-file
   mutex contention in the parallel walker.
Parallelize several sequential phases of turbo run's pre-execution
pipeline: dependency resolution, turbo.json loading, and task summary
construction. Also reduce per-call allocation overhead in the task
hash tracker and gix index classification.
…parallelize-hot-path

# Conflicts:
#	crates/turborepo-scm/src/repo_index.rs
Adds profiling visibility to functions that were invisible in
--profile output: TLS initialization, rayon-spawned hash tasks,
Visitor constructor, Engine scheduler, and per-task cache phases.
Store task hashes as Arc<str> in TaskHashTrackerState instead of String.
In calculate_dependency_hashes, cloning an Arc<str> is a ref count bump
instead of a heap allocation. For the api monorepo (1687 tasks, ~3 deps
each), this eliminates ~5000 String heap allocations per run.
…Summary

Removes the .to_string() conversion in the HashTrackerInfo::hash() trait
impl by changing the trait return type from Option<String> to
Option<Arc<str>>. Also changes SharedTaskSummary.hash to Arc<str> so the
Arc flows all the way to serialization without any String allocation.
The Arc<str> fields in TaskHashTrackerState and SharedTaskSummary
require serde's "rc" feature for Serialize. Previously this worked
via transitive feature activation; make it explicit so it doesn't
break if the transitive path changes.
The --profile output previously had no visibility into the
pre-execution phases of turbo run. This made it impossible to
diagnose where startup overhead was coming from.

Add info-level tracing spans to every significant phase:

- shim_run: top-level shim execution
- cli_run: CLI dispatch (arg parsing, http client, telemetry)
- http_client_init: TLS initialization for reqwest
- telemetry_init: telemetry client setup
- command_base_new: config loading and opts construction
- run_builder_new: API client and auth setup
- pkg_dep_graph_build: package graph construction
- scm_task_await: waiting for background SCM/git index
- async_cache_new: cache initialization
- calculate_filtered_packages: package filtering
- env_infer: environment variable snapshot
- turbo_json_preload: turbo.json cache warming
- build_engine: task graph construction
- hash_scope: parallel file hashing
- start_ui: UI initialization
- repo_inference: repository root detection

These spans appear in both the chrome trace JSON and the
generated markdown summary when using --profile.
@anthonyshew anthonyshew requested a review from a team as a code owner February 23, 2026 14:48
@anthonyshew anthonyshew requested review from tknickman and removed request for a team February 23, 2026 14:48
@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented Feb 23, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
examples-basic-web Ready Ready Preview, Comment, Open in v0 Feb 23, 2026 3:00pm
examples-designsystem-docs Ready Ready Preview, Comment, Open in v0 Feb 23, 2026 3:00pm
examples-gatsby-web Ready Ready Preview, Comment, Open in v0 Feb 23, 2026 3:00pm
examples-kitchensink-blog Ready Ready Preview, Comment, Open in v0 Feb 23, 2026 3:00pm
examples-nonmonorepo Ready Ready Preview, Comment, Open in v0 Feb 23, 2026 3:00pm
examples-svelte-web Ready Ready Preview, Comment, Open in v0 Feb 23, 2026 3:00pm
examples-tailwind-web Ready Ready Preview, Comment, Open in v0 Feb 23, 2026 3:00pm
examples-vite-web Ready Ready Preview, Comment, Open in v0 Feb 23, 2026 3:00pm
turbo-site Ready Ready Preview, Comment, Open in v0 Feb 23, 2026 3:00pm
turborepo-agents Ready Ready Preview, Comment, Open in v0 Feb 23, 2026 3:00pm
turborepo-test-coverage Ready Ready Preview, Comment, Open in v0 Feb 23, 2026 3:00pm

Comment thread crates/turborepo-lib/src/run/builder.rs Outdated
@anthonyshew anthonyshew changed the title perf: Add tracing spans across the turbo run startup path perf: Add more tracing spans into startup path Feb 23, 2026
Holding an EnteredSpan guard across .await corrupts tracing's
thread-local state when the future resumes on a different tokio
worker thread. Use .instrument() which correctly re-enters the
span on whichever thread the future polls on.
@github-actions
Copy link
Copy Markdown
Contributor

Coverage Report

Metric Coverage
Lines 75.16%
Functions 46.86%
Branches 0.00%

View full report

@anthonyshew anthonyshew merged commit 23e144d into main Feb 23, 2026
100 of 101 checks passed
@anthonyshew anthonyshew deleted the perf/tracing-startup-instrumentation branch February 23, 2026 15:16
github-actions Bot added a commit that referenced this pull request Feb 23, 2026
## Release v2.8.11-canary.23

Versioned docs: https://v2-8-11-canary-23.turborepo.dev

### Changes

- release(turborepo): 2.8.11-canary.22 (#11963) (`ac0f273`)
- chore: Migrate to Ultracite (#11948) (`a0db6bf`)
- perf: Add more tracing spans into startup path (#11965) (`23e144d`)

---------

Co-authored-by: Turbobot <turbobot@vercel.com>
github-actions Bot added a commit that referenced this pull request Feb 23, 2026
## Release v2.8.11-canary.24

Versioned docs: https://v2-8-11-canary-24.turborepo.dev

### Changes

- perf: Add more tracing spans into startup path (#11965) (`23e144d`)
- release(turborepo): 2.8.11-canary.23 (#11966) (`b425c39`)
- perf: Defer TLS initialization to a background thread (#11967)
(`f1d487f`)

---------

Co-authored-by: Turbobot <turbobot@vercel.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.

1 participant