Skip to content

Parallel sheet reads from one reader, positional sources and reader lifetime (v5.2.0) - #135

Merged
GabrielMarquezMatte merged 29 commits into
masterfrom
develop
Oct 6, 2026
Merged

GabrielMarquezMatte merged 29 commits into
masterfrom
develop

Conversation

@GabrielMarquezMatte

Copy link
Copy Markdown
Owner

What does this change?

Enumerators obtained from one reader can now be consumed on different threads, for XLSX, XLSB, XLS
and CSV, and a reader's file or stream stays open until its last enumerator is disposed. To get
there, every source is read positionally and XLSX/XLSB stop using ZipArchive on the read path.
The public API is unchanged.

  • Positional sources. New internal ByteSource (memory, file handle, seekable stream) and
    ByteSourceStream. ZipIndex (formerly ZipMemoryIndex) reads its directory and entries through
    any ByteSource, so XLSX and XLSB from a path or a stream no longer go through
    System.IO.Compression.ZipArchive. XLS loads its sectors the same way. A non-seekable stream is
    buffered to memory at open for XLSX, XLSB and XLS.
  • Shared state is safe to share. The decompressed-byte counter is atomic, cached shared strings
    are published with compare-and-swap, and the XLSX shared-string table is loaded once behind a gate
    that records a failure and undoes a cancelled load.
  • Reader lifetime. A reference count ties the pooled buffers, the ZIP index and the source to the
    reader and its live enumerators.
  • CSV. Memory, file paths and seekable streams are read positionally, so several enumerators can
    run at once. A non-seekable stream is still one streaming pass and is not buffered.
  • Before the above (8379db3). WriteRecordBatch accepts more Arrow types; XLSB and XLS yield
    rows written without cells, as XLSX does; the CSV structural scanner uses PMULL on ARM.

Behaviour changes

  • Using a reader after Dispose throws ObjectDisposedException.
  • Disposing a reader no longer closes its file or stream while an enumerator from it is undisposed.
    An enumerator that is never disposed keeps the file open.
  • A failed XLSX shared-string load fails every later enumeration the same way. It used to yield empty
    strings on the second attempt.
  • A CSV read over a seekable stream no longer leaves the caller's stream at the end.
  • XLSB and XLS readers yield rows that have no cells; the XLS writer emits a blank cell for such a row.
  • ZipIndex accepts trailing bytes after the end-of-central-directory record and rejects stored
    entries whose two sizes disagree.

Not in this PR

The v6 API (IExcelWorkbook, sheet values, removal of IExcelRowReader). "Current sheet" and
MoveToSheet are still unsynchronized: select sheets and create enumerators from one thread.

Checklist

  • dotnet build ExcelReader.slnx --configuration Release builds clean (warnings are errors)
  • dotnet test tests/ExcelReader.Tests/ExcelReader.Tests.csproj --configuration Release passes
  • If this changes the public API: PublicAPI.Unshipped.txt updated (no public API change; the file is empty)
  • Tests added/updated for the behavior change
  • One focused change — unrelated fixes are in a separate PR (this is the 5.2.0 release branch: 28 commits)

Test plan

  • Full suite: 2767 passing (2672 before this work), run twice with no flaky test.
  • New tests: ByteSource and ByteSourceStream per source kind; ZipIndex over positional sources
    including ZIP64 and failure paths; lifetime per format (enumerator outlives its reader, double
    dispose, failed open releases the reader); concurrent sheets across XLSX/XLSB/XLS and
    memory/stream/path, sync and async (27 cases, five consecutive runs); CSV with concurrent
    enumerators per source kind.
  • Fuzz smoke: check <seeds> 512 with seeds 1 and 7, 349,866 cases, 0 failures.
  • Sequential reads, pinned to one core, alternated builds: no line slower than before by more than
    1.5% on both lowest and median (XLSX and XLSB by path, FileStream and memory; CSV by path,
    FileStream and memory).
  • One reader with six sheets read in parallel against one reader per sheet (best of 5):
    XLSX 59 ms vs 65 ms, XLSB 67 ms vs 88 ms; sequential 225 ms and 206 ms.
  • Not run locally: the Python, Rust and C++ binding suites (their files and the C ABI are unchanged;
    CI covers them), and a long fuzz run on ZipIndex.

GabrielMarquezMatte and others added 29 commits October 5, 2026 15:21
…seekable streams

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

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…o the central directory

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

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…e from the read path

Excel.cs detects and dispatches with a ZipIndex; the Reopen* helpers,
ZipEntryBytes, ZipReaderOpen and the ZipArchive helpers in WorkbookLookups
are gone.

Tests: deleted ZipIndexTests.ZipEntryBytesReadThrowsInvalidDataWhenEntryUnderDelivers
(sole subject was ZipEntryBytes); rewrote the ReadViaZipArchive helper in
ZipIndexTests to read the entry through ZipArchive directly.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…g a shared stream

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…P index

ZIP64 fixtures now also run through a stream source, sync and async. The
mutation differential test covers sync and async part and entry-stream reads.
Entry streams are compared with the memory entry stream, since streams never
verify declared sizes on any source. Reader entry points are checked for
disposing the stream on failure, and the "less data than declared" guard is
covered again. No product defect found.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…exact stream types

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
DecompressedByteCounter.Add and Remaining are now thread-safe via
Interlocked.Add and Interlocked.Read, enabling concurrent sheet inflation
under a shared decompression limit. Once any thread exceeds the limit, all
subsequent Add calls throw—captured atomically in _total regardless of order.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Replace lazy-initialization with thread-safe compare-and-swap in Cell.GetString()
and each reader's SharedStringCache property. Materializes cache array once
per reader; filled slots never change, ensuring enumerators on different threads
see consistent string references and cached values.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
OnceGate runs a load once for multiple callers. A failure is recorded and rethrown without reloading;
cancellation runs reset and lets the next caller load fresh. Sync and async paths share one load.

ReaderLifetime is a reference-counted lifetime tracker. The reader holds one reference, each
enumerator another. Release runs when the last reference goes. Close is idempotent and prevents
new acquisitions once called.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
…or its enumerators

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…e offsets everywhere

ByteSourceStream and ZipIndex throw ObjectDisposedException after Dispose;
every ByteSource rejects a negative offset with ArgumentOutOfRangeException.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…uctor throws

The constructor reads the header row before it returns. A throw there (a limit,
a corrupt sheet) dropped the enumerator it had just taken, and that enumerator's
lease kept the reader's source open after the caller disposed the reader.

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

Enumerators created on one thread from a single XLSX, XLSB or XLS reader
(memory, stream and path sources) are drained on separate threads, sync and
async, and must match a sequential read. Threads reading one sheet must get
the very same shared-string instances (equal strings for XLS labels).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Dispose left the deferred-open flag set, so a MoveNext after Dispose opened a
new sheet stream and buffers with no lease. Clear the flag in Dispose and
DisposeAsync, and mark the cursor at end of data once its buffers are returned
so a use after dispose reports no rows instead of waiting for a source that
never comes.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…numerators

CsvReader over a seekable stream wraps it in a ByteSource and gives every
enumerator its own positional view, so enumerators no longer share or
rewind one Stream and can run concurrently. The reader holds a
ReaderLifetime: Dispose closes it to new enumerators and its file or stream
is released when the last enumerator is disposed. A non-seekable stream
serves a single enumerator. Rewrites the thread-safety remark of
IExcelRowReader accordingly.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A FileStream opened with a non-UTF-8 encoding would hand parallel chunking the raw, untranscoded file. The only caller already filters on encoding, so this was latent.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The positional stream buffered 64K of its own under a consumer that already buffers, copying every byte twice. It now takes an unbuffered mode, used for CSV when no transcoding stream sits in between.

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

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 91.30435% with 72 lines in your changes missing coverage. Please review.
✅ Project coverage is 89.88%. Comparing base (fe522c5) to head (1723f07).

Files with missing lines Patch % Lines
...xcelReader.Core/Reader/Sources/ByteSourceStream.cs 77.61% 12 Missing and 3 partials ⚠️
src/ExcelReader.Core/Reader/Xlsb/XlsbReader.cs 87.67% 7 Missing and 2 partials ⚠️
src/ExcelReader.Core/Reader/Xlsx/XlsxReader.cs 84.21% 7 Missing and 2 partials ⚠️
src/ExcelReader.Core/Reader/Internal/OnceGate.cs 85.36% 3 Missing and 3 partials ⚠️
src/ExcelReader.Core/Reader/Sources/ByteSource.cs 88.67% 4 Missing and 2 partials ⚠️
src/ExcelReader.Core/Reader/Xls/XlsReader.cs 71.42% 6 Missing ⚠️
src/ExcelReader.Core/Reader/Zip/ZipIndex.cs 97.54% 2 Missing and 3 partials ⚠️
src/ExcelReader.Arrow/ArrowWriteExtensions.cs 90.69% 4 Missing ⚠️
src/ExcelReader.Core/Reader/Csv/CsvReader.cs 93.02% 1 Missing and 2 partials ⚠️
...xcelReader.Core/Reader/Csv/CsvStructuralScanner.cs 0.00% 3 Missing ⚠️
... and 4 more
❗ Your organization needs to install the Codecov GitHub app to enable full functionality.
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #135      +/-   ##
==========================================
+ Coverage   89.45%   89.88%   +0.42%     
==========================================
  Files         181      185       +4     
  Lines       13612    13911     +299     
  Branches     2515     2550      +35     
==========================================
+ Hits        12177    12504     +327     
+ Misses        956      941      -15     
+ Partials      479      466      -13     

☔ 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 6, 2026

Copy link
Copy Markdown

Benchmark Results

Baseline: master fe522c52, 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.RecordWriteBenchmark.Xls(Rows: 50000) 6.49 ms 8.23 ms +26.9%
ExcelReader.Benchmarks.ReadBenchmark.OfficeIMO(Rows: 50000) 160.78 ms 203.65 ms +26.7%
ExcelReader.Benchmarks.StringHeavyReadBenchmark.Xlsx_Sylvan(Rows: 65536) 156.43 ms 189.03 ms +20.8%
ExcelReader.Benchmarks.RecordWriteBenchmark.CsvMapped(Rows: 50000) 7.33 ms 8.76 ms +19.5%
ExcelReader.Benchmarks.DataReaderBenchmark.DataTable_Load(Rows: 50000) 52.88 ms 62.43 ms +18.1%
ExcelReader.Benchmarks.XlsWriteBenchmark.XlsWriter(Rows: 50000) 7.11 ms 8.37 ms +17.7%
ExcelReader.Benchmarks.WritePathBenchmark.StyledRows_Xlsx 8.77 ms 10.29 ms +17.4%
ExcelReader.Benchmarks.XlsWriteBenchmark.XlsxWriter(Rows: 50000) 14.40 ms 16.59 ms +15.2%
ExcelReader.Benchmarks.StringHeavyReadBenchmark.Xlsx_ExcelReader_Materialized_Interned(Rows: 65536) 55.55 ms 63.77 ms +14.8%
ExcelReader.Benchmarks.StringHeavyReadBenchmark.Xlsb_ExcelReader_Materialized_Interned(Rows: 65536) 48.42 ms 55.58 ms +14.8%
ExcelReader.Benchmarks.StringHeavyReadBenchmark.Xlsx_ExcelReader_Materialized(Rows: 65536) 54.22 ms 61.91 ms +14.2%
ExcelReader.Benchmarks.RealDataReadBenchmark.Xlsx_ExcelReader_Memory_Prefetch 45.63 ms 51.99 ms +13.9%
ExcelReader.Benchmarks.CsvWriteBenchmark.Sep(Rows: 50000) 9.33 ms 10.55 ms +13.0%
ExcelReader.Benchmarks.WriteBenchmark.ExcelReaderWriter(Rows: 50000) 14.67 ms 16.51 ms +12.5%
ExcelReader.Benchmarks.StringHeavyReadBenchmark.Xlsb_ExcelReader_Materialized(Rows: 65536) 48.91 ms 55.04 ms +12.5%
ExcelReader.Benchmarks.RecordWriteBenchmark.Xlsb(Rows: 50000) 10.06 ms 11.30 ms +12.3%
ExcelReader.Benchmarks.WriteBenchmark.ExcelReaderWriterSharedStrings(Rows: 50000) 14.32 ms 16.05 ms +12.1%
ExcelReader.Benchmarks.StringHeavyReadBenchmark.Xlsb_ExcelReader(Rows: 65536) 32.21 ms 35.91 ms +11.5%
ExcelReader.Benchmarks.WriteBenchmark.ExcelReaderWriterPrefetch(Rows: 50000) 11.07 ms 12.32 ms +11.2%
ExcelReader.Benchmarks.WritePathBenchmark.NativeStrings_Csv 6.66 ms 7.40 ms +11.2%
ExcelReader.Benchmarks.RealDataReadBenchmark.Xlsx_ExcelReader_Prefetch 47.00 ms 52.21 ms +11.1%
ExcelReader.Benchmarks.RealDataReadBenchmark.Xlsm_ExcelReader_Prefetch 45.52 ms 50.46 ms +10.9%
ExcelReader.Benchmarks.StringHeavyReadBenchmark.Xlsb_Sylvan(Rows: 65536) 53.73 ms 59.23 ms +10.2%
ExcelReader.Benchmarks.CsvParallelVsSepBenchmark.Sep_Parallel(Corpus: NarrowInt) 458.72 ms 408.54 ms -10.9%
ExcelReader.Benchmarks.ParseBenchmark.ExcelParserStructSync(Rows: 50000) 15.46 ms 13.61 ms -11.9%
ExcelReader.Benchmarks.CsvParallelParseBenchmark.NarrowInt(Dop: 1) 801.66 ms 704.92 ms -12.1%
ExcelReader.Benchmarks.CsvParallelParseBenchmark.NarrowInt(Dop: 4) 472.47 ms 414.42 ms -12.3%
ExcelReader.Benchmarks.ParseBenchmark.SylvanAsync(Rows: 50000) 89.70 ms 78.45 ms -12.5%
ExcelReader.Benchmarks.CsvParallelVsSepBenchmark.ExcelReader_Sequential(Corpus: ConversionHeavy) 957.15 ms 836.79 ms -12.6%
ExcelReader.Benchmarks.ParseBenchmark.ExcelParserSync(Rows: 50000) 16.56 ms 14.34 ms -13.4%
ExcelReader.Benchmarks.CsvParallelParseBenchmark.ConversionHeavyAggregate(Dop: 2) 740.68 ms 639.20 ms -13.7%
ExcelReader.Benchmarks.EncryptedWorkbookBenchmark.Encrypted_OpenOnly 44.88 ms 38.68 ms -13.8%
ExcelReader.Benchmarks.ParseBenchmark.ExcelParserXlsbSync(Rows: 50000) 11.90 ms 10.10 ms -15.1%
ExcelReader.Benchmarks.CsvParallelParseBenchmark.ConversionHeavy(Dop: 4) 774.11 ms 651.26 ms -15.9%
ExcelReader.Benchmarks.CsvParallelVsSepBenchmark.Sep_Parallel(Corpus: ConversionHeavy) 813.60 ms 682.27 ms -16.1%
ExcelReader.Benchmarks.CsvParallelParseBenchmark.ConversionHeavy(Dop: 8) 760.80 ms 636.32 ms -16.4%
ExcelReader.Benchmarks.CsvParallelParseBenchmark.ConversionHeavyAggregate(Dop: 16) 503.59 ms 420.40 ms -16.5%
ExcelReader.Benchmarks.CsvParallelParseBenchmark.ConversionHeavy(Dop: 16) 763.79 ms 637.10 ms -16.6%
ExcelReader.Benchmarks.ParseBenchmark.ExcelParserXlsbAsync(Rows: 50000) 12.24 ms 10.21 ms -16.6%
ExcelReader.Benchmarks.CsvParallelParseBenchmark.NarrowIntAggregate(Dop: 2) 490.19 ms 408.79 ms -16.6%
ExcelReader.Benchmarks.CsvParallelParseBenchmark.NarrowInt(Dop: 16) 472.63 ms 392.44 ms -17.0%
ExcelReader.Benchmarks.CsvParallelParseBenchmark.ConversionHeavyAggregate(Dop: 8) 500.38 ms 414.20 ms -17.2%
ExcelReader.Benchmarks.CsvParallelParseBenchmark.ConversionHeavy(Dop: 1) 1.46 s 1.20 s -17.5%
ExcelReader.Benchmarks.CsvParallelParseBenchmark.NarrowIntAggregate(Dop: 4) 311.19 ms 254.04 ms -18.4%
ExcelReader.Benchmarks.CsvParallelVsSepBenchmark.Sep_Sequential(Corpus: ConversionHeavy) 1.18 s 957.88 ms -18.8%
ExcelReader.Benchmarks.ParseBenchmark.ExcelParserSyncSharedStrings(Rows: 50000) 16.30 ms 13.21 ms -19.0%
ExcelReader.Benchmarks.CsvParseBenchmark.ExcelParserAsync(Rows: 50000) 7.35 ms 5.95 ms -19.0%
ExcelReader.Benchmarks.CsvParallelVsSepBenchmark.ExcelReader_Parallel(Corpus: ConversionHeavy) 563.08 ms 455.56 ms -19.1%
ExcelReader.Benchmarks.CsvParallelParseBenchmark.NarrowIntAggregate(Dop: 16) 321.72 ms 259.19 ms -19.4%
ExcelReader.Benchmarks.CsvParallelParseBenchmark.NarrowIntAggregate(Dop: 8) 316.57 ms 252.86 ms -20.1%
ExcelReader.Benchmarks.CsvParallelParseBenchmark.NarrowInt(Dop: 8) 489.10 ms 390.53 ms -20.2%
ExcelReader.Benchmarks.ParseBenchmark.ExcelParserAsync(Rows: 50000) 18.53 ms 14.73 ms -20.5%
ExcelReader.Benchmarks.CsvParallelParseBenchmark.NarrowInt(Dop: 2) 703.50 ms 556.85 ms -20.8%
ExcelReader.Benchmarks.CsvParallelVsSepBenchmark.ExcelReader_Parallel(Corpus: NarrowInt) 493.02 ms 390.09 ms -20.9%
ExcelReader.Benchmarks.EncryptedWorkbookBenchmark.Encrypted_Stream_VerifyIntegrity 44.40 ms 34.77 ms -21.7%
ExcelReader.Benchmarks.ParseBenchmark.RefStructModelSync(Rows: 50000) 15.55 ms 12.14 ms -21.9%
ExcelReader.Benchmarks.EncryptedWorkbookBenchmark.Large_Encrypted_OpenOnly 44.68 ms 34.78 ms -22.2%
ExcelReader.Benchmarks.CsvParallelParseBenchmark.NarrowIntAggregate(Dop: 1) 733.63 ms 568.35 ms -22.5%
ExcelReader.Benchmarks.CsvParseBenchmark.ExcelParserSync(Rows: 50000) 7.23 ms 5.60 ms -22.6%
ExcelReader.Benchmarks.CsvParseBenchmark.Sylvan(Rows: 50000) 19.28 ms 14.65 ms -24.0%
ExcelReader.Benchmarks.CsvParallelParseBenchmark.ConversionHeavy(Dop: 2) 1.14 s 865.28 ms -24.2%
ExcelReader.Benchmarks.CsvParallelParseBenchmark.ConversionHeavyAggregate(Dop: 1) 1.19 s 902.70 ms -24.3%
ExcelReader.Benchmarks.EncryptedWorkbookBenchmark.Encrypted_Memory 44.41 ms 33.55 ms -24.4%
ExcelReader.Benchmarks.EncryptedWorkbookBenchmark.Large_Encrypted_Stream 94.01 ms 69.84 ms -25.7%
ExcelReader.Benchmarks.EncryptedWorkbookBenchmark.Encrypted_Stream 50.15 ms 36.88 ms -26.5%
ExcelReader.Benchmarks.CsvParseBenchmark.Sep(Rows: 50000) 14.65 ms 10.58 ms -27.8%
ExcelReader.Benchmarks.ColdStartBenchmark.FluentParseFirstUse(Rows: 200) 38.45 ms 26.83 ms -30.2%
ExcelReader.Benchmarks.ColdStartBenchmark.TypedParseFirstUse(Rows: 200) 42.83 ms 29.88 ms -30.2%
ExcelReader.Benchmarks.CsvReadBenchmark.ExcelReader(Rows: 50000) 5.92 ms 4.07 ms -31.2%
ExcelReader.Benchmarks.EncryptedWorkbookBenchmark.Large_Plain_Stream 50.46 ms 34.03 ms -32.6%
ExcelReader.Benchmarks.ColdStartBenchmark.FluentParseWithAttributeFallbackFirstUse(Rows: 200) 47.95 ms 31.70 ms -33.9%
ExcelReader.Benchmarks.NativeRowReadBenchmark.ReadAllBlob 58.99 ms 37.91 ms -35.7%
ExcelReader.Benchmarks.NativeRowReadBenchmark.NextRowBlob 54.49 ms 33.78 ms -38.0%
ExcelReader.Benchmarks.NativeRowReadBenchmark.NextRowDecoded 61.82 ms 38.18 ms -38.2%
ExcelReader.Benchmarks.ColdStartBenchmark.RecordWriteFirstUse(Rows: 200) 26.28 ms 15.89 ms -39.5%
ExcelReader.Benchmarks.NativeTypedParseBenchmark.ParseTyped 52.60 ms 31.64 ms -39.8%
ExcelReader.Benchmarks.EncryptedWorkbookBenchmark.Plain_Stream 59.22 µs 33.51 µs -43.4%
ExcelReader.Benchmarks.NativeTypedParseBenchmark.ParseArrow 51.45 ms 28.58 ms -44.4%
ExcelReader.Benchmarks.ChunkedParseBenchmark.Batched_1k(Rows: 50000) 12.90 ms 7.07 ms -45.2%
ExcelReader.Benchmarks.ChunkedParseBenchmark.Batched_10k(Rows: 50000) 12.91 ms 6.94 ms -46.2%
ExcelReader.Benchmarks.ChunkedParseBenchmark.WholeSheet(Rows: 50000) 13.72 ms 7.10 ms -48.2%
ExcelReader.Benchmarks.NativeRowReadBenchmark.ReadAllDecoded 82.91 ms 42.50 ms -48.7%

