Skip to content

6.1: open workbooks from your own sources and streams, managed inflate, leaner typed parse - #140

Open
GabrielMarquezMatte wants to merge 45 commits into
masterfrom
develop
Open

GabrielMarquezMatte wants to merge 45 commits into
masterfrom
develop

Conversation

@GabrielMarquezMatte

@GabrielMarquezMatte GabrielMarquezMatte commented Oct 8, 2026 •

Copy link
Copy Markdown
Owner

What does this change?

Everything on develop since v6.0.0, as the candidate for 6.1.0. Two features and two performance
changes, with no change to the .NET public API and only additions to the C ABI (XL_ABI_VERSION stays 6).

Open a workbook from your own bytes

  • Core: a workbook can be read from any byte source through a seekable view, with the source
    fetched in blocks and each block fetched once (57dc08c, fcb2605).
  • C ABI: xl_open_source (random access through a read_at callback) and xl_open_stream
    (a forward-only stream that cannot seek), plus xl_set_source_error so a callback can report why
    it failed. xl_open_options gains source and buffering fields and still accepts the 6.0 layout
    through struct_size.
  • Bindings: Python takes a Source or any readable stream, C++ an xl::Source or
    xl::InputStream, Rust a Source or any Read. Documented in each binding's README.
  • CSV over a stream: schema inference and replay now work when the input cannot seek
    (ReplayStream).
  • Python Arrow stream: native callbacks release the GIL, so a consumer holding it no longer
    blocks other threads while a batch parses.

Managed inflate decoder

System.IO.Compression.DeflateStream is replaced at all four sites in ZipIndex by InflateStream,
a managed, resumable port of libdeflate's decoder design (MIT notice added to
THIRD-PARTY-NOTICES.md, which now ships in the NuGet package).

  • Inflate only, against DeflateStream: about 1.7x on the XLSX sheet and 1.4x on the XLSB sheet,
    after a fast-loop pass guided by the JIT disassembly (one table array instead of two, removing a
    register spill; libdeflate-style bit accounting).
  • End to end without prefetch: XLSX reads about 1.25x, XLSB about 1.14x (measured before the
    fast-loop pass; the gain with prefetch is smaller because the parse becomes the bottleneck).
  • Hardening: an always-on canary after the output window, exact bit-level truncation detection, a new
    inflate fuzz target that compares output with DeflateStream, and an oracle fix so divergences
    and canary trips are no longer swallowed by FuzzOracle.Guard.

Behavior change. DeflateStream accepts a deflate stream that ends before its final block and
returns the bytes decoded so far. A ZIP entry cut short therefore used to yield a silent prefix of
its rows. It now throws InvalidDataException. Worth a line in the release notes.

Typed parse builds columns in native memory

ColumnBuilder used to write into 32 KB managed chunks and then copy everything into the native
block it returns. It now writes into a native block that grows by doubling, and a column built in one
part hands that block over without a copy. A SafeHandle owns each block, so a builder dropped on an
error path still frees it.

  • Peak memory during to_record_batch on the 65K fixture: 26.0 → 18.1 MiB whole sheet,
    16.7 → 10.7 MiB streamed.
  • Typed parsing 3–5% faster.

Also

  • Static PGO profile regenerated twice, after each signature change, so NativeAOT keeps profile data
    for the decode loop and the column builders.
  • docs/performance/reader-performance.md: inflate measurements, and a correction of the earlier
    "the inflate floor does not move" claim.
  • Dependabot bumps (test and analyzer groups).

Checklist

  • dotnet build ExcelReader.slnx --configuration Release builds clean (warnings are errors)
  • dotnet test tests/ExcelReader.Tests/ExcelReader.Tests.csproj --configuration Release passes (2,990 tests)
  • If this changes the public API: PublicAPI.Unshipped.txt updated (no .NET public API change since v6.0.0)
  • Tests added/updated for the behavior change
  • One focused change: no, this is the release PR from develop

Test plan

  • Full .NET suite: 2,990 passed. Python suite against the republished NativeAOT library: 158 passed,
    1 pre-existing xfail.
  • Inflate: unit tests for every rejection path (crafted stored, fixed and dynamic headers, matches at
    the full 32,768-byte distance, cuts just before the window fills), differential tests against
    DeflateStream over generated shapes at every compression level and over every deflated entry in
    the test workbooks, and fuzz check with 156,780 cases and 0 failures.
  • Native buffers: GrowableNativeBufferTests, plus the existing allocation-tracking tests, which still
    pass through the copy path.
  • All performance numbers above come from an i7-1365U laptop with interleaved A/B runs, so only the
    ratios are meaningful.

Before tagging 6.1.0:

  • BenchmarkDotNet on the Ryzen 7 5700X: no row regresses, and the tiny workbook (0.198 ms) does not
    get slower (each ZIP entry now rents buffers and builds Huffman tables).
  • NativeAOT xl_parse_typed before and after.
  • A few CI fuzz cycles on the new inflate target.
  • Update benchmarks.md and the Python README figures from the Ryzen run.

GabrielMarquezMatte and others added 30 commits October 7, 2026 13:41
…-api-v6.0.0

chore: promote public API for v6.0.0
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… 6.0 options layout

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ard stream reads

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Python callbacks now catch BaseException so Ctrl-C fails the read instead of
truncating a CSV stream. C++ open_source rejects a size above INT64_MAX before
releasing the source, and the C++ tests cover destruction on failure, parallel
reads and stream errors. The smoke test pins the 88-byte 6.0 options struct.
Source error wording no longer claims 0 is valid, StreamBuffer clamps its limit
to Array.MaxLength, and the header, docstring and READMEs are tightened.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Bumps Meziantou.Analyzer from 3.0.290 to 3.0.294

---
updated-dependencies:
- dependency-name: Meziantou.Analyzer
  dependency-version: 3.0.294
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: analyzers
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps Microsoft.Testing.Extensions.CodeCoverage from 18.11.2 to 18.12.0
Bumps Microsoft.Testing.Extensions.TrxReport from 2.4.1 to 2.5.1

---
updated-dependencies:
- dependency-name: Microsoft.Testing.Extensions.CodeCoverage
  dependency-version: 18.12.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: test
- dependency-name: Microsoft.Testing.Extensions.TrxReport
  dependency-version: 2.5.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: test
...

Signed-off-by: dependabot[bot] <support@github.com>
…elop/analyzers-55e46a7a66

Bump the analyzers group with 1 update
…ts/ExcelReader.Tests/develop/test-4352e14058

Bump the test group with 2 updates
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Replaces DeflateStream at all four sites in ZipIndex. A deflate entry that ends before its final block now throws InvalidDataException; DeflateStream returned the bytes decoded so far and reported end of stream.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
GabrielMarquezMatte and others added 10 commits October 8, 2026 14:54
…oded bytes

When input had ended and the window filled while the fast loop was decoding the zero padding, the decoder reported a full window instead of truncation, so up to a few hundred invented bytes reached the caller before the exception. Also pins matches at the full 32,768-byte distance.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Both threw InvalidOperationException, which FuzzOracle sanctions, so Guard swallowed them. Divergence now throws OracleDivergenceException and the canary UnreachableException; a smoke self-check proves Guard lets a divergence through. When InflateStream rejects input, the bytes it delivered first must be a prefix of DeflateStream's output.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Keeps the litlen and offset tables in one array so the offset table is a constant displacement, which removes a register spill on every match. Tracks bitsleft as a long whose low byte alone is meaningful, subtracting whole entries and refilling with 7 - (bitsleft >> 3) as libdeflate does, and drops a redundant mask before the extra-bits shift. Inflate only, interleaved on the i7-1365U: 1.10x on the XLSX sheet, 1.07x on the XLSB sheet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t-loop change

FastLoop lost a parameter, so the previous profile no longer matched it by signature.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… without a copy

ColumnBuilder wrote every value into 32 KB managed chunks and then copied them all into the native block it returned. It now writes into a native block that doubles as it fills; a column built in one part hands that block over directly, and only the parallel CSV path, or a test tracking allocations, still copies. A SafeHandle owns each block so a builder dropped on an error path still frees it. On the 65K fixture the peak during to_record_batch falls from 26.0 to 18.1 MiB (10.7 MiB from 16.7 when streamed); typed parsing is 3-5% faster on the i7-1365U.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…mn buffers

ColumnBuilder.Append and Concat changed signature, so the previous profile no longer matched them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@codecov-commenter

codecov-commenter commented Oct 8, 2026 •

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 90.97826% with 83 lines in your changes missing coverage. Please review.
✅ Project coverage is 90.02%. Comparing base (ca5b50f) to head (4aa3766).

Files with missing lines Patch % Lines
...rc/ExcelReader.Core/Reader/Sources/SourceStream.cs 62.16% 13 Missing and 1 partial ⚠️
src/ExcelReader.Core/Reader/Csv/ReplayStream.cs 75.92% 12 Missing and 1 partial ⚠️
...celReader.Core/Reader/Zip/Inflate/InflateStream.cs 86.36% 11 Missing and 1 partial ⚠️
...c/ExcelReader.Native/Reading/CallbackReadStream.cs 74.46% 11 Missing and 1 partial ⚠️
src/ExcelReader.Native/Reading/ReadApi.Sources.cs 78.00% 8 Missing and 3 partials ⚠️
...Core/Reader/Zip/Inflate/InflateDecoder.FastLoop.cs 94.65% 2 Missing and 5 partials ⚠️
...c/ExcelReader.Native/Reading/CallbackByteSource.cs 87.09% 3 Missing and 1 partial ⚠️
src/ExcelReader.Core/Reader/Csv/CsvReader.cs 72.72% 3 Missing ⚠️
...xcelReader.Core/Reader/Sources/CachedByteSource.cs 96.15% 2 Missing ⚠️
...elReader.Core/Reader/Zip/Inflate/InflateDecoder.cs 98.75% 1 Missing and 1 partial ⚠️
... and 2 more
❗ Your organization needs to install the Codecov GitHub app to enable full functionality.
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #140      +/-   ##
==========================================
+ Coverage   90.00%   90.02%   +0.02%     
==========================================
  Files         190      204      +14     
  Lines       13963    14849     +886     
  Branches     2558     2711     +153     
==========================================
+ Hits        12567    13368     +801     
- Misses        936     1004      +68     
- Partials      460      477      +17     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@github-actions

github-actions Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

Benchmark Results

Baseline: master ca5b50f9, from the series published by benchmark-pages.yml. Both sides ran on a shared ubuntu-latest runner, so treat anything under ±10% as noise.

Moved by at least 10%

Benchmark master This PR Delta
ExcelReader.Benchmarks.ReadBenchmark.Sylvan(Rows: 50000) 39.93 ms 57.97 ms +45.2%
ExcelReader.Benchmarks.CsvReadBenchmark.Sylvan(Rows: 50000) 3.82 ms 5.40 ms +41.5%
ExcelReader.Benchmarks.ColdStartBenchmark.FluentParseFirstUse(Rows: 200) 37.08 ms 51.94 ms +40.1%
ExcelReader.Benchmarks.XlsReadBenchmark.ExcelReader(Rows: 50000) 3.53 ms 4.92 ms +39.4%
ExcelReader.Benchmarks.ColdStartBenchmark.TypedParseFirstUse(Rows: 200) 42.30 ms 58.91 ms +39.3%
ExcelReader.Benchmarks.CsvReadBenchmark.ExcelReaderAsync(Rows: 50000) 2.73 ms 3.78 ms +38.3%
ExcelReader.Benchmarks.ColdStartBenchmark.FluentParseWithAttributeFallbackFirstUse(Rows: 200) 45.64 ms 62.09 ms +36.0%
ExcelReader.Benchmarks.CsvReadBenchmark.ExcelReader(Rows: 50000) 2.71 ms 3.69 ms +36.0%
ExcelReader.Benchmarks.XlsReadBenchmark.Sylvan(Rows: 50000) 5.77 ms 7.83 ms +35.8%
ExcelReader.Benchmarks.ReadBenchmark.OfficeIMO(Rows: 50000) 130.09 ms 176.23 ms +35.5%
ExcelReader.Benchmarks.CsvReadBenchmark.Sep(Rows: 50000) 8.71 ms 11.72 ms +34.5%
ExcelReader.Benchmarks.XlsReadBenchmark.ExcelReaderAsync(Rows: 50000) 3.47 ms 4.57 ms +31.8%
ExcelReader.Benchmarks.CsvReadBenchmark.ExcelReaderWide(Rows: 50000) 9.23 ms 11.95 ms +29.4%
ExcelReader.Benchmarks.ReadBenchmark.ExcelReaderMaterialized(Rows: 50000) 9.95 ms 12.75 ms +28.1%
ExcelReader.Benchmarks.XlsReadBenchmark.OfficeIMO(Rows: 50000) 7.98 ms 10.20 ms +27.9%
ExcelReader.Benchmarks.ReadBenchmark.ExcelReaderAsync(Rows: 50000) 9.04 ms 11.44 ms +26.6%
ExcelReader.Benchmarks.ReadBenchmark.OfficeIMOXlsb(Rows: 50000) 12.72 ms 16.00 ms +25.9%
ExcelReader.Benchmarks.ReadBenchmark.ExcelReader(Rows: 50000) 8.61 ms 10.76 ms +25.0%
ExcelReader.Benchmarks.ColdStartBenchmark.RecordWriteFirstUse(Rows: 200) 22.45 ms 25.22 ms +12.4%
ExcelReader.Benchmarks.XlsxSharedStringHotPathBenchmark.IndexParse_Utf8Parser(Rows: 65536) 3.06 ms 2.74 ms -10.3%
ExcelReader.Benchmarks.RealDataReadBenchmark.Xlsm_ExcelReader_Materialized 62.47 ms 55.97 ms -10.4%
ExcelReader.Benchmarks.RealDataReadBenchmark.Xlsb_ExcelReader 29.31 ms 26.17 ms -10.7%
ExcelReader.Benchmarks.StringHeavyReadBenchmark.Xlsb_Sylvan(Rows: 65536) 98.14 ms 87.56 ms -10.8%
ExcelReader.Benchmarks.RealDataReadBenchmark.Xlsx_ExcelReader 59.51 ms 52.33 ms -12.1%
ExcelReader.Benchmarks.RealDataReadBenchmark.Xlsx_ExcelReader_Memory 60.29 ms 52.97 ms -12.1%
ExcelReader.Benchmarks.RealDataTypedParseBenchmark.Xlsb_ExcelParser 39.60 ms 34.75 ms -12.3%
ExcelReader.Benchmarks.RealDataReadBenchmark.Xlsm_ExcelReader 59.65 ms 52.33 ms -12.3%
ExcelReader.Benchmarks.RealDataReadBenchmark.Xlsb_ExcelReader_Memory_Prefetch 17.29 ms 15.14 ms -12.4%
ExcelReader.Benchmarks.NativeTypedParseBenchmark.ParseTyped 53.00 ms 46.30 ms -12.6%
ExcelReader.Benchmarks.ChunkedParseBenchmark.Batched_10k(Rows: 50000) 13.43 ms 11.70 ms -12.9%
ExcelReader.Benchmarks.RealDataReadBenchmark.Xlsb_ExcelReader_Prefetch 17.70 ms 15.40 ms -13.0%
ExcelReader.Benchmarks.NativeTypedParseBenchmark.ParseArrow 50.74 ms 43.13 ms -15.0%
ExcelReader.Benchmarks.StringHeavyReadBenchmark.Xlsx_ExcelReader_Materialized(Rows: 65536) 94.04 ms 79.66 ms -15.3%
ExcelReader.Benchmarks.StringHeavyReadBenchmark.Xlsb_ExcelReader_Materialized(Rows: 65536) 80.87 ms 68.00 ms -15.9%
ExcelReader.Benchmarks.StringHeavyReadBenchmark.Xlsx_ExcelReader_Materialized_Interned(Rows: 65536) 94.67 ms 79.58 ms -15.9%
ExcelReader.Benchmarks.XlsxSharedStringHotPathBenchmark.Stored_EndToEnd(Rows: 65536) 28.56 ms 23.80 ms -16.7%
ExcelReader.Benchmarks.XlsxSharedStringHotPathBenchmark.Stored_SharedStringPrologue(Rows: 65536) 6.32 ms 4.94 ms -21.8%
ExcelReader.Benchmarks.ArrowConversionBenchmark.XlsbTyped(Rows: 100000) 21.64 ms 16.21 ms -25.1%
ExcelReader.Benchmarks.ArrowConversionBenchmark.CsvAllString(Rows: 100000) 29.10 ms 21.67 ms -25.5%
ExcelReader.Benchmarks.XlsxSharedStringHotPathBenchmark.IndexParse_DigitLoop(Rows: 65536) 2.23 ms 1.63 ms -26.8%
ExcelReader.Benchmarks.ArrowConversionBenchmark.CsvTyped(Rows: 100000) 16.00 ms 11.60 ms -27.5%
ExcelReader.Benchmarks.ArrowConversionBenchmark.CsvTypedWithInference(Rows: 100000) 16.84 ms 11.98 ms -28.9%
ExcelReader.Benchmarks.DataReaderBenchmark.DataReader_TypedGetters(Rows: 50000) 14.16 ms 10.05 ms -29.0%
ExcelReader.Benchmarks.DataReaderBenchmark.DataReader_GetValue(Rows: 50000) 15.08 ms 10.61 ms -29.7%
ExcelReader.Benchmarks.DataReaderBenchmark.DataTable_Load(Rows: 50000) 76.83 ms 53.49 ms -30.4%
ExcelReader.Benchmarks.DataReaderBenchmark.DataReader_GetBytes(Rows: 50000) 11.16 ms 7.74 ms -30.7%
ExcelReader.Benchmarks.DataReaderBenchmark.Baseline_RawRows(Rows: 50000) 11.20 ms 7.67 ms -31.5%
ExcelReader.Benchmarks.StringHeavyReadBenchmark.Xlsx_ExcelReader_Prefetch(Rows: 65536) 48.97 ms 33.04 ms -32.5%
ExcelReader.Benchmarks.XlsxSharedStringHotPathBenchmark.EndToEnd_Prefetch(Rows: 65536) 50.63 ms 33.32 ms -34.2%
ExcelReader.Benchmarks.StringHeavyReadBenchmark.Xlsb_ExcelReader(Rows: 65536) 58.46 ms 37.99 ms -35.0%
ExcelReader.Benchmarks.StringHeavyReadBenchmark.Xlsb_ExcelReader_Memory(Rows: 65536) 57.64 ms 36.66 ms -36.4%
ExcelReader.Benchmarks.XlsxSharedStringHotPathBenchmark.EndToEnd(Rows: 65536) 66.53 ms 42.13 ms -36.7%
ExcelReader.Benchmarks.StringHeavyReadBenchmark.Xlsx_ExcelReader(Rows: 65536) 66.97 ms 42.30 ms -36.8%
ExcelReader.Benchmarks.StringHeavyReadBenchmark.Xlsb_ExcelReader_Prefetch(Rows: 65536) 47.66 ms 26.33 ms -44.8%
ExcelReader.Benchmarks.XlsxSharedStringHotPathBenchmark.SharedStringPrologue(Rows: 65536) 25.09 ms 13.22 ms -47.3%

104 within ±10%, 38 with no baseline entry (new, renamed, or reparameterized).

Full results per group

ExcelReader.Benchmarks.ArrowConversionBenchmark


BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.5 LTS (Noble Numbat)
INTEL XEON PLATINUM 8573C 2.30GHz, 1 CPU, 4 logical and 2 physical cores
.NET SDK 10.0.401
  [Host]     : .NET 10.0.12 (10.0.12, 10.0.1226.42308), X64 RyuJIT x86-64-v4
  Job-MEHJPP : .NET 10.0.12 (10.0.12, 10.0.1226.42308), X64 RyuJIT x86-64-v4

IterationCount=5  WarmupCount=1  

Method Rows Mean Error StdDev Ratio RatioSD Gen0 Gen1 Gen2 Allocated Alloc Ratio
CsvAllString 100000 21.67 ms 0.924 ms 0.240 ms 1.00 0.01 531.2500 531.2500 531.2500 16.27 MB 1.00
CsvTyped 100000 11.60 ms 1.334 ms 0.347 ms 0.54 0.02 453.1250 453.1250 453.1250 8.13 MB 0.50
XlsbTyped 100000 16.21 ms 1.404 ms 0.365 ms 0.75 0.02 375.0000 375.0000 375.0000 8.14 MB 0.50
CsvTypedWithInference 100000 11.98 ms 1.621 ms 0.421 ms 0.55 0.02 578.1250 578.1250 578.1250 14.89 MB 0.92

ExcelReader.Benchmarks.ChunkedParseBenchmark


BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.5 LTS (Noble Numbat)
AMD EPYC 7763 2.45GHz, 1 CPU, 4 logical and 2 physical cores
.NET SDK 10.0.401
  [Host]     : .NET 10.0.12 (10.0.12, 10.0.1226.42308), X64 RyuJIT x86-64-v3
  Job-MEHJPP : .NET 10.0.12 (10.0.12, 10.0.1226.42308), X64 RyuJIT x86-64-v3

IterationCount=5  WarmupCount=1  

Method Rows Mean Error StdDev Ratio RatioSD Allocated Alloc Ratio
WholeSheet 50000 12.56 ms 1.923 ms 0.499 ms 1.00 0.05 9.81 KB 1.00
Batched_10k 50000 11.70 ms 0.095 ms 0.025 ms 0.93 0.03 16.75 KB 1.71
Batched_1k 50000 12.21 ms 0.097 ms 0.015 ms 0.97 0.04 81.09 KB 8.27

ExcelReader.Benchmarks.ColdStartBenchmark


BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.5 LTS (Noble Numbat)
AMD EPYC 7763 2.45GHz, 1 CPU, 4 logical and 2 physical cores
.NET SDK 10.0.401
  [Host]     : .NET 10.0.12 (10.0.12, 10.0.1226.42308), X64 RyuJIT x86-64-v3
  Job-GOEFXF : .NET 10.0.12 (10.0.12, 10.0.1226.42308), X64 RyuJIT x86-64-v3

InvocationCount=1  IterationCount=1  LaunchCount=16  
RunStrategy=ColdStart  UnrollFactor=1  WarmupCount=0  

Method Rows Mean Error StdDev Allocated
TypedParseFirstUse 200 58.91 ms 2.244 ms 2.204 ms 20.78 KB
RecordWriteFirstUse 200 25.22 ms 0.443 ms 0.435 ms 84.25 KB
FluentParseFirstUse 200 51.94 ms 0.539 ms 0.529 ms 23.3 KB
FluentParseWithAttributeFallbackFirstUse 200 62.09 ms 2.039 ms 2.003 ms 25 KB

ExcelReader.Benchmarks.CsvParallelParseBenchmark


BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.5 LTS (Noble Numbat)
AMD EPYC 7763 2.45GHz, 1 CPU, 4 logical and 2 physical cores
.NET SDK 10.0.401
  [Host]     : .NET 10.0.12 (10.0.12, 10.0.1226.42308), X64 RyuJIT x86-64-v3
  Job-MEHJPP : .NET 10.0.12 (10.0.12, 10.0.1226.42308), X64 RyuJIT x86-64-v3

IterationCount=5  WarmupCount=1  

Method Dop Mean Error StdDev Ratio RatioSD Gen0 Gen1 Allocated Alloc Ratio
ConversionHeavy 1 1,497.7 ms 200.79 ms 52.14 ms 1.00 0.04 42000.0000 - 671.38 MB 1.000
NarrowInt 1 814.4 ms 222.90 ms 34.49 ms 0.54 0.03 15000.0000 - 245.7 MB 0.366
ConversionHeavyAggregate 1 1,175.7 ms 134.41 ms 34.91 ms 0.79 0.03 - - 1.17 MB 0.002
NarrowIntAggregate 1 748.4 ms 189.16 ms 49.12 ms 0.50 0.03 - - 1.22 MB 0.002
ConversionHeavy 2 1,166.2 ms 84.33 ms 21.90 ms 1.00 0.02 42000.0000 27000.0000 678.74 MB 1.000
NarrowInt 2 729.3 ms 35.44 ms 9.20 ms 0.63 0.01 15000.0000 2000.0000 253.17 MB 0.373
ConversionHeavyAggregate 2 823.4 ms 70.30 ms 18.26 ms 0.71 0.02 - - 1.27 MB 0.002
NarrowIntAggregate 2 527.8 ms 41.72 ms 6.46 ms 0.45 0.01 - - 1.25 MB 0.002
ConversionHeavy 4 740.2 ms 22.70 ms 3.51 ms 1.00 0.01 42000.0000 38000.0000 678.87 MB 1.000
NarrowInt 4 483.0 ms 30.76 ms 7.99 ms 0.65 0.01 15000.0000 1000.0000 253.32 MB 0.373
ConversionHeavyAggregate 4 506.3 ms 38.61 ms 5.98 ms 0.68 0.01 - - 1.27 MB 0.002
NarrowIntAggregate 4 326.4 ms 46.35 ms 12.04 ms 0.44 0.02 - - 1.27 MB 0.002
ConversionHeavy 8 788.1 ms 64.83 ms 16.84 ms 1.00 0.03 42000.0000 17000.0000 678.97 MB 1.000
NarrowInt 8 482.8 ms 46.46 ms 12.07 ms 0.61 0.02 15000.0000 1000.0000 253.28 MB 0.373
ConversionHeavyAggregate 8 503.5 ms 26.80 ms 6.96 ms 0.64 0.02 - - 1.29 MB 0.002
NarrowIntAggregate 8 327.1 ms 72.17 ms 18.74 ms 0.42 0.02 - - 1.29 MB 0.002
ConversionHeavy 16 763.3 ms 78.49 ms 20.38 ms 1.00 0.03 42000.0000 1000.0000 679.3 MB 1.000
NarrowInt 16 480.2 ms 7.62 ms 1.18 ms 0.63 0.02 15000.0000 1000.0000 254.14 MB 0.374
ConversionHeavyAggregate 16 541.9 ms 49.03 ms 12.73 ms 0.71 0.02 - - 1.33 MB 0.002
NarrowIntAggregate 16 320.2 ms 32.79 ms 5.07 ms 0.42 0.01 - - 1.33 MB 0.002

ExcelReader.Benchmarks.CsvParallelVsSepBenchmark


BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.5 LTS (Noble Numbat)
AMD EPYC 7763 2.45GHz, 1 CPU, 4 logical and 2 physical cores
.NET SDK 10.0.401
  [Host]     : .NET 10.0.12 (10.0.12, 10.0.1226.42308), X64 RyuJIT x86-64-v3
  Job-MEHJPP : .NET 10.0.12 (10.0.12, 10.0.1226.42308), X64 RyuJIT x86-64-v3

IterationCount=5  WarmupCount=1  

Method Corpus Mean Error StdDev Ratio RatioSD Gen0 Gen1 Gen2 Allocated Alloc Ratio
ExcelReader_Sequential NarrowInt 712.4 ms 13.32 ms 2.06 ms 1.00 0.00 15000.0000 - - 244.15 MB 1.00
ExcelReader_Parallel NarrowInt 481.8 ms 78.60 ms 20.41 ms 0.68 0.03 15000.0000 1000.0000 - 253.32 MB 1.04
Sep_Sequential NarrowInt 595.5 ms 4.23 ms 1.10 ms 0.84 0.00 15000.0000 - - 244.15 MB 1.00
Sep_Parallel NarrowInt 467.7 ms 131.89 ms 20.41 ms 0.66 0.03 17000.0000 13000.0000 1000.0000 256.08 MB 1.05
ExcelReader_Sequential ConversionHeavy 941.8 ms 11.84 ms 3.07 ms 1.00 0.00 29000.0000 - - 467.31 MB 1.00
ExcelReader_Parallel ConversionHeavy 522.4 ms 21.99 ms 5.71 ms 0.55 0.01 29000.0000 25000.0000 - 473.71 MB 1.01
Sep_Sequential ConversionHeavy 1,149.4 ms 31.27 ms 8.12 ms 1.22 0.01 29000.0000 - - 467.31 MB 1.00
Sep_Parallel ConversionHeavy 834.5 ms 80.70 ms 20.96 ms 0.89 0.02 33000.0000 31000.0000 4000.0000 475.64 MB 1.02

ExcelReader.Benchmarks.CsvParseBenchmark


BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.5 LTS (Noble Numbat)
AMD EPYC 7763 2.45GHz, 1 CPU, 4 logical and 2 physical cores
.NET SDK 10.0.401
  [Host]     : .NET 10.0.12 (10.0.12, 10.0.1226.42308), X64 RyuJIT x86-64-v3
  Job-MEHJPP : .NET 10.0.12 (10.0.12, 10.0.1226.42308), X64 RyuJIT x86-64-v3

IterationCount=5  WarmupCount=1  

Method Rows Mean Error StdDev Ratio Gen0 Gen1 Allocated Alloc Ratio
ExcelParserSync 50000 6.911 ms 0.0580 ms 0.0090 ms 1.00 242.1875 - 3.86 MB 1.00
ExcelParserAsync 50000 7.326 ms 0.0569 ms 0.0088 ms 1.06 242.1875 - 3.86 MB 1.00
Sep 50000 14.716 ms 0.0474 ms 0.0123 ms 2.13 234.3750 - 3.87 MB 1.00
Sylvan 50000 19.857 ms 0.4282 ms 0.0663 ms 2.87 656.2500 62.5000 10.95 MB 2.84

ExcelReader.Benchmarks.CsvReadBenchmark


BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.5 LTS (Noble Numbat)
Intel Xeon Platinum 8370C CPU 2.80GHz (Max: 3.39GHz), 1 CPU, 4 logical and 2 physical cores
.NET SDK 10.0.401
  [Host]     : .NET 10.0.12 (10.0.12, 10.0.1226.42308), X64 RyuJIT x86-64-v4
  Job-MEHJPP : .NET 10.0.12 (10.0.12, 10.0.1226.42308), X64 RyuJIT x86-64-v4

IterationCount=5  WarmupCount=1  

Method Rows Mean Error StdDev Ratio RatioSD Allocated Alloc Ratio
ExcelReader 50000 3.688 ms 0.0674 ms 0.0104 ms 1.00 0.00 840 B 1.00
ExcelReaderWide 50000 11.948 ms 0.1370 ms 0.0356 ms 3.24 0.01 840 B 1.00
ExcelReaderAsync 50000 3.777 ms 0.0208 ms 0.0054 ms 1.02 0.00 912 B 1.09
Sep 50000 11.718 ms 0.3207 ms 0.0833 ms 3.18 0.02 4024 B 4.79
Sylvan 50000 5.402 ms 0.0243 ms 0.0038 ms 1.46 0.00 38682 B 46.05

ExcelReader.Benchmarks.CsvWriteBenchmark


BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.5 LTS (Noble Numbat)
AMD EPYC 7763 2.45GHz, 1 CPU, 4 logical and 2 physical cores
.NET SDK 10.0.401
  [Host]     : .NET 10.0.12 (10.0.12, 10.0.1226.42308), X64 RyuJIT x86-64-v3
  Job-MEHJPP : .NET 10.0.12 (10.0.12, 10.0.1226.42308), X64 RyuJIT x86-64-v3

IterationCount=5  WarmupCount=1  

Method Rows Mean Error StdDev Ratio RatioSD Gen0 Gen1 Gen2 Allocated Alloc Ratio
ExcelReaderWriter 50000 6.507 ms 0.1422 ms 0.0369 ms 1.00 0.01 500.0000 500.0000 500.0000 4 MB 1.00
Sep 50000 10.022 ms 0.2595 ms 0.0402 ms 1.54 0.01 500.0000 500.0000 500.0000 4.01 MB 1.00
SylvanWriter 50000 10.574 ms 0.4782 ms 0.1242 ms 1.63 0.02 500.0000 500.0000 500.0000 4.04 MB 1.01

ExcelReader.Benchmarks.DataReaderBenchmark


BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.5 LTS (Noble Numbat)
INTEL XEON PLATINUM 8573C 2.30GHz, 1 CPU, 4 logical and 2 physical cores
.NET SDK 10.0.401
  [Host]     : .NET 10.0.12 (10.0.12, 10.0.1226.42308), X64 RyuJIT x86-64-v4
  Job-MEHJPP : .NET 10.0.12 (10.0.12, 10.0.1226.42308), X64 RyuJIT x86-64-v4

IterationCount=5  WarmupCount=1  

