Skip to content

Adjust tracer home resolution to honor architecture-specific profiler paths#7567

Closed
lucaspimentel wants to merge 4 commits intomasterfrom
codex/remove-dd_dotnet_tracer_home-dependency
Closed

Adjust tracer home resolution to honor architecture-specific profiler paths#7567
lucaspimentel wants to merge 4 commits intomasterfrom
codex/remove-dd_dotnet_tracer_home-dependency

Conversation

@lucaspimentel
Copy link
Member

Summary

  • iterate profiler path environment variables per runtime so we prefer the value matching the current process architecture
  • add .NET Core logic to prefer CORECLR_PROFILER_PATH_ before falling back to CORECLR_PROFILER_PATH when deriving the tracer home
  • add .NET Framework logic to prefer COR_PROFILER_PATH_ before falling back to COR_PROFILER_PATH when deriving the tracer home

Testing

  • dotnet build tracer/src/Datadog.Trace.ClrProfiler.Managed.Loader/Datadog.Trace.ClrProfiler.Managed.Loader.csproj

https://chatgpt.com/codex/tasks/task_b_68d59245fcec832180db94dd256130ba

@dd-trace-dotnet-ci-bot
Copy link

dd-trace-dotnet-ci-bot bot commented Sep 25, 2025

Execution-Time Benchmarks Report ⏱️

Execution-time results for samples comparing the following branches/commits:

Execution-time benchmarks measure the whole time it takes to execute a program. And are intended to measure the one-off costs. Cases where the execution time results for the PR are worse than latest master results are shown in red. The following thresholds were used for comparing the execution times:

  • Welch test with statistical test for significance of 5%
  • Only results indicating a difference greater than 5% and 5 ms are considered.

Note that these results are based on a single point-in-time result for each branch. For full results, see the dashboard.

Graphs show the p99 interval based on the mean and StdDev of the test run, as well as the mean value of the run (shown as a diamond below the graph).

gantt
    title Execution time (ms) FakeDbCommand (.NET Framework 4.8) 
    dateFormat  X
    axisFormat %s
    todayMarker off
    section Bailout
    This PR (7567) - mean (72ms)  : 71, 73
     .   : milestone, 72,
    master - mean (77ms)  : 68, 86
     .   : milestone, 77,

    section Baseline
    This PR (7567) - mean (68ms)  : 65, 71
     .   : milestone, 68,
    master - mean (71ms)  : 66, 75
     .   : milestone, 71,

    section CallTarget+Inlining+NGEN
    This PR (7567) - mean (1,056ms)  : 1000, 1112
     .   : milestone, 1056,
    master - mean (1,063ms)  : 998, 1128
     .   : milestone, 1063,

Loading
gantt
    title Execution time (ms) FakeDbCommand (.NET Core 3.1) 
    dateFormat  X
    axisFormat %s
    todayMarker off
    section Bailout
    This PR (7567) - mean (114ms)  : 111, 116
     .   : milestone, 114,
    master - mean (109ms)  : 107, 111
     .   : milestone, 109,

    section Baseline
    This PR (7567) - mean (113ms)  : 110, 115
     .   : milestone, 113,
    master - mean (108ms)  : 105, 112
     .   : milestone, 108,

    section CallTarget+Inlining+NGEN
    This PR (7567) - mean (747ms)  : 722, 771
     .   : milestone, 747,
    master - mean (769ms)  : 726, 813
     .   : milestone, 769,

Loading
gantt
    title Execution time (ms) FakeDbCommand (.NET 6) 
    dateFormat  X
    axisFormat %s
    todayMarker off
    section Bailout
    This PR (7567) - mean (100ms)  : 99, 102
     .   : milestone, 100,
    master - mean (108ms)  : 101, 115
     .   : milestone, 108,

    section Baseline
    This PR (7567) - mean (100ms)  : 98, 102
     .   : milestone, 100,
    master - mean (105ms)  : 96, 113
     .   : milestone, 105,

    section CallTarget+Inlining+NGEN
    This PR (7567) - mean (778ms)  : 733, 823
     .   : milestone, 778,
    master - mean (799ms)  : 743, 855
     .   : milestone, 799,

