Skip to content

perf: avoid per-test TCS allocation when test has no dependencies #5716

@thomhurst

Description

@thomhurst

Summary

TestRunner allocates a TaskCompletionSource<bool> and inserts into a dedup dictionary for every single test — to support test dependency recursion. But the vast majority of tests have zero dependencies, so this allocation and dictionary growth is pure waste. Estimated 1 TCS + 1 dict entry avoided per test (~1K allocations for a 1K-test suite).

Evidence

TUnit.Engine/Scheduling/TestRunner.cs:45-89 — unconditional TCS + _executingTests[testId] = tcs.

Trace: __Canon].GetOrAdd(...) 1.36% inclusive / 1.08% self — partly this dedup dict.

Proposed fix

  • Skip the TCS + dict entirely when test.Dependencies.Count == 0.
  • Only allocate on first entry into a dependency-bearing call path.
  • Alternative: replace with ConcurrentDictionary<string, Task> storing the execution Task directly via GetOrAdd, eliminating the TCS and WrapAsync layer.

Expected impact

  • 1013 TCS + dict entries avoided on the profile workload.
  • Measurable dent in GetOrAdd 1.08% exclusive.
  • Reduced GC pressure on large suites.

Metadata

Metadata

Assignees

No one assigned

    Labels

    .NETPull requests that update .net codeduplicateThis issue or pull request already existsenhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions