Summary
Every test is wrapped in TimeoutHelper.ExecuteWithTimeoutAsync because TestDetails.Timeout is always set to the default (30 min), even when the user never applied [Timeout]. Estimated ~5% CPU + 4 extra allocations per test (linked CancellationTokenSource, TaskCompletionSource, CancellationTokenRegistration, Task.WhenAny array).
This is likely the single biggest ROI fix from the profiling session.
Evidence
Trace shows TimeoutHelper.ExecuteWithTimeoutAsync as ~5% inclusive / ~3% direct in the per-test path.
Root cause
TUnitSettings.Default.Timeouts.DefaultTestTimeout (30 min) is copied into TestDetails.Timeout during build, so testTimeout.HasValue is always true:
TUnit.Engine/Building/TestBuilderPipeline.cs:260, 387, 466, 519
TUnit.Engine/Building/TestBuilder.cs:1089, 1182
- Check-site:
TUnit.Engine/TestExecutor.cs:203
Every test then goes through TUnit.Engine/Helpers/TimeoutHelper.cs:26 with the full allocation set.
Proposed fix
- Leave
TestDetails.Timeout = null when the user did not specify [Timeout].
- Only run through
TimeoutHelper.ExecuteWithTimeoutAsync when a timeout is actually requested.
- If a global default is still desirable, apply it as a coarser session-level guard rather than per-test.
Expected impact
- ~5% CPU reduction per test.
- Removes 4 allocations per test — cuts GC pressure dramatically on large suites.
Files
TUnit.Engine/Building/TestBuilderPipeline.cs
TUnit.Engine/Building/TestBuilder.cs
TUnit.Engine/TestExecutor.cs
TUnit.Engine/Helpers/TimeoutHelper.cs
Summary
Every test is wrapped in
TimeoutHelper.ExecuteWithTimeoutAsyncbecauseTestDetails.Timeoutis always set to the default (30 min), even when the user never applied[Timeout]. Estimated ~5% CPU + 4 extra allocations per test (linkedCancellationTokenSource,TaskCompletionSource,CancellationTokenRegistration,Task.WhenAnyarray).This is likely the single biggest ROI fix from the profiling session.
Evidence
Trace shows
TimeoutHelper.ExecuteWithTimeoutAsyncas ~5% inclusive / ~3% direct in the per-test path.Root cause
TUnitSettings.Default.Timeouts.DefaultTestTimeout(30 min) is copied intoTestDetails.Timeoutduring build, sotestTimeout.HasValueis always true:TUnit.Engine/Building/TestBuilderPipeline.cs:260, 387, 466, 519TUnit.Engine/Building/TestBuilder.cs:1089, 1182TUnit.Engine/TestExecutor.cs:203Every test then goes through
TUnit.Engine/Helpers/TimeoutHelper.cs:26with the full allocation set.Proposed fix
TestDetails.Timeout = nullwhen the user did not specify[Timeout].TimeoutHelper.ExecuteWithTimeoutAsyncwhen a timeout is actually requested.Expected impact
Files
TUnit.Engine/Building/TestBuilderPipeline.csTUnit.Engine/Building/TestBuilder.csTUnit.Engine/TestExecutor.csTUnit.Engine/Helpers/TimeoutHelper.cs