Loading
gantt
    title Execution time (ms) FakeDbCommand (.NET 8) 
    dateFormat  X
    axisFormat %s
    todayMarker off
    section Bailout
    This PR (7567) - mean (93ms)  : 91, 94
     .   : milestone, 93,
    master - mean (97ms)  : 92, 102
     .   : milestone, 97,

    section Baseline
    This PR (7567) - mean (92ms)  : 90, 94
     .   : milestone, 92,
    master - mean (96ms)  : 90, 101
     .   : milestone, 96,

    section CallTarget+Inlining+NGEN
    This PR (7567) - mean (660ms)  : 645, 676
     .   : milestone, 660,
    master - mean (675ms)  : 649, 700
     .   : milestone, 675,

Loading
gantt
    title Execution time (ms) HttpMessageHandler (.NET Framework 4.8) 
    dateFormat  X
    axisFormat %s
    todayMarker off
    section Bailout
    This PR (7567) - mean (201ms)  : 196, 206
     .   : milestone, 201,
    master - mean (208ms)  : 196, 220
     .   : milestone, 208,

    section Baseline
    This PR (7567) - mean (198ms)  : 192, 204
     .   : milestone, 198,
    master - mean (203ms)  : 194, 213
     .   : milestone, 203,

    section CallTarget+Inlining+NGEN
    This PR (7567) - mean (1,192ms)  : 1107, 1277
     .   : milestone, 1192,
    master - mean (1,230ms)  : 1143, 1318
     .   : milestone, 1230,

Loading
gantt
    title Execution time (ms) HttpMessageHandler (.NET Core 3.1) 
    dateFormat  X
    axisFormat %s
    todayMarker off
    section Bailout
    This PR (7567) - mean (285ms)  : 275, 296
     .   : milestone, 285,
    master - mean (298ms)  : 283, 313
     .   : milestone, 298,

    section Baseline
    This PR (7567) - mean (284ms)  : 276, 292
     .   : milestone, 284,
    master - mean (298ms)  : 282, 313
     .   : milestone, 298,

    section CallTarget+Inlining+NGEN
    This PR (7567) - mean (952ms)  : 915, 988
     .   : milestone, 952,
    master - mean (995ms)  : 956, 1034
     .   : milestone, 995,

Loading
gantt
    title Execution time (ms) HttpMessageHandler (.NET 6) 
    dateFormat  X
    axisFormat %s
    todayMarker off
    section Bailout
    This PR (7567) - mean (287ms)  : 281, 293
     .   : milestone, 287,
    master - mean (301ms)  : 285, 316
     .   : milestone, 301,

    section Baseline
    This PR (7567) - mean (288ms)  : 281, 295
     .   : milestone, 288,
    master - mean (300ms)  : 279, 321
     .   : milestone, 300,

    section CallTarget+Inlining+NGEN
    This PR (7567) - mean (1,013ms)  : 982, 1043
     .   : milestone, 1013,
    master - mean (1,040ms)  : 993, 1088
     .   : milestone, 1040,

Loading
gantt
    title Execution time (ms) HttpMessageHandler (.NET 8) 
    dateFormat  X
    axisFormat %s
    todayMarker off
    section Bailout
    This PR (7567) - mean (276ms)  : 270, 281
     .   : milestone, 276,
    master - mean (292ms)  : 271, 312
     .   : milestone, 292,

    section Baseline
    This PR (7567) - mean (275ms)  : 268, 283
     .   : milestone, 275,
    master - mean (291ms)  : 269, 314
     .   : milestone, 291,

    section CallTarget+Inlining+NGEN
    This PR (7567) - mean (873ms)  : 845, 900
     .   : milestone, 873,
    master - mean (933ms)  : 842, 1024
     .   : milestone, 933,

Loading

@lucaspimentel lucaspimentel deleted the codex/remove-dd_dotnet_tracer_home-dependency branch October 3, 2025 21:20
lucaspimentel added a commit that referenced this pull request Oct 23, 2025
~_This PR is stacked on #7594. Merge that PR first._~

## Summary of changes