Method Rows Mean Error StdDev Ratio RatioSD Gen0 Gen1 Gen2 Allocated Alloc Ratio
Baseline_RawRows 50000 7.673 ms 0.4784 ms 0.1242 ms 1.00 0.02 - - - 3.55 KB 1.00
DataReader_GetValue 50000 10.607 ms 0.3628 ms 0.0561 ms 1.38 0.02 62.5000 - - 5131.2 KB 1,443.50
DataReader_TypedGetters 50000 10.053 ms 0.6758 ms 0.1755 ms 1.31 0.03 15.6250 - - 1615.57 KB 454.49
DataReader_GetBytes 50000 7.736 ms 0.2271 ms 0.0590 ms 1.01 0.02 - - - 4.24 KB 1.19
DataTable_Load 50000 53.487 ms 4.0802 ms 0.6314 ms 6.97 0.13 1000.0000 900.0000 800.0000 23392.94 KB 6,580.87

ExcelReader.Benchmarks.EncryptedWorkbookBenchmark


BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.5 LTS (Noble Numbat)
AMD EPYC 7763 2.76GHz, 1 CPU, 4 logical and 2 physical cores
.NET SDK 10.0.401
  [Host]     : .NET 10.0.12 (10.0.12, 10.0.1226.42308), X64 RyuJIT x86-64-v3
  Job-MEHJPP : .NET 10.0.12 (10.0.12, 10.0.1226.42308), X64 RyuJIT x86-64-v3

IterationCount=5  WarmupCount=1  

Method Mean Error StdDev Ratio RatioSD Gen0 Allocated Alloc Ratio
Plain_Stream 58.43 μs 4.238 μs 0.656 μs 1.00 0.01 0.4883 8.75 KB 1.00
Encrypted_Stream 58,925.31 μs 801.192 μs 208.067 μs 1,008.52 10.47 - 37.82 KB 4.32
Encrypted_Stream_VerifyIntegrity 59,731.79 μs 2,661.412 μs 691.160 μs 1,022.32 14.82 - 39.76 KB 4.54
Encrypted_Memory 59,323.28 μs 750.733 μs 194.963 μs 1,015.33 10.47 - 52.74 KB 6.03
Encrypted_OpenOnly 60,086.00 μs 451.963 μs 117.373 μs 1,028.38 10.31 - 32.25 KB 3.69
Large_Plain_Stream 58,464.01 μs 1,555.214 μs 403.884 μs 1,000.62 11.73 - 3.55 KB 0.41
Large_Encrypted_Stream 120,260.00 μs 367.343 μs 56.847 μs 2,058.27 20.46 - 29.31 KB 3.35
Large_Encrypted_OpenOnly 60,353.90 μs 651.005 μs 169.064 μs 1,032.97 10.53 - 28.72 KB 3.28

ExcelReader.Benchmarks.InflateBenchmark


BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.5 LTS (Noble Numbat)
Intel Xeon Platinum 8370C CPU 2.80GHz (Max: 3.39GHz), 1 CPU, 4 logical and 2 physical cores
.NET SDK 10.0.401
  [Host]     : .NET 10.0.12 (10.0.12, 10.0.1226.42308), X64 RyuJIT x86-64-v4
  Job-MEHJPP : .NET 10.0.12 (10.0.12, 10.0.1226.42308), X64 RyuJIT x86-64-v4

IterationCount=5  WarmupCount=1  

Method Categories Mean Error StdDev Ratio Allocated Alloc Ratio
SharedStrings_DeflateStream SharedStrings 15.71 ms 0.217 ms 0.034 ms 1.00 280 B 1.00
SharedStrings_InflateStream SharedStrings 10.04 ms 0.081 ms 0.012 ms 0.64 200 B 0.71
XlsbSheet_DeflateStream XlsbSheet 18.40 ms 0.112 ms 0.029 ms 1.00 280 B 1.00
XlsbSheet_InflateStream XlsbSheet 15.45 ms 0.056 ms 0.009 ms 0.84 200 B 0.71
XlsxSheet_DeflateStream XlsxSheet 33.50 ms 0.067 ms 0.017 ms 1.00 280 B 1.00
XlsxSheet_InflateStream XlsxSheet 24.31 ms 0.077 ms 0.020 ms 0.73 200 B 0.71

ExcelReader.Benchmarks.NativeOpenBenchmark


BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.5 LTS (Noble Numbat)
AMD EPYC 7763 2.45GHz, 1 CPU, 4 logical and 2 physical cores
.NET SDK 10.0.401
  [Host]     : .NET 10.0.12 (10.0.12, 10.0.1226.42308), X64 RyuJIT x86-64-v3
  Job-MEHJPP : .NET 10.0.12 (10.0.12, 10.0.1226.42308), X64 RyuJIT x86-64-v3

IterationCount=5  WarmupCount=1  

Method Format ReadRows Mean Error StdDev Ratio RatioSD Gen0 Gen1 Gen2 Allocated Alloc Ratio
OpenMemory csv False 1,270,393.0 ns 86,983.41 ns 22,589.32 ns 1.000 0.02 398.4375 398.4375 398.4375 8171734 B 1.000
OpenFile csv False 8,100.8 ns 363.04 ns 94.28 ns 0.006 0.00 0.0458 - - 976 B 0.000
OpenSource csv False 208.9 ns 9.18 ns 2.38 ns 0.000 0.00 0.0372 - - 624 B 0.000
OpenStream csv False 191.1 ns 4.16 ns 0.64 ns 0.000 0.00 0.0334 - - 560 B 0.000
OpenMemory csv True 16,249,929.7 ns 860,810.46 ns 223,549.74 ns 1.00 0.02 375.0000 375.0000 375.0000 8176271 B 1.000
OpenFile csv True 15,479,351.8 ns 669,435.98 ns 173,850.40 ns 0.95 0.02 - - - 5620 B 0.001
OpenSource csv True 16,626,589.4 ns 329,350.54 ns 50,967.36 ns 1.02 0.01 406.2500 406.2500 406.2500 8181200 B 1.001
OpenStream csv True 17,644,402.5 ns 117,117.10 ns 18,124.00 ns 1.09 0.01 500.0000 500.0000 500.0000 16717660 B 2.045
OpenMemory xls False 1,523,972.4 ns 69,457.94 ns 18,038.01 ns 1.00 0.02 332.0313 332.0313 332.0313 11834486 B 1.000
OpenFile xls False 229,761.7 ns 6,061.87 ns 938.08 ns 0.15 0.00 0.4883 - - 14480 B 0.001
OpenSource xls False 1,175,795.4 ns 129,626.48 ns 33,663.59 ns 0.77 0.02 396.4844 396.4844 396.4844 7646929 B 0.646
OpenStream xls False 2,309,531.4 ns 134,066.10 ns 20,746.88 ns 1.52 0.02 335.9375 335.9375 335.9375 27563448 B 2.329
OpenMemory xls True 37,520,355.7 ns 130,638.64 ns 33,926.44 ns 1.00 0.00 285.7143 285.7143 285.7143 11841153 B 1.000
OpenFile xls True 36,607,018.1 ns 96,187.46 ns 24,979.58 ns 0.98 0.00 - - - 21240 B 0.002
OpenSource xls True 39,630,489.2 ns 399,183.51 ns 61,774.09 ns 1.06 0.00 384.6154 384.6154 384.6154 11854453 B 1.001
OpenStream xls True 39,043,315.8 ns 684,384.70 ns 177,732.53 ns 1.04 0.00 461.5385 461.5385 461.5385 27570997 B 2.328
OpenMemory xlsb False 493,762.1 ns 31,083.72 ns 8,072.34 ns 1.00 0.02 333.0078 333.0078 333.0078 3882551 B 1.000
OpenFile xlsb False 66,070.5 ns 5,779.44 ns 894.37 ns 0.13 0.00 0.2441 - - 5144 B 0.001
OpenSource xlsb False 487,566.1 ns 136,368.78 ns 35,414.54 ns 0.99 0.07 333.0078 333.0078 333.0078 3881639 B 1.000
OpenStream xlsb False 1,675,033.7 ns 135,922.82 ns 35,298.72 ns 3.39 0.08 361.3281 361.3281 361.3281 11223552 B 2.891
OpenMemory xlsb True 53,327,365.0 ns 694,159.37 ns 107,421.93 ns 1.00 0.00 300.0000 300.0000 300.0000 3889086 B 1.000
OpenFile xlsb True 51,590,346.0 ns 759,197.13 ns 117,486.60 ns 0.97 0.00 - - - 11774 B 0.003
OpenSource xlsb True 52,256,608.4 ns 1,275,937.56 ns 331,356.93 ns 0.98 0.01 300.0000 300.0000 300.0000 3890102 B 1.000
OpenStream xlsb True 55,777,588.1 ns 517,450.99 ns 80,076.11 ns 1.05 0.00 600.0000 600.0000 600.0000 11230784 B 2.888
OpenMemory xlsx False 902,548.4 ns 357,951.28 ns 92,958.81 ns 1.01 0.13 333.0078 333.0078 333.0078 6725383 B 1.000
OpenFile xlsx False 57,181.7 ns 1,712.16 ns 264.96 ns 0.06 0.01 0.1221 - - 4008 B 0.001
OpenSource xlsx False 1,224,769.5 ns 32,675.88 ns 5,056.63 ns 1.37 0.13 427.7344 427.7344 427.7344 6726692 B 1.000
OpenStream xlsx False 1,827,635.9 ns 177,748.97 ns 46,160.84 ns 2.04 0.20 398.4375 398.4375 398.4375 14065810 B 2.091
OpenMemory xlsx True 70,219,577.0 ns 114,758.28 ns 17,758.97 ns 1.00 0.00 250.0000 250.0000 250.0000 6733346 B 1.000
OpenFile xlsx True 70,467,349.4 ns 682,284.16 ns 105,584.23 ns 1.00 0.00 - - - 12236 B 0.002
OpenSource xlsx True 70,163,185.7 ns 362,789.01 ns 94,215.15 ns 1.00 0.00 250.0000 250.0000 250.0000 6737994 B 1.001
OpenStream xlsx True 72,466,058.6 ns 1,452,960.44 ns 377,329.21 ns 1.03 0.00 285.7143 285.7143 285.7143 14073713 B 2.090

