Skip to content

perf: split filter data into separate lightweight class to avoid full .cctor during discovery #5394

@thomhurst

Description

@thomhurst

Summary

Follow-up to the lazy registration optimization (which defers per-class .cctor JIT from module init to discovery time).

Currently, when the engine needs to filter tests by method name/category, it must resolve the lazy factory for each matching class — which triggers the full .cctor (creating ClassMetadata, MethodMetadata, delegate captures, TestEntry[] arrays).

The idea is to emit filter data in a separate nested class with its own lightweight .cctor, so that discovery filtering only JITs the filter data — not the full test entries.

Proposed approach

Split the generated __TestSource class into two parts:

internal static class TUnit_TestProject_BasicTests__TestSource
{
    // Separate class = separate .cctor (just strings and booleans, no delegates)
    internal static class Filter
    {
        public static readonly int Count = 3;
        public static readonly TestEntryFilterData[] Data = new[]
        {
            new TestEntryFilterData { MethodName = "SynchronousTest", ClassName = "BasicTests", ... },
            new TestEntryFilterData { MethodName = "AsynchronousTest", ClassName = "BasicTests", ... },
            new TestEntryFilterData { MethodName = "ValueTaskAsynchronousTest", ClassName = "BasicTests", ... },
        };
    }
    
    // Full entries — only accessed when tests actually need to execute
    public static readonly TestEntry<BasicTests>[] Entries = /* ... existing ... */;
}

Registration becomes:

SourceRegistrar.RegisterLazy<BasicTests>(
    TUnit_TestProject_BasicTests__TestSource.Filter.Data,     // ← cheap, separate .cctor
    static () => TUnit_TestProject_BasicTests__TestSource.Entries);  // ← deferred until execution

Benefit

During discovery:

  • Type filter — zero materialization (dict key check only)
  • Method/category filter — only Filter..cctor JIT'd (just string arrays, ~microseconds)
  • Execution — full __TestSource..cctor JIT'd (delegates, metadata) only for tests that will run

Context

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions