You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add realistic ZipArchive metadata-reading benchmarks using a generated ZIP containing JSON package metadata and payload entries.
Cover synchronous and asynchronous reads from both memory and file streams.
Move the runtime-async feature gate to the repository root so BenchmarkDotNet-generated projects under artifacts/ inherit it.
The public async benchmark uses a synchronous BenchmarkDotNet entrypoint around a private async workload. This avoids BenchmarkDotNet generating an async void runner state machine while preserving runtime-async compilation for the measured workload.
Runtime comparison
Using matched compiler-async and runtime-async benchmark builds and System.IO.Compression CoreRoots:
Source
Compiler async
Runtime async
Time
Allocation
Memory
19.61 us, 29,568 B
18.56 us, 26,560 B
5.3% faster
10.2% less
File
424.71 us, 36,030 B
375.88 us, 33,044 B
11.5% faster
8.3% less
The results reproduced across two paired runs. The runtime-async benchmark workload contains no generated async state machine.
Add sync and async ZipArchive metadata-reading benchmarks over memory and file streams. Move the runtime-async feature gate to the repository root so BenchmarkDotNet-generated projects inherit it.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d6957835-b7f3-45ee-875f-4efad68e3c4e
The reason will be displayed to describe this comment to others. Learn more.
Copilot review overview
🟢 Approval recommended
The changes look correct and aligned with the stated benchmarking/build goals, with only a minor benchmark-noise improvement suggested.
Review tier: Lite Findings: 1
New issues introduced by this change (1)
Severity
Finding
src/benchmarks/micro/libraries/System.IO.Compression/ZipArchive.cs — GetMetadataEntry uses LINQ (Entries.First + predicate), which adds extra overhead/allocations into…
What changed in this PR
This pull request adds new microbenchmarks to measure ZipArchive metadata-reading performance across sync/async and memory/file-backed streams, and adjusts the build so the runtime-async feature gate is applied from the repository root (allowing BenchmarkDotNet-generated projects under artifacts/ to inherit it).
Changes:
Added a ZipArchive metadata-reading benchmark that generates a representative ZIP (JSON metadata + payload entries) and measures sync vs async read paths from memory and file streams.
Moved the runtime-async feature gating logic from src/Directory.Build.targets into the repository root Directory.Build.targets.
Removed the now-unneeded src/Directory.Build.targets.
File
Description
src/Directory.Build.targets
Removed subdirectory build targets so the root targets apply directly under src/.
This avoids BenchmarkDotNet generating an async void runner state machine while preserving runtime-async compilation for the measured workload.
What's the issue with async void calling async Task<int>? As far as I'm aware, the generated project should pick up the runtime-async feature from the root targets. And that generated code should result in better measurements than the GetAwaiter().GetResult() method.
The public async benchmark uses a synchronous BenchmarkDotNet entrypoint around a private async workload.
You can also use [ConsumeTasksSynchronously(true)] instead of manually wrapping it if you need that behavior.
Moved the whole-file .NET 10 gate from ZipArchive.cs into MicroBenchmarks.csproj, matching the existing whole-file framework exclusions (particularly Zstandard.cs in this directory). This is a consistency change, not a correctness fix; benchmark behavior and supported frameworks are unchanged.
This relocation leaves the setup documentation in scripts/ci_setup.py:430-432 pointing at src/Directory.Build.targets, which no longer exists. Please update that comment to reference the repository-root Directory.Build.targets so maintainers are not directed to a deleted file.
async void isn't supported by runtime-async, so it generates a de-optimization
That's not included in the measurement, though. The measurement is in a loop in an async Task method. The async void method just kicks it off. If you observed a measurement regression with that, maybe the generated project isn't picking up the feature, so it's still using async v1 for the async Task. Can you confirm? We should fix it in BDN if it's doing the wrong thing. If you pass the feature by MsBuildArgument does it generate it correctly?
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
ZipArchivemetadata-reading benchmarks using a generated ZIP containing JSON package metadata and payload entries.artifacts/inherit it.The public async benchmark uses a synchronous BenchmarkDotNet entrypoint around a private async workload. This avoids BenchmarkDotNet generating an
async voidrunner state machine while preserving runtime-async compilation for the measured workload.Runtime comparison
Using matched compiler-async and runtime-async benchmark builds and
System.IO.CompressionCoreRoots:The results reproduced across two paired runs. The runtime-async benchmark workload contains no generated async state machine.