77 within ±10%.

Full results per group

ExcelReader.Benchmarks.ArrowConversionBenchmark


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
CsvAllString 100000 22.12 ms 0.541 ms 0.141 ms 1.00 0.01 687.5000 562.5000 562.5000 16.27 MB 1.00
CsvTyped 100000 12.63 ms 0.469 ms 0.122 ms 0.57 0.01 468.7500 421.8750 421.8750 8.13 MB 0.50
XlsbTyped 100000 17.01 ms 2.200 ms 0.571 ms 0.77 0.02 468.7500 437.5000 437.5000 8.14 MB 0.50
CsvTypedWithInference 100000 11.29 ms 0.458 ms 0.119 ms 0.51 0.01 593.7500 562.5000 531.2500 14.89 MB 0.92

ExcelReader.Benchmarks.ChunkedParseBenchmark


BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.5 LTS (Noble Numbat)
AMD EPYC 9V45 4.40GHz, 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
WholeSheet 50000 7.105 ms 0.3098 ms 0.0479 ms 1.00 78.1250 62.5000 1.3 MB 1.00
Batched_10k 50000 6.944 ms 0.3417 ms 0.0887 ms 0.98 93.7500 54.6875 1.59 MB 1.23
Batched_1k 50000 7.066 ms 0.2696 ms 0.0417 ms 0.99 93.7500 7.8125 1.51 MB 1.16

ExcelReader.Benchmarks.ColdStartBenchmark


BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.5 LTS (Noble Numbat)
AMD EPYC 9V45 4.27GHz, 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-GOEFXF : .NET 10.0.12 (10.0.12, 10.0.1226.42308), X64 RyuJIT x86-64-v4

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

Method Rows Mean Error StdDev Allocated
TypedParseFirstUse 200 29.88 ms 1.461 ms 1.435 ms 20.98 KB
RecordWriteFirstUse 200 15.89 ms 0.779 ms 0.765 ms 84.25 KB
FluentParseFirstUse 200 26.83 ms 4.229 ms 4.154 ms 23.5 KB
FluentParseWithAttributeFallbackFirstUse 200 31.70 ms 0.758 ms 0.745 ms 25.2 KB

ExcelReader.Benchmarks.CsvParallelParseBenchmark


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 Dop Mean Error StdDev Ratio RatioSD Gen0 Gen1 Allocated Alloc Ratio
ConversionHeavy 1 1,204.5 ms 44.57 ms 6.90 ms 1.00 0.01 8000.0000 - 671.37 MB 1.000
NarrowInt 1 704.9 ms 56.56 ms 14.69 ms 0.59 0.01 3000.0000 - 245.76 MB 0.366
ConversionHeavyAggregate 1 902.7 ms 23.79 ms 6.18 ms 0.75 0.01 - - 1.17 MB 0.002
NarrowIntAggregate 1 568.3 ms 37.58 ms 9.76 ms 0.47 0.01 - - 1.15 MB 0.002
ConversionHeavy 2 865.3 ms 60.98 ms 15.84 ms 1.00 0.02 8000.0000 4000.0000 678.7 MB 1.000
NarrowInt 2 556.9 ms 66.04 ms 17.15 ms 0.64 0.02 3000.0000 1000.0000 253.12 MB 0.373
ConversionHeavyAggregate 2 639.2 ms 33.81 ms 8.78 ms 0.74 0.02 - - 1.22 MB 0.002
NarrowIntAggregate 2 408.8 ms 46.37 ms 12.04 ms 0.47 0.01 - - 1.23 MB 0.002
ConversionHeavy 4 651.3 ms 33.42 ms 8.68 ms 1.00 0.02 8000.0000 6000.0000 678.78 MB 1.000
NarrowInt 4 414.4 ms 56.02 ms 14.55 ms 0.64 0.02 3000.0000 1000.0000 253.33 MB 0.373
ConversionHeavyAggregate 4 447.0 ms 52.82 ms 13.72 ms 0.69 0.02 - - 1.22 MB 0.002
NarrowIntAggregate 4 254.0 ms 12.32 ms 3.20 ms 0.39 0.01 - - 1.23 MB 0.002
ConversionHeavy 8 636.3 ms 52.45 ms 13.62 ms 1.00 0.03 8000.0000 7000.0000 678.81 MB 1.000
NarrowInt 8 390.5 ms 40.21 ms 6.22 ms 0.61 0.01 3000.0000 1000.0000 253.32 MB 0.373
ConversionHeavyAggregate 8 414.2 ms 48.52 ms 12.60 ms 0.65 0.02 - - 1.23 MB 0.002
NarrowIntAggregate 8 252.9 ms 5.67 ms 0.88 ms 0.40 0.01 - - 1.26 MB 0.002
ConversionHeavy 16 637.1 ms 50.01 ms 7.74 ms 1.00 0.02 8000.0000 2000.0000 679.27 MB 1.000
NarrowInt 16 392.4 ms 45.41 ms 7.03 ms 0.62 0.01 3000.0000 1000.0000 254.02 MB 0.374
ConversionHeavyAggregate 16 420.4 ms 9.14 ms 1.41 ms 0.66 0.01 - - 1.29 MB 0.002
NarrowIntAggregate 16 259.2 ms 9.42 ms 2.45 ms 0.41 0.01 - - 1.31 MB 0.002

ExcelReader.Benchmarks.CsvParallelVsSepBenchmark


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 Corpus Mean Error StdDev Ratio RatioSD Gen0 Gen1 Allocated Alloc Ratio
ExcelReader_Sequential NarrowInt 642.7 ms 20.98 ms 5.45 ms 1.00 0.01 3000.0000 - 244.14 MB 1.00
ExcelReader_Parallel NarrowInt 390.1 ms 26.27 ms 4.06 ms 0.61 0.01 3000.0000 1000.0000 253.15 MB 1.04
Sep_Sequential NarrowInt 552.0 ms 5.22 ms 1.36 ms 0.86 0.01 3000.0000 - 244.15 MB 1.00
Sep_Parallel NarrowInt 408.5 ms 59.06 ms 15.34 ms 0.64 0.02 3000.0000 2000.0000 257.6 MB 1.06
ExcelReader_Sequential ConversionHeavy 836.8 ms 15.89 ms 4.13 ms 1.00 0.01 5000.0000 - 467.3 MB 1.00
ExcelReader_Parallel ConversionHeavy 455.6 ms 49.65 ms 12.90 ms 0.54 0.01 5000.0000 4000.0000 473.63 MB 1.01
Sep_Sequential ConversionHeavy 957.9 ms 13.27 ms 2.05 ms 1.14 0.01 5000.0000 - 467.31 MB 1.00
Sep_Parallel ConversionHeavy 682.3 ms 64.62 ms 16.78 ms 0.82 0.02 6000.0000 5000.0000 477.26 MB 1.02

ExcelReader.Benchmarks.CsvParseBenchmark


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 Gen0 Gen1 Allocated Alloc Ratio
ExcelParserSync 50000 5.597 ms 0.0536 ms 0.0139 ms 1.00 46.8750 - 3.86 MB 1.00
ExcelParserAsync 50000 5.952 ms 0.0708 ms 0.0109 ms 1.06 46.8750 - 3.86 MB 1.00
Sep 50000 10.582 ms 0.2055 ms 0.0318 ms 1.89 46.8750 - 3.87 MB 1.00
Sylvan 50000 14.649 ms 0.1403 ms 0.0364 ms 2.62 125.0000 15.6250 10.95 MB 2.84

ExcelReader.Benchmarks.CsvReadBenchmark


BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.5 LTS (Noble Numbat)
AMD EPYC 7763 3.19GHz, 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
ExcelReader 50000 4.071 ms 0.2974 ms 0.0772 ms 1.00 0.02 784 B 1.00
ExcelReaderWide 50000 12.523 ms 0.2030 ms 0.0314 ms 3.08 0.05 784 B 1.00
ExcelReaderAsync 50000 3.964 ms 0.0200 ms 0.0052 ms 0.97 0.02 856 B 1.09
Sep 50000 13.663 ms 0.1800 ms 0.0468 ms 3.36 0.06 4024 B 5.13
Sylvan 50000 5.893 ms 0.0510 ms 0.0079 ms 1.45 0.03 38682 B 49.34

ExcelReader.Benchmarks.CsvWriteBenchmark


BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.5 LTS (Noble Numbat)
AMD EPYC 7763 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-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.462 ms 0.2263 ms 0.0588 ms 1.00 0.01 500.0000 500.0000 500.0000 4 MB 1.00
Sep 50000 10.551 ms 0.7169 ms 0.1862 ms 1.63 0.03 500.0000 500.0000 500.0000 4.01 MB 1.00
SylvanWriter 50000 10.815 ms 0.2655 ms 0.0689 ms 1.67 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)
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
Baseline_RawRows 50000 8.006 ms 0.0099 ms 0.0026 ms 1.00 0.00 - - - 3.73 KB 1.00
DataReader_GetValue 50000 11.050 ms 0.0855 ms 0.0222 ms 1.38 0.00 312.5000 - - 5131.38 KB 1,374.09
DataReader_TypedGetters 50000 10.977 ms 0.0224 ms 0.0035 ms 1.37 0.00 93.7500 - - 1615.75 KB 432.67
DataReader_GetBytes 50000 8.423 ms 0.0366 ms 0.0057 ms 1.05 0.00 - - - 4.42 KB 1.18
DataTable_Load 50000 62.434 ms 2.3489 ms 0.6100 ms 7.80 0.07 2000.0000 1875.0000 875.0000 23393.35 KB 6,264.33

ExcelReader.Benchmarks.EncryptedWorkbookBenchmark


BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.5 LTS (Noble Numbat)
AMD EPYC 9V45 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
Plain_Stream 33.51 μs 1.352 μs 0.209 μs 1.00 0.01 0.5493 9.01 KB 1.00
Encrypted_Stream 36,876.78 μs 5,348.495 μs 1,388.987 μs 1,100.48 38.52 - 38.05 KB 4.22
Encrypted_Stream_VerifyIntegrity 34,768.61 μs 1,407.507 μs 365.525 μs 1,037.57 11.55 - 39.98 KB 4.44
Encrypted_Memory 33,554.87 μs 976.205 μs 151.069 μs 1,001.35 6.89 - 53 KB 5.88
Encrypted_OpenOnly 38,681.96 μs 4,660.453 μs 721.210 μs 1,154.35 20.30 - 32.43 KB 3.60
Large_Plain_Stream 34,029.41 μs 499.472 μs 77.294 μs 1,015.51 6.03 - 3.73 KB 0.41
Large_Encrypted_Stream 69,839.37 μs 3,167.099 μs 490.112 μs 2,084.16 17.51 - 29.46 KB 3.27
Large_Encrypted_OpenOnly 34,782.39 μs 2,043.549 μs 530.703 μs 1,037.98 15.63 - 28.86 KB 3.20

ExcelReader.Benchmarks.NativeRowReadBenchmark


BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.5 LTS (Noble Numbat)
AMD EPYC 9V45 4.40GHz, 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 Gen1 Gen2 Allocated Alloc Ratio
NextRowBlob 33.78 ms 2.293 ms 0.596 ms 1.00 0.02 266.6667 266.6667 266.6667 3.71 MB 1.00
NextRowDecoded 38.18 ms 1.039 ms 0.161 ms 1.13 0.02 285.7143 285.7143 285.7143 3.71 MB 1.00
ReadAllBlob 37.91 ms 2.487 ms 0.646 ms 1.12 0.03 1142.8571 1071.4286 71.4286 21.06 MB 5.68
ReadAllDecoded 42.50 ms 1.199 ms 0.312 ms 1.26 0.02 583.3333 583.3333 583.3333 5.71 MB 1.54

ExcelReader.Benchmarks.NativeTypedParseBenchmark


BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.5 LTS (Noble Numbat)
AMD EPYC 9V45 4.40GHz, 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 Gen1 Gen2 Allocated Alloc Ratio
ParseTyped 31.64 ms 2.536 ms 0.659 ms 1.00 0.03 812.5000 687.5000 375.0000 11.61 MB 1.00
ParseArrow 28.58 ms 1.906 ms 0.495 ms 0.90 0.02 906.2500 843.7500 437.5000 11.62 MB 1.00

ExcelReader.Benchmarks.ParseBenchmark


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 Allocated Alloc Ratio
ExcelParserSync 50000 14.34 ms 0.098 ms 0.015 ms 1.00 0.00 46.8750 3959.35 KB 1.000
ExcelParserSyncSharedStrings 50000 13.21 ms 0.582 ms 0.090 ms 0.92 0.01 15.6250 2349.29 KB 0.593
ExcelParserStructSync 50000 13.61 ms 0.054 ms 0.008 ms 0.95 0.00 15.6250 1615.6 KB 0.408
RefStructModelSync 50000 12.14 ms 0.142 ms 0.022 ms 0.85 0.00 - 4.27 KB 0.001
ExcelParserAsync 50000 14.73 ms 0.162 ms 0.042 ms 1.03 0.00 46.8750 3959.44 KB 1.000
ExcelParserXlsbSync 50000 10.10 ms 0.091 ms 0.024 ms 0.70 0.00 46.8750 3959.66 KB 1.000
ExcelParserXlsbAsync 50000 10.21 ms 0.212 ms 0.055 ms 0.71 0.00 46.8750 3959.75 KB 1.000
OfficeIMO 50000 174.72 ms 103.092 ms 26.773 ms 12.18 1.71 - 5833.73 KB 1.473
Sylvan 50000 82.08 ms 94.723 ms 14.658 ms 5.72 0.91 - 10726.71 KB 2.709
SylvanAsync 50000 78.45 ms 2.021 ms 0.313 ms 5.47 0.02 - 10727.74 KB 2.709

ExcelReader.Benchmarks.ReadBenchmark


BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.5 LTS (Noble Numbat)
AMD EPYC 7763 3.19GHz, 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
ExcelReader 50000 11.916 ms 0.0680 ms 0.0105 ms 1.00 0.00 - 3.73 KB 1.00
ExcelReaderAsync 50000 12.400 ms 0.1378 ms 0.0213 ms 1.04 0.00 - 3.8 KB 1.02
ExcelReaderXlsb 50000 7.270 ms 0.0250 ms 0.0065 ms 0.61 0.00 - 4.05 KB 1.08
ExcelReaderXlsbAsync 50000 7.402 ms 0.1075 ms 0.0279 ms 0.62 0.00 - 4.12 KB 1.10
ExcelReaderMaterialized 50000 13.284 ms 0.0819 ms 0.0213 ms 1.11 0.00 93.7500 1615.06 KB 432.49
Sylvan 50000 55.244 ms 1.3595 ms 0.2104 ms 4.64 0.02 - 1939.18 KB 519.28
OfficeIMO 50000 203.650 ms 264.4153 ms 40.9186 ms 17.09 3.07 - 7003.97 KB 1,875.54
OfficeIMOXlsb 50000 17.675 ms 0.3864 ms 0.0598 ms 1.48 0.00 406.2500 6858.72 KB 1,836.64

ExcelReader.Benchmarks.RealDataReadBenchmark


BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.5 LTS (Noble Numbat)
Intel Xeon Platinum 8370C CPU 2.80GHz, 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 76.623 ms 1.3756 ms 0.2129 ms 1.00 0.00 - 7720 B 1.00
Xlsx_Sylvan 311.419 ms 22.7511 ms 3.5208 ms 4.06 0.04 - 659568 B 85.44
Xlsx_ExcelReader_Materialized 77.948 ms 0.9473 ms 0.1466 ms 1.02 0.00 - 17416 B 2.26
Xlsx_ExcelReader_Prefetch 52.214 ms 11.8649 ms 3.0813 ms 0.68 0.04 - 26852 B 3.48
Xlsx_ExcelReader_Memory 77.592 ms 0.8782 ms 0.1359 ms 1.01 0.00 - 7464 B 0.97
Xlsx_ExcelReader_Memory_Prefetch 51.987 ms 22.3976 ms 5.8166 ms 0.68 0.07 - 26908 B 3.49
Xlsm_ExcelReader 77.794 ms 0.8965 ms 0.2328 ms 1.02 0.00 - 7720 B 1.00
Xlsm_Sylvan 310.297 ms 5.0602 ms 1.3141 ms 4.05 0.02 - 659648 B 85.45
Xlsm_ExcelReader_Materialized 77.874 ms 0.7616 ms 0.1978 ms 1.02 0.00 - 17416 B 2.26
Xlsm_ExcelReader_Prefetch 50.457 ms 22.5951 ms 3.4966 ms 0.66 0.04 - 27962 B 3.62
Xlsm_ExcelReader_Memory 76.066 ms 0.3553 ms 0.0923 ms 0.99 0.00 - 7464 B 0.97
Xlsm_ExcelReader_Memory_Prefetch 46.903 ms 4.8716 ms 1.2651 ms 0.61 0.02 - 27426 B 3.55
Xlsb_ExcelReader 34.657 ms 0.2941 ms 0.0455 ms 0.45 0.00 - 7264 B 0.94
Xlsb_Sylvan 42.360 ms 0.2748 ms 0.0714 ms 0.55 0.00 - 346673 B 44.91
Xlsb_ExcelReader_Materialized 36.615 ms 0.4287 ms 0.0663 ms 0.48 0.00 - 16960 B 2.20
Xlsb_ExcelReader_Prefetch 21.407 ms 3.2100 ms 0.8336 ms 0.28 0.01 - 27473 B 3.56
Xlsb_ExcelReader_Memory 34.664 ms 0.1992 ms 0.0308 ms 0.45 0.00 - 9008 B 1.17
Xlsb_ExcelReader_Memory_Prefetch 22.041 ms 2.0007 ms 0.3096 ms 0.29 0.00 - 18254 B 2.36
Xls_ExcelReader 16.060 ms 0.1071 ms 0.0278 ms 0.21 0.00 - 12216 B 1.58
Xls_Sylvan 25.543 ms 0.4191 ms 0.1088 ms 0.33 0.00 - 190366 B 24.66
Xls_ExcelReader_Materialized 18.268 ms 0.0629 ms 0.0097 ms 0.24 0.00 - 21912 B 2.84
Xls_ExcelReader_Memory 15.556 ms 0.1738 ms 0.0269 ms 0.20 0.00 - 12080 B 1.56
Csv_ExcelReader 8.334 ms 0.0406 ms 0.0063 ms 0.11 0.00 - 784 B 0.10
Csv_Sylvan 6.833 ms 0.0811 ms 0.0211 ms 0.09 0.00 - 41226 B 5.34
Csv_ExcelReader_Materialized 32.940 ms 0.3277 ms 0.0851 ms 0.43 0.00 1437.5000 37443392 B 4,850.18
Csv_ExcelReader_Memory 7.664 ms 0.1114 ms 0.0289 ms 0.10 0.00 - 512 B 0.07

ExcelReader.Benchmarks.RealDataTypedParseBenchmark


BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.5 LTS (Noble Numbat)
Intel Xeon Platinum 8370C CPU 2.80GHz, 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 Gen0 Allocated Alloc Ratio
Xlsx_ExcelParser 89.70 ms 0.956 ms 0.148 ms 1.00 333.3333 8.02 MB 1.00
Xlsb_ExcelParser 45.54 ms 0.449 ms 0.117 ms 0.51 272.7273 8.02 MB 1.00

ExcelReader.Benchmarks.RecordWriteBenchmark


BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.5 LTS (Noble Numbat)
AMD EPYC 7763 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-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
Xlsx 50000 17.620 ms 0.9798 ms 0.2545 ms 1.00 0.02 500.0000 500.0000 500.0000 4.02 MB 1.00
Xlsb 50000 11.297 ms 0.3082 ms 0.0800 ms 0.64 0.01 500.0000 500.0000 500.0000 4.02 MB 1.00
Xls 50000 8.233 ms 0.6094 ms 0.1583 ms 0.47 0.01 250.0000 250.0000 250.0000 4.03 MB 1.00
Csv 50000 6.688 ms 0.0535 ms 0.0139 ms 0.38 0.01 500.0000 500.0000 500.0000 4 MB 1.00
XlsxMapped 50000 18.528 ms 0.3185 ms 0.0827 ms 1.05 0.01 500.0000 500.0000 500.0000 4.02 MB 1.00
XlsbMapped 50000 12.139 ms 0.2471 ms 0.0382 ms 0.69 0.01 500.0000 500.0000 500.0000 4.02 MB 1.00
CsvMapped 50000 8.757 ms 0.0978 ms 0.0254 ms 0.50 0.01 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 9V45 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 40.77 ms 2.000 ms 0.310 ms 1.00 0.01 - - - 2.18 MB 1.00
Xlsx_ExcelReader_Prefetch 65536 33.82 ms 2.274 ms 0.591 ms 0.83 0.01 - - - 2.27 MB 1.04
Xlsx_Sylvan 65536 189.03 ms 6.842 ms 1.777 ms 4.64 0.05 666.6667 333.3333 - 17.41 MB 7.98
Xlsx_ExcelReader_Materialized 65536 61.91 ms 3.108 ms 0.807 ms 1.52 0.02 1000.0000 875.0000 250.0000 15.25 MB 6.99
Xlsx_ExcelReader_Materialized_Interned 65536 63.77 ms 7.944 ms 2.063 ms 1.56 0.05 1000.0000 875.0000 250.0000 15.26 MB 7.00
Xlsb_ExcelReader 65536 35.91 ms 1.250 ms 0.193 ms 0.88 0.01 - - - 2.18 MB 1.00
Xlsb_ExcelReader_Prefetch 65536 26.53 ms 1.298 ms 0.337 ms 0.65 0.01 - - - 2.31 MB 1.06
Xlsb_Sylvan 65536 59.23 ms 11.118 ms 2.887 ms 1.45 0.07 1111.1111 1000.0000 333.3333 17.38 MB 7.97
Xlsb_ExcelReader_Materialized 65536 55.04 ms 4.139 ms 0.641 ms 1.35 0.02 1100.0000 1000.0000 300.0000 15.25 MB 6.99
Xlsb_ExcelReader_Materialized_Interned 65536 55.58 ms 5.176 ms 1.344 ms 1.36 0.03 1100.0000 1000.0000 300.0000 15.26 MB 7.00
Xlsb_ExcelReader_Memory 65536 35.11 ms 1.182 ms 0.183 ms 0.86 0.01 - - - 6.47 MB 2.97

ExcelReader.Benchmarks.WriteBenchmark


BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.5 LTS (Noble Numbat)
AMD EPYC 7763 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-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 16.508 ms 0.1546 ms 0.0401 ms 1.00 0.00 500.0000 500.0000 500.0000 4.02 MB 1.00
ExcelReaderWriterSharedStrings 50000 16.050 ms 0.2038 ms 0.0529 ms 0.97 0.00 500.0000 500.0000 500.0000 4.06 MB 1.01
ExcelReaderWriterPrefetch 50000 12.320 ms 2.6839 ms 0.6970 ms 0.75 0.04 484.3750 484.3750 484.3750 4.03 MB 1.00
ExcelReaderXlsbWriter 50000 10.434 ms 0.2605 ms 0.0403 ms 0.63 0.00 500.0000 500.0000 500.0000 4.02 MB 1.00
ExcelReaderXlsbWriterSharedStrings 50000 10.302 ms 0.1938 ms 0.0300 ms 0.62 0.00 500.0000 500.0000 500.0000 4.06 MB 1.01
ExcelReaderXlsbWriterPrefetch 50000 9.403 ms 0.9702 ms 0.2520 ms 0.57 0.01 484.3750 484.3750 484.3750 4.03 MB 1.00
OfficeIMO 50000 24.467 ms 0.4918 ms 0.1277 ms 1.48 0.01 312.5000 312.5000 312.5000 4.02 MB 1.00
SpreadCheetah 50000 21.526 ms 0.7055 ms 0.1832 ms 1.30 0.01 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.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-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 28.076 ms 0.2023 ms 0.0313 ms 18448 B
NativeStrings_Csv 7.399 ms 0.0922 ms 0.0240 ms 416 B
ArrowStrings_Xlsx 36.424 ms 0.8572 ms 0.2226 ms 18496 B
StyledRows_Xlsx 10.294 ms 0.1763 ms 0.0458 ms 18632 B

ExcelReader.Benchmarks.XlsReadBenchmark


BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.5 LTS (Noble Numbat)
AMD EPYC 7763 3.19GHz, 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
ExcelReader 50000 5.449 ms 0.1054 ms 0.0274 ms 1.00 - - 2.75 KB 1.00
ExcelReaderAsync 50000 4.922 ms 0.0394 ms 0.0102 ms 0.90 - - 2.82 KB 1.03
Sylvan 50000 8.953 ms 0.0864 ms 0.0224 ms 1.64 93.7500 15.6250 1717.73 KB 624.63
OfficeIMO 50000 10.396 ms 0.1577 ms 0.0244 ms 1.91 640.6250 - 10499.25 KB 3,817.91

ExcelReader.Benchmarks.XlsWriteBenchmark


BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.5 LTS (Noble Numbat)
AMD EPYC 7763 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-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 8.375 ms 0.1838 ms 0.0477 ms 1.00 484.3750 484.3750 484.3750 16.03 MB 1.00
XlsxWriter 50000 16.594 ms 0.6382 ms 0.0988 ms 1.98 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 9V45 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 40.782 ms 1.9189 ms 0.2970 ms 1.00 0.01 2285968 B 1.00
EndToEnd_Prefetch 65536 34.020 ms 3.5101 ms 0.9116 ms 0.83 0.02 2382275 B 1.04
SharedStringPrologue 65536 15.833 ms 0.1874 ms 0.0487 ms 0.39 0.00 765104 B 0.33
Stored_EndToEnd 65536 17.950 ms 0.2507 ms 0.0651 ms 0.44 0.00 2284888 B 1.00
Stored_SharedStringPrologue 65536 4.130 ms 0.1627 ms 0.0252 ms 0.10 0.00 764024 B 0.33
IndexParse_Utf8Parser 65536 2.227 ms 0.2182 ms 0.0567 ms 0.05 0.00 - 0.00
IndexParse_DigitLoop 65536 1.323 ms 0.0461 ms 0.0120 ms 0.03 0.00 - 0.00

@GabrielMarquezMatte
GabrielMarquezMatte merged commit 1161344 into master Oct 6, 2026
57 checks passed
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