ExcelReader.Benchmarks.NativeRowReadBenchmark


BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.5 LTS (Noble Numbat)
AMD EPYC 7763 2.45GHz, 1 CPU, 4 logical and 2 physical cores
.NET SDK 10.0.401
  [Host]     : .NET 10.0.12 (10.0.12, 10.0.1226.42308), X64 RyuJIT x86-64-v3
  Job-MEHJPP : .NET 10.0.12 (10.0.12, 10.0.1226.42308), X64 RyuJIT x86-64-v3

IterationCount=5  WarmupCount=1  

Method Mean Error StdDev Ratio Gen0 Gen1 Gen2 Allocated Alloc Ratio
NextRowBlob 51.04 ms 1.676 ms 0.435 ms 1.00 300.0000 300.0000 300.0000 3.71 MB 1.00
NextRowDecoded 56.94 ms 0.839 ms 0.130 ms 1.12 222.2222 222.2222 222.2222 3.71 MB 1.00
ReadAllBlob 55.63 ms 1.660 ms 0.431 ms 1.09 1000.0000 888.8889 - 21.06 MB 5.68
ReadAllDecoded 78.13 ms 1.880 ms 0.291 ms 1.53 571.4286 571.4286 571.4286 5.71 MB 1.54

ExcelReader.Benchmarks.NativeTypedParseBenchmark


BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.5 LTS (Noble Numbat)
AMD EPYC 7763 2.45GHz, 1 CPU, 4 logical and 2 physical cores
.NET SDK 10.0.401
  [Host]     : .NET 10.0.12 (10.0.12, 10.0.1226.42308), X64 RyuJIT x86-64-v3
  Job-MEHJPP : .NET 10.0.12 (10.0.12, 10.0.1226.42308), X64 RyuJIT x86-64-v3

IterationCount=5  WarmupCount=1  

Method Mean Error StdDev Ratio RatioSD Gen0 Gen1 Gen2 Allocated Alloc Ratio
ParseTyped 46.30 ms 0.401 ms 0.104 ms 1.00 0.00 272.7273 272.7273 272.7273 3.71 MB 1.00
ParseArrow 43.13 ms 3.851 ms 1.000 ms 0.93 0.02 250.0000 250.0000 250.0000 3.72 MB 1.00

ExcelReader.Benchmarks.ParseBenchmark


BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.5 LTS (Noble Numbat)
AMD EPYC 7763 2.45GHz, 1 CPU, 4 logical and 2 physical cores
.NET SDK 10.0.401
  [Host]     : .NET 10.0.12 (10.0.12, 10.0.1226.42308), X64 RyuJIT x86-64-v3
  Job-MEHJPP : .NET 10.0.12 (10.0.12, 10.0.1226.42308), X64 RyuJIT x86-64-v3

IterationCount=5  WarmupCount=1  

Method Rows Mean Error StdDev Ratio RatioSD Gen0 Allocated Alloc Ratio
ExcelParserSync 50000 16.05 ms 0.279 ms 0.073 ms 1.00 0.01 218.7500 3959.13 KB 1.000
ExcelParserSyncSharedStrings 50000 15.01 ms 0.113 ms 0.029 ms 0.94 0.00 140.6250 2348.98 KB 0.593
ExcelParserStructSync 50000 15.12 ms 0.118 ms 0.018 ms 0.94 0.00 93.7500 1615.38 KB 0.408
RefStructModelSync 50000 13.55 ms 0.078 ms 0.012 ms 0.84 0.00 - 4.05 KB 0.001
ExcelParserAsync 50000 17.31 ms 0.033 ms 0.005 ms 1.08 0.00 218.7500 3959.23 KB 1.000
ExcelParserXlsbSync 50000 11.05 ms 0.135 ms 0.035 ms 0.69 0.00 234.3750 3959.36 KB 1.000
ExcelParserXlsbAsync 50000 11.89 ms 0.229 ms 0.059 ms 0.74 0.00 234.3750 3959.47 KB 1.000
OfficeIMO 50000 158.19 ms 13.278 ms 2.055 ms 9.86 0.12 - 5834.04 KB 1.474
Sylvan 50000 89.64 ms 2.070 ms 0.320 ms 5.59 0.03 - 10726.71 KB 2.709
SylvanAsync 50000 91.27 ms 3.466 ms 0.900 ms 5.69 0.06 - 10727.74 KB 2.710

ExcelReader.Benchmarks.ReadBenchmark


BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.5 LTS (Noble Numbat)
Intel Xeon Platinum 8370C CPU 2.80GHz (Max: 3.39GHz), 1 CPU, 4 logical and 2 physical cores
.NET SDK 10.0.401
  [Host]     : .NET 10.0.12 (10.0.12, 10.0.1226.42308), X64 RyuJIT x86-64-v4
  Job-MEHJPP : .NET 10.0.12 (10.0.12, 10.0.1226.42308), X64 RyuJIT x86-64-v4

IterationCount=5  WarmupCount=1  

Method Rows Mean Error StdDev Ratio RatioSD Gen0 Allocated Alloc Ratio
ExcelReader 50000 10.761 ms 0.1432 ms 0.0372 ms 1.00 0.00 - 3.51 KB 1.00
ExcelReaderAsync 50000 11.441 ms 0.0552 ms 0.0143 ms 1.06 0.00 - 3.58 KB 1.02
ExcelReaderXlsb 50000 6.250 ms 0.0154 ms 0.0024 ms 0.58 0.00 - 3.74 KB 1.07
ExcelReaderXlsbAsync 50000 6.320 ms 0.0183 ms 0.0048 ms 0.59 0.00 - 3.81 KB 1.09
ExcelReaderMaterialized 50000 12.748 ms 0.0466 ms 0.0121 ms 1.18 0.00 62.5000 1614.84 KB 460.35
Sylvan 50000 57.968 ms 1.0896 ms 0.1686 ms 5.39 0.02 - 1939.18 KB 552.82
OfficeIMO 50000 176.228 ms 87.8192 ms 13.5901 ms 16.38 1.12 - 7003.67 KB 1,996.59
OfficeIMOXlsb 50000 16.003 ms 0.2609 ms 0.0404 ms 1.49 0.01 250.0000 6858.38 KB 1,955.17

ExcelReader.Benchmarks.RealDataReadBenchmark


BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.5 LTS (Noble Numbat)
AMD EPYC 9V74 2.60GHz, 1 CPU, 4 logical and 2 physical cores
.NET SDK 10.0.401
  [Host]     : .NET 10.0.12 (10.0.12, 10.0.1226.42308), X64 RyuJIT x86-64-v4
  Job-MEHJPP : .NET 10.0.12 (10.0.12, 10.0.1226.42308), X64 RyuJIT x86-64-v4