Make `DD_DOTNET_TRACER_HOME` optional. If not set, try to figure out the
path from `COR_PROFILER_PATH`/`CORECLR_PROFILER_PATH` and friends.

## Reason for change

One less env var for users to set manually. Easier onboarding, less
error-prone.

I recently worked on an escalation where `DD_DOTNET_TRACER_HOME` was set
to the wrong path so the tracer was not loading.

## Implementation details

The implementation makes `DD_DOTNET_TRACER_HOME` optional by adding
fallback logic to derive the tracer home path from the profiler path
environment variables:

  1. **New method `GetTracerHomePath`** (`Startup.cs:150-178`):
- First checks for explicit `DD_DOTNET_TRACER_HOME` setting (preserves
backward compatibility)
- Falls back to computing the path from architecture-specific profiler
path env vars (e.g., `CORECLR_PROFILER_PATH_64`, `COR_PROFILER_PATH_64`)
- If not found, tries the generic profiler path env var (e.g.,
`CORECLR_PROFILER_PATH`, `COR_PROFILER_PATH`)

2. **New method `ComputeTracerHomePathFromProfilerPath`**
(`Startup.cs:180-218`):
- Takes a profiler path like
`C:\tracer\win-x64\Datadog.Trace.ClrProfiler.Native.dll`
     - Extracts the parent directory
- If the parent directory name matches a known architecture folder
(e.g., `win-x64`, `linux-arm64`, `osx`), goes up one more level
     - Returns the computed tracer home path

  3. **Platform-specific helper methods**:
- `GetProfilerPathEnvVarNameForArch()`: Returns the
architecture-specific env var name (`CORECLR_PROFILER_PATH_64` on .NET
Core x64, `COR_PROFILER_PATH_32` on .NET Framework x86, etc.)
- `GetProfilerPathEnvVarNameFallback()`: Returns the generic env var
name (`CORECLR_PROFILER_PATH` or `COR_PROFILER_PATH`)

  4. **Architecture directory detection**:
- Maintains a `HashSet<string>` of known architecture directories
(`win-x64`, `win-x86`, `linux-x64`, `linux-arm64`, etc)

## Test coverage

**Unit tests**
(`tracer/test/Datadog.Trace.Tests/ClrProfiler/Managed/Loader/`):
- Environment variable reading and fallback logic
(`StartupNetCoreTests.cs`, `StartupNetFrameworkTests.cs`)
- `GetTracerHomePath()` with explicit `DD_DOTNET_TRACER_HOME`
(with/without whitespace)
- `GetTracerHomePath()` with architecture-specific profiler path
fallback
- `GetTracerHomePath()` with generic profiler path fallback
- `ComputeTracerHomePathFromProfilerPath()` with all architecture
directories
- Edge cases: empty values, whitespace, missing variables, null handling

**Integration tests**:
- Added `WhenOmittingTracerHome_InstrumentsApp()` test in
`InstrumentationTests.cs` that explicitly omits `DD_DOTNET_TRACER_HOME`
and verifies instrumentation works via fallback logic
- Modified all smoke tests (`SmokeTests/SmokeTestBase.cs`) to omit
`DD_DOTNET_TRACER_HOME` by default, providing comprehensive real-world
validation of the fallback behavior across multiple regression scenarios

## Other details
<!-- Fixes #{issue} -->

⚠️ Based on #7567, which was originally [generated by OpenAI
Codex](https://chatgpt.com/codex/tasks/task_b_68d59245fcec832180db94dd256130ba),
but I made substantial changes to clean up and refactor.


<!--  ⚠️ Note:

Where possible, please obtain 2 approvals prior to merging. Unless
CODEOWNERS specifies otherwise, for external teams it is typically best
to have one review from a team member, and one review from apm-dotnet.
Trivial changes do not require 2 reviews.

MergeQueue is NOT enabled in this repository. If you have write access
to the repo, the PR has 1-2 approvals (see above), and all of the
required checks have passed, you can use the Squash and Merge button to
merge the PR. If you don't have write access, or you need help, reach
out in the #apm-dotnet channel in Slack.
-->

---------

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant