From d07f964f79776cf455fe17420df01588e4931d94 Mon Sep 17 00:00:00 2001 From: Marcel Roozerkans Date: Fri, 22 May 2026 15:35:22 +0200 Subject: [PATCH] chore(deps): migrate to ZeroAlloc.TestHelpers for AllocationGate Removes the local samples/.../Internal/AllocationGate.cs and pulls the helper in via the new ZeroAlloc.TestHelpers package (ZeroAlloc-Net/ZeroAlloc.TestHelpers, source-only NuGet at contentFiles/cs/any/ZeroAlloc.TestHelpers/AllocationGate.cs). Consumer recipe per the package's README: PrivateAssets="all" + IncludeAssets="contentfiles;build" on the PackageReference. The source file compiles into the AotSmoke assembly as internal static class AllocationGate in namespace ZeroAlloc.TestHelpers. The test project previously consumed the same helper via link from the smoke sample; it now references the package directly and the link is removed. Part of the org-wide migration closing AllocationGate-copy-drift across the ZeroAlloc.* ecosystem (ZA.Mediator backlog #10). --- .../Internal/AllocationGate.cs | 73 ------------------- .../Program.cs | 2 +- .../ZeroAlloc.Authorization.AotSmoke.csproj | 4 + .../AllocationBudgetTests.cs | 2 +- .../ZeroAlloc.Authorization.Tests.csproj | 8 +- 5 files changed, 10 insertions(+), 79 deletions(-) delete mode 100644 samples/ZeroAlloc.Authorization.AotSmoke/Internal/AllocationGate.cs diff --git a/samples/ZeroAlloc.Authorization.AotSmoke/Internal/AllocationGate.cs b/samples/ZeroAlloc.Authorization.AotSmoke/Internal/AllocationGate.cs deleted file mode 100644 index 32b9712..0000000 --- a/samples/ZeroAlloc.Authorization.AotSmoke/Internal/AllocationGate.cs +++ /dev/null @@ -1,73 +0,0 @@ -namespace ZeroAlloc.Authorization.AotSmoke.Internal; - -internal static class AllocationGate -{ - public static void AssertBudget(int budgetBytes, int iterations, Action action, string label) - { - ArgumentNullException.ThrowIfNull(action); - if (iterations < 1) throw new ArgumentOutOfRangeException(nameof(iterations)); - - // Warmup — JIT-compile, populate type-handle caches, allocate one-time fixtures. - action(); - action(); - - // Flush warmup garbage so it can't leak into the measurement. - GC.Collect(); - GC.WaitForPendingFinalizers(); - GC.Collect(); - - var before = GC.GetAllocatedBytesForCurrentThread(); - for (int i = 0; i < iterations; i++) action(); - var allocated = GC.GetAllocatedBytesForCurrentThread() - before; - - var perCall = allocated / iterations; - var totalBudget = (long)budgetBytes * iterations; - if (allocated > totalBudget) - { - throw new InvalidOperationException( - $"AllocationGate: {label} allocated {allocated} B total over {iterations} iterations " + - $"(~{perCall} B/call avg), budget is {budgetBytes} B/call ({totalBudget} B total). " + - "Use BenchmarkDotNet [MemoryDiagnoser] locally to find the culprit."); - } - } - - public static void AssertBudgetValueTask(int budgetBytes, int iterations, Func> action, string label) - { - ArgumentNullException.ThrowIfNull(action); - if (iterations < 1) throw new ArgumentOutOfRangeException(nameof(iterations)); - - static T Drain(ValueTask t) - { - if (!t.IsCompletedSuccessfully) - { - throw new InvalidOperationException( - "AllocationGate: sync-completion-required — the supplied ValueTask did not " + - "complete synchronously. Awaiter machinery would pollute the measurement; " + - "the API under test must return an already-completed ValueTask."); - } - return t.Result; - } - - // Warmup. - Drain(action()); - Drain(action()); - - GC.Collect(); - GC.WaitForPendingFinalizers(); - GC.Collect(); - - var before = GC.GetAllocatedBytesForCurrentThread(); - for (int i = 0; i < iterations; i++) Drain(action()); - var allocated = GC.GetAllocatedBytesForCurrentThread() - before; - - var perCall = allocated / iterations; - var totalBudget = (long)budgetBytes * iterations; - if (allocated > totalBudget) - { - throw new InvalidOperationException( - $"AllocationGate: {label} allocated {allocated} B total over {iterations} iterations " + - $"(~{perCall} B/call avg), budget is {budgetBytes} B/call ({totalBudget} B total). " + - "Use BenchmarkDotNet [MemoryDiagnoser] locally to find the culprit."); - } - } -} diff --git a/samples/ZeroAlloc.Authorization.AotSmoke/Program.cs b/samples/ZeroAlloc.Authorization.AotSmoke/Program.cs index 8c4b774..e0b0020 100644 --- a/samples/ZeroAlloc.Authorization.AotSmoke/Program.cs +++ b/samples/ZeroAlloc.Authorization.AotSmoke/Program.cs @@ -1,6 +1,6 @@ using Microsoft.Extensions.DependencyInjection; using ZeroAlloc.Authorization; -using ZeroAlloc.Authorization.AotSmoke.Internal; +using ZeroAlloc.TestHelpers; using ZeroAlloc.Authorization.Generated; using ZeroAlloc.Results; diff --git a/samples/ZeroAlloc.Authorization.AotSmoke/ZeroAlloc.Authorization.AotSmoke.csproj b/samples/ZeroAlloc.Authorization.AotSmoke/ZeroAlloc.Authorization.AotSmoke.csproj index 46d3436..6601f32 100644 --- a/samples/ZeroAlloc.Authorization.AotSmoke/ZeroAlloc.Authorization.AotSmoke.csproj +++ b/samples/ZeroAlloc.Authorization.AotSmoke/ZeroAlloc.Authorization.AotSmoke.csproj @@ -16,6 +16,10 @@ + + all + contentfiles;build + diff --git a/tests/ZeroAlloc.Authorization.Tests/AllocationBudgetTests.cs b/tests/ZeroAlloc.Authorization.Tests/AllocationBudgetTests.cs index 0951388..020447a 100644 --- a/tests/ZeroAlloc.Authorization.Tests/AllocationBudgetTests.cs +++ b/tests/ZeroAlloc.Authorization.Tests/AllocationBudgetTests.cs @@ -1,5 +1,5 @@ using ZeroAlloc.Authorization; -using ZeroAlloc.Authorization.AotSmoke.Internal; +using ZeroAlloc.TestHelpers; using ZeroAlloc.Results; namespace ZeroAlloc.Authorization.Tests; diff --git a/tests/ZeroAlloc.Authorization.Tests/ZeroAlloc.Authorization.Tests.csproj b/tests/ZeroAlloc.Authorization.Tests/ZeroAlloc.Authorization.Tests.csproj index 5f21d47..a9f9da4 100644 --- a/tests/ZeroAlloc.Authorization.Tests/ZeroAlloc.Authorization.Tests.csproj +++ b/tests/ZeroAlloc.Authorization.Tests/ZeroAlloc.Authorization.Tests.csproj @@ -9,6 +9,10 @@ + + all + contentfiles;build + @@ -16,8 +20,4 @@ - - -