IterationCount=5  WarmupCount=1  

Method Mean Error StdDev Ratio RatioSD Gen0 Allocated Alloc Ratio
Xlsx_ExcelReader 52.332 ms 0.8652 ms 0.1339 ms 1.00 0.00 - 7408 B 1.00
Xlsx_Sylvan 230.347 ms 0.9381 ms 0.1452 ms 4.40 0.01 - 659688 B 89.05
Xlsx_ExcelReader_Materialized 56.719 ms 0.2279 ms 0.0592 ms 1.08 0.00 - 17107 B 2.31
Xlsx_ExcelReader_Prefetch 37.274 ms 9.3308 ms 2.4232 ms 0.71 0.04 - 23872 B 3.22
Xlsx_ExcelReader_Memory 52.971 ms 2.1755 ms 0.5650 ms 1.01 0.01 - 7152 B 0.97
Xlsx_ExcelReader_Memory_Prefetch 35.398 ms 7.2521 ms 1.8833 ms 0.68 0.03 - 23724 B 3.20
Xlsm_ExcelReader 52.326 ms 0.1776 ms 0.0275 ms 1.00 0.00 - 7408 B 1.00
Xlsm_Sylvan 230.082 ms 2.4235 ms 0.3750 ms 4.40 0.01 - 659528 B 89.03
Xlsm_ExcelReader_Materialized 55.968 ms 0.5330 ms 0.0825 ms 1.07 0.00 - 17104 B 2.31
Xlsm_ExcelReader_Prefetch 34.954 ms 8.3362 ms 2.1649 ms 0.67 0.04 - 23808 B 3.21
Xlsm_ExcelReader_Memory 53.675 ms 0.1770 ms 0.0460 ms 1.03 0.00 - 7152 B 0.97
Xlsm_ExcelReader_Memory_Prefetch 34.660 ms 6.1922 ms 0.9582 ms 0.66 0.02 - 23552 B 3.18
Xlsb_ExcelReader 26.172 ms 0.0774 ms 0.0120 ms 0.50 0.00 - 6952 B 0.94
Xlsb_Sylvan 35.215 ms 0.1786 ms 0.0464 ms 0.67 0.00 - 346670 B 46.80
Xlsb_ExcelReader_Materialized 29.219 ms 0.4220 ms 0.0653 ms 0.56 0.00 - 16648 B 2.25
Xlsb_ExcelReader_Prefetch 15.400 ms 2.1702 ms 0.5636 ms 0.29 0.01 - 13000 B 1.75
Xlsb_ExcelReader_Memory 26.491 ms 0.1402 ms 0.0217 ms 0.51 0.00 - 8696 B 1.17
Xlsb_ExcelReader_Memory_Prefetch 15.140 ms 1.4985 ms 0.2319 ms 0.29 0.00 - 14850 B 2.00
Xls_ExcelReader 12.749 ms 0.1966 ms 0.0510 ms 0.24 0.00 - 12304 B 1.66
Xls_Sylvan 21.762 ms 0.2103 ms 0.0326 ms 0.42 0.00 - 190366 B 25.70
Xls_ExcelReader_Materialized 14.866 ms 0.2071 ms 0.0538 ms 0.28 0.00 - 22000 B 2.97
Xls_ExcelReader_Memory 12.558 ms 0.1187 ms 0.0308 ms 0.24 0.00 - 12168 B 1.64
Csv_ExcelReader 6.443 ms 0.0717 ms 0.0186 ms 0.12 0.00 - 840 B 0.11
Csv_Sylvan 5.353 ms 0.0299 ms 0.0078 ms 0.10 0.00 - 41226 B 5.57
Csv_ExcelReader_Materialized 23.904 ms 0.2431 ms 0.0631 ms 0.46 0.00 2218.7500 37443448 B 5,054.46
Csv_ExcelReader_Memory 6.165 ms 0.0242 ms 0.0063 ms 0.12 0.00 - 568 B 0.08

ExcelReader.Benchmarks.RealDataTypedParseBenchmark


BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.5 LTS (Noble Numbat)
AMD EPYC 9V74 2.60GHz, 1 CPU, 4 logical and 2 physical cores
.NET SDK 10.0.401
  [Host]     : .NET 10.0.12 (10.0.12, 10.0.1226.42308), X64 RyuJIT x86-64-v4
  Job-MEHJPP : .NET 10.0.12 (10.0.12, 10.0.1226.42308), X64 RyuJIT x86-64-v4

IterationCount=5  WarmupCount=1  

Method Mean Error StdDev Ratio RatioSD Gen0 Allocated Alloc Ratio
Xlsx_ExcelParser 63.73 ms 3.144 ms 0.816 ms 1.00 0.02 500.0000 8.02 MB 1.00
Xlsb_ExcelParser 34.75 ms 0.355 ms 0.055 ms 0.55 0.01 466.6667 8.02 MB 1.00

ExcelReader.Benchmarks.RecordWriteBenchmark


BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.5 LTS (Noble Numbat)
AMD EPYC 7763 2.45GHz, 1 CPU, 4 logical and 2 physical cores
.NET SDK 10.0.401
  [Host]     : .NET 10.0.12 (10.0.12, 10.0.1226.42308), X64 RyuJIT x86-64-v3
  Job-MEHJPP : .NET 10.0.12 (10.0.12, 10.0.1226.42308), X64 RyuJIT x86-64-v3

IterationCount=5  WarmupCount=1  

Method Rows Mean Error StdDev Ratio Gen0 Gen1 Gen2 Allocated Alloc Ratio
Xlsx 50000 17.538 ms 0.1057 ms 0.0163 ms 1.00 500.0000 500.0000 500.0000 4.02 MB 1.00
Xlsb 50000 10.421 ms 0.0852 ms 0.0221 ms 0.59 500.0000 500.0000 500.0000 4.02 MB 1.00
Xls 50000 7.919 ms 0.4844 ms 0.0750 ms 0.45 250.0000 250.0000 250.0000 4.03 MB 1.00
Csv 50000 7.103 ms 0.0849 ms 0.0131 ms 0.40 500.0000 500.0000 500.0000 4 MB 1.00
XlsxMapped 50000 19.404 ms 0.6372 ms 0.1655 ms 1.11 500.0000 500.0000 500.0000 4.02 MB 1.00
XlsbMapped 50000 12.563 ms 0.1558 ms 0.0405 ms 0.72 500.0000 500.0000 500.0000 4.02 MB 1.00
CsvMapped 50000 7.822 ms 0.1208 ms 0.0187 ms 0.45 500.0000 500.0000 500.0000 4 MB 1.00

ExcelReader.Benchmarks.StringHeavyReadBenchmark


BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.5 LTS (Noble Numbat)
AMD EPYC 9V74 2.60GHz, 1 CPU, 4 logical and 2 physical cores
.NET SDK 10.0.401
  [Host]     : .NET 10.0.12 (10.0.12, 10.0.1226.42308), X64 RyuJIT x86-64-v4
  Job-MEHJPP : .NET 10.0.12 (10.0.12, 10.0.1226.42308), X64 RyuJIT x86-64-v4

IterationCount=5  WarmupCount=1  

Method Rows Mean Error StdDev Ratio RatioSD Gen0 Gen1 Gen2 Allocated Alloc Ratio
Xlsx_ExcelReader 65536 42.30 ms 0.479 ms 0.124 ms 1.00 0.00 - - - 2.18 MB 1.00
Xlsx_ExcelReader_Prefetch 65536 33.04 ms 4.913 ms 1.276 ms 0.78 0.03 - - - 2.21 MB 1.01
Xlsx_Sylvan 65536 233.77 ms 9.237 ms 1.429 ms 5.53 0.03 666.6667 333.3333 - 17.41 MB 7.99
Xlsx_ExcelReader_Materialized 65536 79.66 ms 2.305 ms 0.599 ms 1.88 0.01 1000.0000 857.1429 285.7143 15.25 MB 7.00
Xlsx_ExcelReader_Materialized_Interned 65536 79.58 ms 12.879 ms 1.993 ms 1.88 0.04 1000.0000 857.1429 285.7143 15.26 MB 7.00
Xlsb_ExcelReader 65536 37.99 ms 1.668 ms 0.433 ms 0.90 0.01 - - - 2.18 MB 1.00
Xlsb_ExcelReader_Prefetch 65536 26.33 ms 3.460 ms 0.899 ms 0.62 0.02 - - - 2.22 MB 1.02
Xlsb_Sylvan 65536 87.56 ms 20.628 ms 5.357 ms 2.07 0.12 1166.6667 1000.0000 333.3333 17.38 MB 7.97
Xlsb_ExcelReader_Materialized 65536 68.00 ms 1.889 ms 0.491 ms 1.61 0.01 1000.0000 857.1429 285.7143 15.25 MB 7.00
Xlsb_ExcelReader_Materialized_Interned 65536 72.45 ms 13.524 ms 3.512 ms 1.71 0.08 1000.0000 875.0000 250.0000 15.26 MB 7.00
Xlsb_ExcelReader_Memory 65536 36.66 ms 0.467 ms 0.121 ms 0.87 0.00 - - - 6.46 MB 2.97

ExcelReader.Benchmarks.WriteBenchmark


BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.5 LTS (Noble Numbat)
AMD EPYC 7763 2.45GHz, 1 CPU, 4 logical and 2 physical cores
.NET SDK 10.0.401
  [Host]     : .NET 10.0.12 (10.0.12, 10.0.1226.42308), X64 RyuJIT x86-64-v3
  Job-MEHJPP : .NET 10.0.12 (10.0.12, 10.0.1226.42308), X64 RyuJIT x86-64-v3

IterationCount=5  WarmupCount=1  

Method Rows Mean Error StdDev Ratio Gen0 Gen1 Gen2 Allocated Alloc Ratio
ExcelReaderWriter 50000 16.554 ms 0.1595 ms 0.0414 ms 1.00 500.0000 500.0000 500.0000 4.02 MB 1.00
ExcelReaderWriterSharedStrings 50000 16.101 ms 0.0370 ms 0.0057 ms 0.97 500.0000 500.0000 500.0000 4.06 MB 1.01
ExcelReaderWriterPrefetch 50000 12.584 ms 1.6537 ms 0.2559 ms 0.76 484.3750 484.3750 484.3750 4.03 MB 1.00
ExcelReaderXlsbWriter 50000 10.399 ms 0.1737 ms 0.0451 ms 0.63 500.0000 500.0000 500.0000 4.02 MB 1.00
ExcelReaderXlsbWriterSharedStrings 50000 10.176 ms 0.4387 ms 0.1139 ms 0.61 500.0000 500.0000 500.0000 4.06 MB 1.01
ExcelReaderXlsbWriterPrefetch 50000 8.972 ms 0.5494 ms 0.1427 ms 0.54 484.3750 484.3750 484.3750 4.03 MB 1.00
OfficeIMO 50000 23.960 ms 0.0634 ms 0.0098 ms 1.45 312.5000 312.5000 312.5000 4.02 MB 1.00
SpreadCheetah 50000 20.803 ms 0.3130 ms 0.0813 ms 1.26 1437.5000 718.7500 718.7500 15.84 MB 3.94

ExcelReader.Benchmarks.WritePathBenchmark


BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.5 LTS (Noble Numbat)
AMD EPYC 7763 2.45GHz, 1 CPU, 4 logical and 2 physical cores
.NET SDK 10.0.401
  [Host]     : .NET 10.0.12 (10.0.12, 10.0.1226.42308), X64 RyuJIT x86-64-v3
  Job-MEHJPP : .NET 10.0.12 (10.0.12, 10.0.1226.42308), X64 RyuJIT x86-64-v3

IterationCount=5  WarmupCount=1  

Method Mean Error StdDev Allocated
NativeStrings_Xlsx 27.780 ms 0.0909 ms 0.0141 ms 18448 B
NativeStrings_Csv 7.214 ms 0.0201 ms 0.0031 ms 416 B
ArrowStrings_Xlsx 36.517 ms 0.2767 ms 0.0719 ms 18496 B
StyledRows_Xlsx 10.218 ms 0.0231 ms 0.0036 ms 18632 B

ExcelReader.Benchmarks.XlsReadBenchmark


BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.5 LTS (Noble Numbat)
Intel Xeon Platinum 8370C CPU 2.80GHz (Max: 3.39GHz), 1 CPU, 4 logical and 2 physical cores
.NET SDK 10.0.401
  [Host]     : .NET 10.0.12 (10.0.12, 10.0.1226.42308), X64 RyuJIT x86-64-v4
  Job-MEHJPP : .NET 10.0.12 (10.0.12, 10.0.1226.42308), X64 RyuJIT x86-64-v4

IterationCount=5  WarmupCount=1  

Method Rows Mean Error StdDev Ratio Gen0 Gen1 Allocated Alloc Ratio
ExcelReader 50000 4.918 ms 0.0616 ms 0.0160 ms 1.00 - - 2.84 KB 1.00
ExcelReaderAsync 50000 4.573 ms 0.0466 ms 0.0072 ms 0.93 - - 2.91 KB 1.02
Sylvan 50000 7.834 ms 0.1798 ms 0.0467 ms 1.59 62.5000 7.8125 1717.73 KB 605.70
OfficeIMO 50000 10.204 ms 0.2313 ms 0.0601 ms 2.07 421.8750 - 10499.2 KB 3,702.20

ExcelReader.Benchmarks.XlsWriteBenchmark


BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.5 LTS (Noble Numbat)
AMD EPYC 7763 2.45GHz, 1 CPU, 4 logical and 2 physical cores
.NET SDK 10.0.401
  [Host]     : .NET 10.0.12 (10.0.12, 10.0.1226.42308), X64 RyuJIT x86-64-v3
  Job-MEHJPP : .NET 10.0.12 (10.0.12, 10.0.1226.42308), X64 RyuJIT x86-64-v3

IterationCount=5  WarmupCount=1  

Method Rows Mean Error StdDev Ratio Gen0 Gen1 Gen2 Allocated Alloc Ratio
XlsWriter 50000 7.802 ms 0.0869 ms 0.0226 ms 1.00 484.3750 484.3750 484.3750 16.03 MB 1.00
XlsxWriter 50000 16.080 ms 0.1309 ms 0.0203 ms 2.06 500.0000 500.0000 500.0000 4.02 MB 0.25

ExcelReader.Benchmarks.XlsxSharedStringHotPathBenchmark


BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.5 LTS (Noble Numbat)
AMD EPYC 9V74 2.60GHz, 1 CPU, 4 logical and 2 physical cores
.NET SDK 10.0.401
  [Host]     : .NET 10.0.12 (10.0.12, 10.0.1226.42308), X64 RyuJIT x86-64-v4
  Job-MEHJPP : .NET 10.0.12 (10.0.12, 10.0.1226.42308), X64 RyuJIT x86-64-v4

IterationCount=5  WarmupCount=1  

Method Rows Mean Error StdDev Ratio RatioSD Allocated Alloc Ratio
EndToEnd 65536 42.130 ms 0.2185 ms 0.0567 ms 1.00 0.00 2285656 B 1.00
EndToEnd_Prefetch 65536 33.316 ms 2.6779 ms 0.6954 ms 0.79 0.02 2319424 B 1.01
SharedStringPrologue 65536 13.216 ms 0.9705 ms 0.2520 ms 0.31 0.01 764792 B 0.33
Stored_EndToEnd 65536 23.804 ms 0.2979 ms 0.0774 ms 0.56 0.00 2284976 B 1.00
Stored_SharedStringPrologue 65536 4.939 ms 0.2062 ms 0.0319 ms 0.12 0.00 764112 B 0.33
IndexParse_Utf8Parser 65536 2.745 ms 0.0109 ms 0.0017 ms 0.07 0.00 - 0.00
IndexParse_DigitLoop 65536 1.630 ms 0.0026 ms 0.0007 ms 0.04 0.00 - 0.00

GabrielMarquezMatte and others added 5 commits October 8, 2026 18:36
The generated factory was `new T()`, which fails with CS9035 when T or a base type declares a required member. It now sets every required member to default in the object initializer and lets the parse overwrite the ones it maps, matching FromAttributes, whose Activator.CreateInstance the runtime never checks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… across C++, Python, and Rust implementations
…rmats to reflect improved performance metrics
…merator overhead based on recent measurements

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants