Skip to content

Parallel typed CSV reads, text-based schema inference and in-memory encryption (v5.1.0) - #131

Merged
GabrielMarquezMatte merged 29 commits into
masterfrom
develop
Sep 28, 2026
Merged

GabrielMarquezMatte merged 29 commits into
masterfrom
develop

Conversation

@GabrielMarquezMatte

Copy link
Copy Markdown
Owner

Summary

  • Parallel typed CSV parsing. xl_parse_typed_ex / xl_parse_arrow_ex take a degree of
    parallelism; Python's parse_typed, to_arrow, to_record_batch and to_polars expose it as
    parallelism (1 = one thread, the default; 0 = every core). ~3.6x faster on a 160 MB CSV with
    16 threads. Other formats, and CSVs under 256 KiB, still read on one thread with the same result.
  • Schema inference from text. Excel.InferSchema(..., parseText: true), xl_infer_schema_ex
    with XL_INFER_PARSE_TEXT, and Python's infer_schema(parse_text=True) type text cells (every
    CSV field) as integers, decimals, booleans and ISO dates/date-times when the text has exactly that
    shape. Leading-zero codes, scientific notation, integers past long, padded or comma-decimal
    numbers and non-ISO dates stay strings.
  • In-memory encryption and frame writers. xl_encrypt_package_to_memory and Python's
    encrypt_package_bytes() encrypt a package without writing its plaintext to disk.
    write_arrow_to_bytes, write_pandas_to_bytes and write_polars_to_bytes complete the
    in-memory writers.
  • Performance. FastDouble parses integer and fraction digits in separate loops; the parallel
    table's columns are built concurrently; ColumnBuilder.AppendFrom is a thin per-cell dispatcher
    (-2.5% CSV, -2% XLSB sequential in AOT). The static PGO profile is regenerated.

Fixes

  • Partitioned CSV reads keep a BOM when the dialect does not detect it (also affects the existing
    parallel CSV aggregation).
  • A sequential typed CSV parse no longer reopens the file for overlapped reads it never uses
    (regression from this branch's parallel work).

Compatibility

  • No breaking changes. XL_ABI_VERSION stays 5; every new export is additive.
  • .NET: InferSchema(reader, headerRow, sampleSize) keeps its binary signature; the new overload
    adds parseText = false.
  • Not in this PR: Rust and C++ wrappers for the _ex exports and xl_encrypt_package_to_memory
    (the Rust .def is updated so the import library links).

Test plan

  • dotnet test tests/ExcelReader.Tests — 2444 passed
  • pytest python/tests against a freshly published native library — 123 passed, 1 xfailed (pre-existing)
  • AOT timings for CSV/XLSX/XLSB before and after the PGO regeneration (no format regressed)

GabrielMarquezMatte and others added 29 commits September 25, 2026 23:45
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…handle's row cursor

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…overlapped handle on Windows

A synchronous handle serializes every read on its file object, so 16 chunk readers sharing
the FileStream's handle queued behind each other (cell scan 52 -> 25 ms on a 160 MB file).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…tion's columns

The partitions were merged into the first one's builders on one thread (53 ms of a 160 MB
parse) before BuildTable copied the result again. BuildTable now concatenates every
partition's buffers into the native block once, rebasing string offsets and splicing
validity bits.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…e tight loops

The single loop checked for the dot and for leading zeros on every digit. Significant digits
are now only recounted when the raw digit count exceeds the limit, and Pow10 is a table.
Identical results to the old parser over 20M random inputs; ~3-4% on sequential CSV and
XLSX typed parses through the AOT library.
…on one thread

xl_parse_typed and xl_parse_arrow now route through ParseTypedTable with a
degree of parallelism of 1, but the chunk source was resolved before the
partition check, so every file-backed CSV parse on Windows reopened the file
for overlapped reads it never used.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
FastDouble accepts an exponent, so parseText typed a column of part codes
such as 12E4 as Float64 and parse_typed then silently read it as 120000.
Text with an e or E now stays a string, like leading-zero codes do.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…and its _ex twin

xl_parse_typed/xl_parse_typed_ex and xl_parse_arrow/xl_parse_arrow_ex were
copies apart from the degree of parallelism. Each pair now forwards to one
private helper, and the arrow path takes its cause from the caller, so
xl_parse_arrow_ex names itself in a live-session error like xl_parse_typed_ex.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
After the partitions are parsed, copying every column into its native block
ran on one thread and took about a quarter of a parallel parse. Columns now
build under Parallel.For when the parse itself ran in parallel; a sequential
parse keeps the single-threaded loop. On a 521 MB CSV with 16 threads the
parse drops from ~370 ms to ~330 ms read from a file and to ~300 ms read from
memory.

The columns block is zeroed first so a failed build frees whichever columns
finished, and the allocation hooks move from ThreadStatic to AsyncLocal so
fault-injection tests still reach the pool threads. Merging a byte-aligned
validity bitmap also copies straight into the destination instead of through
a temporary array.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The double parser was inlined into AppendFrom, so every cell of every column
type paid its eight-register prologue and stack zeroing just to be dispatched.
Int64, Float64 and Bool now append through their own methods, and
RecordValidity's no-null fast path is inlined. With the static PGO profile
regenerated for the new methods, an AOT typed parse gets ~2.5% faster on CSV
and ~2% on XLSB; XLSX is unchanged.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…t column build

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
xl_encrypt_package only takes file paths, so encrypting a workbook meant
writing its plaintext package to disk first. The new export takes the package
bytes and returns the encrypted workbook in an xl_buffer released with
xl_free_buffer, so a package from xl_write_typed_to_memory never reaches disk.
Both exports share the password length check.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
encrypt_package_bytes() encrypts a package's bytes through
xl_encrypt_package_to_memory, so write_workbook_to_bytes() plus it produces an
encrypted workbook without the plaintext touching disk.
write_arrow_to_bytes(), write_pandas_to_bytes() and write_polars_to_bytes()
are the in-memory twins of the frame writers, sharing their Arrow-to-table
conversion with the file versions.

Co-Authored-By: Claude Opus 5.5 (1M context) <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 94.75410% with 16 lines in your changes missing coverage. Please review.
✅ Project coverage is 89.47%. Comparing base (d9477aa) to head (fc5b616).

Files with missing lines Patch % Lines
src/ExcelReader.Core/Reader/Csv/CsvReader.cs 57.89% 5 Missing and 3 partials ⚠️
src/ExcelReader.Native/Typed/TypedApi.Parallel.cs 90.47% 4 Missing and 2 partials ⚠️
src/ExcelReader.Native/Typed/TypedApi.cs 98.37% 2 Missing ⚠️
❗ Your organization needs to install the Codecov GitHub app to enable full functionality.
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #131      +/-   ##
==========================================
+ Coverage   89.32%   89.47%   +0.15%     
==========================================
  Files         180      181       +1     
  Lines       13416    13611     +195     
  Branches     2462     2514      +52     
==========================================
+ Hits        11984    12179     +195     
  Misses        954      954              
  Partials      478      478              

☔ 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

Copy link
Copy Markdown

Benchmark Results

Baseline: master d9477aaa, 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.StringHeavyReadBenchmark.Xlsx_Sylvan(Rows: 65536) 182.07 ms 291.28 ms +60.0%
ExcelReader.Benchmarks.ChunkedParseBenchmark.Batched_10k(Rows: 50000) 8.87 ms 13.57 ms +53.0%
ExcelReader.Benchmarks.ChunkedParseBenchmark.WholeSheet(Rows: 50000) 8.91 ms 13.22 ms +48.5%
ExcelReader.Benchmarks.EncryptedWorkbookBenchmark.Encrypted_Stream 44.36 ms 65.03 ms +46.6%
ExcelReader.Benchmarks.EncryptedWorkbookBenchmark.Encrypted_Memory 44.61 ms 64.95 ms +45.6%
ExcelReader.Benchmarks.ChunkedParseBenchmark.Batched_1k(Rows: 50000) 9.05 ms 13.18 ms +45.6%
ExcelReader.Benchmarks.EncryptedWorkbookBenchmark.Encrypted_Stream_VerifyIntegrity 45.09 ms 65.13 ms +44.4%
ExcelReader.Benchmarks.StringHeavyReadBenchmark.Xlsx_ExcelReader_Prefetch(Rows: 65536) 37.44 ms 53.75 ms +43.6%
ExcelReader.Benchmarks.XlsxSharedStringHotPathBenchmark.Stored_EndToEnd(Rows: 65536) 21.16 ms 30.16 ms +42.5%
ExcelReader.Benchmarks.NativeRowReadBenchmark.ReadAllDecoded 59.12 ms 83.99 ms +42.1%
ExcelReader.Benchmarks.NativeTypedParseBenchmark.ParseTyped 37.47 ms 52.81 ms +40.9%
ExcelReader.Benchmarks.NativeRowReadBenchmark.NextRowBlob 39.02 ms 54.89 ms +40.7%
ExcelReader.Benchmarks.NativeRowReadBenchmark.NextRowDecoded 43.58 ms 60.12 ms +37.9%
ExcelReader.Benchmarks.XlsxSharedStringHotPathBenchmark.EndToEnd_Prefetch(Rows: 65536) 37.14 ms 50.75 ms +36.7%
ExcelReader.Benchmarks.XlsxSharedStringHotPathBenchmark.IndexParse_Utf8Parser(Rows: 65536) 2.34 ms 3.14 ms +34.5%
ExcelReader.Benchmarks.NativeTypedParseBenchmark.ParseArrow 39.61 ms 53.27 ms +34.5%
ExcelReader.Benchmarks.ReadBenchmark.OfficeIMO(Rows: 50000) 165.34 ms 218.72 ms +32.3%
ExcelReader.Benchmarks.StringHeavyReadBenchmark.Xlsx_ExcelReader(Rows: 65536) 47.95 ms 62.13 ms +29.6%
ExcelReader.Benchmarks.EncryptedWorkbookBenchmark.Large_Encrypted_OpenOnly 44.62 ms 57.09 ms +28.0%
ExcelReader.Benchmarks.EncryptedWorkbookBenchmark.Plain_Stream 59.68 µs 76.01 µs +27.4%
ExcelReader.Benchmarks.NativeRowReadBenchmark.ReadAllBlob 45.71 ms 57.93 ms +26.7%
ExcelReader.Benchmarks.StringHeavyReadBenchmark.Xlsb_ExcelReader(Rows: 65536) 42.91 ms 54.24 ms +26.4%
ExcelReader.Benchmarks.StringHeavyReadBenchmark.Xlsx_ExcelReader_Materialized(Rows: 65536) 75.03 ms 94.64 ms +26.1%
ExcelReader.Benchmarks.ParseBenchmark.OfficeIMO(Rows: 50000) 158.05 ms 198.35 ms +25.5%
ExcelReader.Benchmarks.XlsxSharedStringHotPathBenchmark.EndToEnd(Rows: 65536) 48.91 ms 61.33 ms +25.4%
ExcelReader.Benchmarks.StringHeavyReadBenchmark.Xlsb_ExcelReader_Materialized_Interned(Rows: 65536) 65.74 ms 80.37 ms +22.3%
ExcelReader.Benchmarks.StringHeavyReadBenchmark.Xlsb_ExcelReader_Memory(Rows: 65536) 42.66 ms 51.92 ms +21.7%
ExcelReader.Benchmarks.StringHeavyReadBenchmark.Xlsb_Sylvan(Rows: 65536) 77.03 ms 93.71 ms +21.6%
ExcelReader.Benchmarks.StringHeavyReadBenchmark.Xlsx_ExcelReader_Materialized_Interned(Rows: 65536) 74.94 ms 89.74 ms +19.7%
ExcelReader.Benchmarks.StringHeavyReadBenchmark.Xlsb_ExcelReader_Materialized(Rows: 65536) 67.63 ms 80.23 ms +18.6%
ExcelReader.Benchmarks.ArrowConversionBenchmark.CsvTypedWithInference(Rows: 100000) 13.96 ms 16.41 ms +17.5%
ExcelReader.Benchmarks.StringHeavyReadBenchmark.Xlsb_ExcelReader_Prefetch(Rows: 65536) 34.93 ms 40.97 ms +17.3%
ExcelReader.Benchmarks.ArrowConversionBenchmark.CsvAllString(Rows: 100000) 23.31 ms 27.16 ms +16.5%
ExcelReader.Benchmarks.CsvParallelVsSepBenchmark.Sep_Sequential(Corpus: NarrowInt) 585.37 ms 680.15 ms +16.2%
ExcelReader.Benchmarks.CsvReadBenchmark.Sep(Rows: 50000) 11.84 ms 13.72 ms +15.9%
ExcelReader.Benchmarks.EncryptedWorkbookBenchmark.Large_Encrypted_Stream 106.43 ms 123.12 ms +15.7%
ExcelReader.Benchmarks.ArrowConversionBenchmark.XlsbTyped(Rows: 100000) 18.75 ms 21.61 ms +15.3%
ExcelReader.Benchmarks.EncryptedWorkbookBenchmark.Encrypted_OpenOnly 49.90 ms 57.25 ms +14.7%
ExcelReader.Benchmarks.XlsxSharedStringHotPathBenchmark.SharedStringPrologue(Rows: 65536) 17.72 ms 19.95 ms +12.6%
ExcelReader.Benchmarks.ReadBenchmark.OfficeIMOXlsb(Rows: 50000) 15.76 ms 17.73 ms +12.5%
ExcelReader.Benchmarks.DataReaderBenchmark.DataReader_GetValue(Rows: 50000) 11.59 ms 12.96 ms +11.8%
ExcelReader.Benchmarks.XlsxSharedStringHotPathBenchmark.IndexParse_DigitLoop(Rows: 65536) 1.73 ms 1.93 ms +11.6%
ExcelReader.Benchmarks.CsvParallelVsSepBenchmark.Sep_Parallel(Corpus: NarrowInt) 455.35 ms 503.69 ms +10.6%
ExcelReader.Benchmarks.EncryptedWorkbookBenchmark.Large_Plain_Stream 53.97 ms 59.54 ms +10.3%
ExcelReader.Benchmarks.ParseBenchmark.RefStructModelSync(Rows: 50000) 15.79 ms 14.16 ms -10.4%
ExcelReader.Benchmarks.CsvParallelParseBenchmark.ConversionHeavy(Dop: 2) 1.16 s 1.03 s -11.1%
ExcelReader.Benchmarks.RealDataReadBenchmark.Xlsb_ExcelReader_Prefetch 19.88 ms 17.46 ms -12.2%
ExcelReader.Benchmarks.CsvReadBenchmark.ExcelReader(Rows: 50000) 6.81 ms 5.98 ms -12.2%
ExcelReader.Benchmarks.RealDataReadBenchmark.Xlsb_ExcelReader_Memory_Prefetch 20.08 ms 17.57 ms -12.5%
ExcelReader.Benchmarks.ParseBenchmark.ExcelParserSync(Rows: 50000) 18.37 ms 15.95 ms -13.2%
ExcelReader.Benchmarks.CsvParseBenchmark.Sep(Rows: 50000) 14.81 ms 12.72 ms -14.1%
ExcelReader.Benchmarks.ParseBenchmark.ExcelParserAsync(Rows: 50000) 19.72 ms 16.72 ms -15.2%
ExcelReader.Benchmarks.RealDataReadBenchmark.Csv_Sylvan 6.40 ms 5.40 ms -15.6%
ExcelReader.Benchmarks.RealDataReadBenchmark.Xlsb_ExcelReader_Materialized 37.89 ms 31.83 ms -16.0%
ExcelReader.Benchmarks.RealDataReadBenchmark.Csv_ExcelReader_Materialized 29.30 ms 24.31 ms -17.0%
ExcelReader.Benchmarks.RealDataReadBenchmark.Xlsb_ExcelReader 35.99 ms 29.45 ms -18.2%
ExcelReader.Benchmarks.WritePathBenchmark.NativeStrings_Csv 7.16 ms 5.85 ms -18.3%
ExcelReader.Benchmarks.RealDataReadBenchmark.Xls_ExcelReader_Materialized 17.70 ms 14.44 ms -18.4%
ExcelReader.Benchmarks.RealDataReadBenchmark.Xlsb_ExcelReader_Memory 35.70 ms 29.08 ms -18.5%
ExcelReader.Benchmarks.RealDataTypedParseBenchmark.Xlsb_ExcelParser 47.16 ms 38.33 ms -18.7%
ExcelReader.Benchmarks.RealDataReadBenchmark.Xlsb_Sylvan 43.94 ms 35.64 ms -18.9%
ExcelReader.Benchmarks.RealDataReadBenchmark.Xls_Sylvan 26.95 ms 21.76 ms -19.3%
ExcelReader.Benchmarks.WriteBenchmark.ExcelReaderWriterPrefetch(Rows: 50000) 12.82 ms 10.02 ms -21.8%
ExcelReader.Benchmarks.WriteBenchmark.OfficeIMO(Rows: 50000) 24.52 ms 19.16 ms -21.9%
ExcelReader.Benchmarks.RealDataReadBenchmark.Xls_ExcelReader 15.47 ms 12.05 ms -22.1%
ExcelReader.Benchmarks.RealDataReadBenchmark.Csv_ExcelReader 8.39 ms 6.50 ms -22.5%
ExcelReader.Benchmarks.CsvWriteBenchmark.ExcelReaderWriter(Rows: 50000) 6.53 ms 5.03 ms -23.1%
ExcelReader.Benchmarks.WriteBenchmark.ExcelReaderXlsbWriter(Rows: 50000) 10.67 ms 8.13 ms -23.8%
ExcelReader.Benchmarks.RecordWriteBenchmark.Xlsb(Rows: 50000) 10.80 ms 8.23 ms -23.8%
ExcelReader.Benchmarks.RealDataReadBenchmark.Xls_ExcelReader_Memory 15.65 ms 11.92 ms -23.9%
ExcelReader.Benchmarks.WriteBenchmark.ExcelReaderXlsbWriterSharedStrings(Rows: 50000) 10.61 ms 8.07 ms -23.9%
ExcelReader.Benchmarks.RecordWriteBenchmark.Csv(Rows: 50000) 7.05 ms 5.34 ms -24.3%
ExcelReader.Benchmarks.RealDataReadBenchmark.Xlsx_Sylvan 308.96 ms 232.66 ms -24.7%
ExcelReader.Benchmarks.RealDataReadBenchmark.Xlsm_Sylvan 309.24 ms 232.81 ms -24.7%
ExcelReader.Benchmarks.RealDataReadBenchmark.Xlsx_ExcelReader_Materialized 83.08 ms 62.51 ms -24.8%
ExcelReader.Benchmarks.RealDataReadBenchmark.Xlsm_ExcelReader_Memory 80.00 ms 60.01 ms -25.0%
ExcelReader.Benchmarks.RecordWriteBenchmark.XlsxMapped(Rows: 50000) 18.80 ms 14.06 ms -25.2%
ExcelReader.Benchmarks.RealDataReadBenchmark.Xlsm_ExcelReader 80.25 ms 59.86 ms -25.4%
ExcelReader.Benchmarks.WriteBenchmark.SpreadCheetah(Rows: 50000) 21.89 ms 16.31 ms -25.5%
ExcelReader.Benchmarks.RealDataReadBenchmark.Xlsx_ExcelReader 81.64 ms 60.74 ms -25.6%
ExcelReader.Benchmarks.RealDataReadBenchmark.Csv_ExcelReader_Memory 8.41 ms 6.25 ms -25.6%
ExcelReader.Benchmarks.CsvWriteBenchmark.Sep(Rows: 50000) 10.39 ms 7.71 ms -25.8%
ExcelReader.Benchmarks.RealDataReadBenchmark.Xlsm_ExcelReader_Materialized 83.07 ms 61.67 ms -25.8%
ExcelReader.Benchmarks.WritePathBenchmark.ArrowStrings_Xlsx 36.72 ms 27.17 ms -26.0%
ExcelReader.Benchmarks.RealDataReadBenchmark.Xlsx_ExcelReader_Memory 80.98 ms 59.82 ms -26.1%
ExcelReader.Benchmarks.RecordWriteBenchmark.XlsbMapped(Rows: 50000) 12.34 ms 9.08 ms -26.4%
ExcelReader.Benchmarks.RealDataTypedParseBenchmark.Xlsx_ExcelParser 96.28 ms 70.79 ms -26.5%
ExcelReader.Benchmarks.RealDataReadBenchmark.Xlsm_ExcelReader_Memory_Prefetch 54.76 ms 40.01 ms -26.9%
ExcelReader.Benchmarks.RecordWriteBenchmark.CsvMapped(Rows: 50000) 8.22 ms 6.00 ms -27.0%
ExcelReader.Benchmarks.WriteBenchmark.ExcelReaderWriterSharedStrings(Rows: 50000) 16.04 ms 11.68 ms -27.2%
ExcelReader.Benchmarks.CsvWriteBenchmark.SylvanWriter(Rows: 50000) 10.61 ms 7.66 ms -27.9%
ExcelReader.Benchmarks.RecordWriteBenchmark.Xlsx(Rows: 50000) 17.60 ms 12.69 ms -27.9%
ExcelReader.Benchmarks.WritePathBenchmark.StyledRows_Xlsx 10.30 ms 7.42 ms -27.9%
ExcelReader.Benchmarks.WritePathBenchmark.NativeStrings_Xlsx 28.96 ms 20.85 ms -28.0%
ExcelReader.Benchmarks.XlsWriteBenchmark.XlsxWriter(Rows: 50000) 16.17 ms 11.56 ms -28.5%
ExcelReader.Benchmarks.WriteBenchmark.ExcelReaderWriter(Rows: 50000) 16.73 ms 11.50 ms -31.2%
ExcelReader.Benchmarks.WriteBenchmark.ExcelReaderXlsbWriterPrefetch(Rows: 50000) 9.54 ms 6.36 ms -33.3%
ExcelReader.Benchmarks.RealDataReadBenchmark.Xlsx_ExcelReader_Memory_Prefetch 57.58 ms 37.56 ms -34.8%
ExcelReader.Benchmarks.RealDataReadBenchmark.Xlsx_ExcelReader_Prefetch 55.85 ms 35.97 ms -35.6%
ExcelReader.Benchmarks.XlsWriteBenchmark.XlsWriter(Rows: 50000) 8.13 ms 5.01 ms -38.3%
ExcelReader.Benchmarks.RealDataReadBenchmark.Xlsm_ExcelReader_Prefetch 55.96 ms 33.73 ms -39.7%
ExcelReader.Benchmarks.RecordWriteBenchmark.Xls(Rows: 50000) 7.93 ms 4.62 ms -41.7%

57 within ±10%.

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 27.16 ms 2.884 ms 0.749 ms 1.00 0.04 468.7500 468.7500 468.7500 16.27 MB 1.00
CsvTyped 100000 13.67 ms 0.815 ms 0.212 ms 0.50 0.01 453.1250 453.1250 453.1250 8.13 MB 0.50
XlsbTyped 100000 21.61 ms 0.242 ms 0.037 ms 0.80 0.02 437.5000 437.5000 437.5000 8.15 MB 0.50
CsvTypedWithInference 100000 16.41 ms 0.550 ms 0.143 ms 0.60 0.02 593.7500 593.7500 593.7500 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 Gen0 Gen1 Allocated Alloc Ratio
WholeSheet 50000 13.22 ms 0.107 ms 0.028 ms 1.00 78.1250 62.5000 1.31 MB 1.00
Batched_10k 50000 13.57 ms 0.087 ms 0.013 ms 1.03 93.7500 46.8750 1.6 MB 1.23
Batched_1k 50000 13.18 ms 0.047 ms 0.007 ms 1.00 93.7500 - 1.52 MB 1.16

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 41.90 ms 1.312 ms 1.289 ms 28.43 KB
RecordWriteFirstUse 200 24.75 ms 1.707 ms 1.677 ms 84.25 KB
FluentParseFirstUse 200 36.12 ms 1.107 ms 1.088 ms 30.95 KB
FluentParseWithAttributeFallbackFirstUse 200 45.46 ms 0.302 ms 0.296 ms 32.65 KB

ExcelReader.Benchmarks.CsvParallelParseBenchmark


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-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,390.5 ms 44.51 ms 11.56 ms 1.00 0.01 42000.0000 - 687055.97 KB 1.000
NarrowInt 1 748.0 ms 27.61 ms 7.17 ms 0.54 0.01 15000.0000 - 251161.02 KB 0.366
ConversionHeavyAggregate 1 1,096.4 ms 52.52 ms 8.13 ms 0.79 0.01 - - 826.38 KB 0.001
NarrowIntAggregate 1 693.2 ms 19.23 ms 2.98 ms 0.50 0.00 - - 813.38 KB 0.001
ConversionHeavy 2 1,028.5 ms 27.56 ms 7.16 ms 1.00 0.01 42000.0000 23000.0000 694999.88 KB 1.000
NarrowInt 2 667.2 ms 20.74 ms 5.39 ms 0.65 0.01 15000.0000 3000.0000 259144.1 KB 0.373
ConversionHeavyAggregate 2 713.3 ms 76.53 ms 11.84 ms 0.69 0.01 - - 1248.46 KB 0.002
NarrowIntAggregate 2 470.7 ms 25.79 ms 6.70 ms 0.46 0.01 - - 1233.95 KB 0.002
ConversionHeavy 4 741.9 ms 69.99 ms 18.18 ms 1.00 0.03 42000.0000 20000.0000 695080.21 KB 1.000
NarrowInt 4 467.1 ms 30.43 ms 7.90 ms 0.63 0.02 15000.0000 1000.0000 259255.23 KB 0.373
ConversionHeavyAggregate 4 478.9 ms 45.64 ms 7.06 ms 0.65 0.02 - - 1253.59 KB 0.002
NarrowIntAggregate 4 316.8 ms 27.38 ms 7.11 ms 0.43 0.01 - - 1239.38 KB 0.002
ConversionHeavy 8 764.1 ms 85.82 ms 22.29 ms 1.00 0.04 42000.0000 21000.0000 695235.51 KB 1.000
NarrowInt 8 474.1 ms 66.12 ms 17.17 ms 0.62 0.03 15000.0000 1000.0000 259391.35 KB 0.373
ConversionHeavyAggregate 8 462.2 ms 17.97 ms 4.67 ms 0.61 0.02 - - 1260.92 KB 0.002
NarrowIntAggregate 8 335.3 ms 84.12 ms 21.85 ms 0.44 0.03 - - 1252.27 KB 0.002
ConversionHeavy 16 719.7 ms 56.59 ms 8.76 ms 1.00 0.02 42000.0000 20000.0000 695306.02 KB 1.000
NarrowInt 16 464.4 ms 24.86 ms 3.85 ms 0.65 0.01 15000.0000 1000.0000 260066.42 KB 0.374
ConversionHeavyAggregate 16 473.5 ms 19.98 ms 5.19 ms 0.66 0.01 - - 1309.09 KB 0.002
NarrowIntAggregate 16 330.6 ms 76.35 ms 19.83 ms 0.46 0.03 - - 1303.76 KB 0.002

ExcelReader.Benchmarks.CsvParallelVsSepBenchmark


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-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 704.7 ms 4.43 ms 0.69 ms 1.00 0.00 15000.0000 - - 244.15 MB 1.00
ExcelReader_Parallel NarrowInt 468.5 ms 32.29 ms 8.39 ms 0.66 0.01 15000.0000 1000.0000 - 253.33 MB 1.04
Sep_Sequential NarrowInt 680.2 ms 26.71 ms 6.94 ms 0.97 0.01 15000.0000 - - 244.15 MB 1.00
Sep_Parallel NarrowInt 503.7 ms 154.74 ms 23.95 ms 0.71 0.03 16000.0000 12000.0000 1000.0000 251.43 MB 1.03
ExcelReader_Sequential ConversionHeavy 936.2 ms 7.71 ms 1.19 ms 1.00 0.00 29000.0000 - - 467.31 MB 1.00
ExcelReader_Parallel ConversionHeavy 503.9 ms 46.63 ms 12.11 ms 0.54 0.01 29000.0000 26000.0000 - 473.66 MB 1.01
Sep_Sequential ConversionHeavy 1,059.2 ms 71.24 ms 18.50 ms 1.13 0.02 29000.0000 - - 467.31 MB 1.00
Sep_Parallel ConversionHeavy 854.5 ms 63.60 ms 16.52 ms 0.91 0.02 36000.0000 34000.0000 6000.0000 476.99 MB 1.02

ExcelReader.Benchmarks.CsvParseBenchmark


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-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 7.450 ms 0.0995 ms 0.0154 ms 1.00 234.3750 - 3.86 MB 1.00
ExcelParserAsync 50000 7.571 ms 0.0511 ms 0.0079 ms 1.02 234.3750 - 3.86 MB 1.00
Sep 50000 12.716 ms 0.1046 ms 0.0272 ms 1.71 234.3750 - 3.87 MB 1.00
Sylvan 50000 18.526 ms 0.3140 ms 0.0815 ms 2.49 656.2500 62.5000 10.95 MB 2.84

ExcelReader.Benchmarks.CsvReadBenchmark


BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.5 LTS (Noble Numbat)
AMD EPYC 7763 2.62GHz, 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 5.984 ms 0.0299 ms 0.0078 ms 1.00 0.00 448 B 1.00
ExcelReaderWide 50000 12.525 ms 0.9844 ms 0.2556 ms 2.09 0.04 376 B 0.84
ExcelReaderAsync 50000 4.089 ms 0.0063 ms 0.0010 ms 0.68 0.00 520 B 1.16
Sep 50000 13.723 ms 0.2075 ms 0.0321 ms 2.29 0.01 4024 B 8.98
Sylvan 50000 5.933 ms 0.0220 ms 0.0034 ms 0.99 0.00 38682 B 86.34

ExcelReader.Benchmarks.CsvWriteBenchmark


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
ExcelReaderWriter 50000 5.027 ms 0.5279 ms 0.1371 ms 1.00 0.03 500.0000 500.0000 500.0000 4 MB 1.00
Sep 50000 7.710 ms 0.1443 ms 0.0223 ms 1.53 0.04 500.0000 500.0000 500.0000 4.01 MB 1.00
SylvanWriter 50000 7.655 ms 0.1489 ms 0.0230 ms 1.52 0.04 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 9.419 ms 0.0426 ms 0.0111 ms 1.00 0.00 - - - 11.18 KB 1.00
DataReader_GetValue 50000 12.958 ms 0.1453 ms 0.0377 ms 1.38 0.00 62.5000 - - 5138.82 KB 459.66
DataReader_TypedGetters 50000 12.778 ms 0.0512 ms 0.0079 ms 1.36 0.00 15.6250 - - 1623.2 KB 145.19
DataReader_GetBytes 50000 9.641 ms 0.0911 ms 0.0141 ms 1.02 0.00 - - - 11.87 KB 1.06
DataTable_Load 50000 65.154 ms 5.8148 ms 1.5101 ms 6.92 0.15 1111.1111 1000.0000 888.8889 23401.53 KB 2,093.22

ExcelReader.Benchmarks.EncryptedWorkbookBenchmark


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-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 76.01 μs 2.449 μs 0.379 μs 1.00 0.01 1.0986 19.42 KB 1.00
Encrypted_Stream 65,027.15 μs 2,737.971 μs 711.042 μs 855.51 9.38 - 48.33 KB 2.49
Encrypted_Stream_VerifyIntegrity 65,125.32 μs 567.065 μs 147.265 μs 856.80 4.18 - 50.27 KB 2.59
Encrypted_Memory 64,945.66 μs 689.442 μs 179.046 μs 854.43 4.35 - 52.77 KB 2.72
Encrypted_OpenOnly 57,245.07 μs 593.717 μs 154.186 μs 753.12 3.81 - 42.8 KB 2.20
Large_Plain_Stream 59,543.67 μs 1,598.143 μs 247.314 μs 783.36 4.54 - 11.18 KB 0.58
Large_Encrypted_Stream 123,118.33 μs 16,398.645 μs 4,258.676 μs 1,619.76 51.91 - 36.94 KB 1.90
Large_Encrypted_OpenOnly 57,086.35 μs 659.206 μs 102.013 μs 751.04 3.55 - 36.37 KB 1.87

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 RatioSD Gen0 Gen1 Gen2 Allocated Alloc Ratio
NextRowBlob 54.89 ms 0.187 ms 0.029 ms 1.00 0.00 300.0000 300.0000 300.0000 3.71 MB 1.00
NextRowDecoded 60.12 ms 0.118 ms 0.018 ms 1.10 0.00 222.2222 222.2222 222.2222 3.71 MB 1.00
ReadAllBlob 57.93 ms 1.240 ms 0.192 ms 1.06 0.00 1000.0000 888.8889 - 21.06 MB 5.68
ReadAllDecoded 83.99 ms 5.227 ms 1.358 ms 1.53 0.02 500.0000 500.0000 500.0000 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 Gen0 Gen1 Gen2 Allocated Alloc Ratio
ParseTyped 52.81 ms 0.698 ms 0.181 ms 1.00 700.0000 500.0000 300.0000 11.61 MB 1.00
ParseArrow 53.27 ms 0.320 ms 0.050 ms 1.01 700.0000 500.0000 300.0000 11.62 MB 1.00

ExcelReader.Benchmarks.ParseBenchmark


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-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 15.95 ms 0.078 ms 0.020 ms 1.00 0.00 218.7500 3966.8 KB 1.000
ExcelParserSyncSharedStrings 50000 15.45 ms 0.064 ms 0.010 ms 0.97 0.00 140.6250 2357.3 KB 0.594
ExcelParserStructSync 50000 15.40 ms 0.185 ms 0.048 ms 0.97 0.00 93.7500 1623.05 KB 0.409
RefStructModelSync 50000 14.16 ms 0.040 ms 0.006 ms 0.89 0.00 - 11.72 KB 0.003
ExcelParserAsync 50000 16.72 ms 0.062 ms 0.010 ms 1.05 0.00 218.7500 3968.95 KB 1.001
ExcelParserXlsbSync 50000 12.34 ms 0.472 ms 0.122 ms 0.77 0.01 234.3750 3968.9 KB 1.001
ExcelParserXlsbAsync 50000 12.36 ms 0.039 ms 0.010 ms 0.78 0.00 234.3750 3971.47 KB 1.001
OfficeIMO 50000 198.35 ms 136.593 ms 35.473 ms 12.44 2.03 - 5858.15 KB 1.477
Sylvan 50000 87.21 ms 15.328 ms 3.981 ms 5.47 0.23 - 10726.71 KB 2.704
SylvanAsync 50000 85.40 ms 5.602 ms 1.455 ms 5.36 0.08 - 10727.74 KB 2.704

ExcelReader.Benchmarks.ReadBenchmark


BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.5 LTS (Noble Numbat)
AMD EPYC 7763 2.62GHz, 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.427 ms 0.1088 ms 0.0168 ms 1.00 0.00 - 11.18 KB 1.00
ExcelReaderAsync 50000 12.409 ms 0.0323 ms 0.0050 ms 1.09 0.00 - 13.31 KB 1.19
ExcelReaderXlsb 50000 7.348 ms 0.2012 ms 0.0311 ms 0.64 0.00 - 13.28 KB 1.19
ExcelReaderXlsbAsync 50000 7.981 ms 0.0865 ms 0.0225 ms 0.70 0.00 - 15.84 KB 1.42
ExcelReaderMaterialized 50000 13.292 ms 0.0518 ms 0.0135 ms 1.16 0.00 93.7500 1622.51 KB 145.13
Sylvan 50000 55.772 ms 0.4923 ms 0.0762 ms 4.88 0.01 - 1939.18 KB 173.46
OfficeIMO 50000 218.723 ms 232.4554 ms 60.3679 ms 19.14 4.85 - 7003.68 KB 626.46
OfficeIMOXlsb 50000 17.729 ms 0.0734 ms 0.0191 ms 1.55 0.00 406.2500 6858.72 KB 613.50

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 60.739 ms 4.5183 ms 1.1734 ms 1.00 0.02 - 18291 B 1.00
Xlsx_Sylvan 232.665 ms 1.7388 ms 0.4516 ms 3.83 0.07 - 659448 B 36.05
Xlsx_ExcelReader_Materialized 62.507 ms 0.8058 ms 0.1247 ms 1.03 0.02 - 27990 B 1.53
Xlsx_ExcelReader_Prefetch 35.970 ms 12.6361 ms 3.2816 ms 0.59 0.05 - 29596 B 1.62
Xlsx_ExcelReader_Memory 59.820 ms 0.2377 ms 0.0617 ms 0.99 0.02 - 7179 B 0.39
Xlsx_ExcelReader_Memory_Prefetch 37.559 ms 16.2277 ms 4.2143 ms 0.62 0.06 - 14867 B 0.81
Xlsm_ExcelReader 59.860 ms 0.3360 ms 0.0873 ms 0.99 0.02 - 19664 B 1.08
Xlsm_Sylvan 232.815 ms 9.6141 ms 2.4968 ms 3.83 0.08 - 659528 B 36.06
Xlsm_ExcelReader_Materialized 61.667 ms 0.3837 ms 0.0594 ms 1.02 0.02 - 27990 B 1.53
Xlsm_ExcelReader_Prefetch 33.728 ms 4.0393 ms 1.0490 ms 0.56 0.02 - 31377 B 1.72
Xlsm_ExcelReader_Memory 60.008 ms 0.5323 ms 0.1382 ms 0.99 0.02 - 7179 B 0.39
Xlsm_ExcelReader_Memory_Prefetch 40.012 ms 23.4334 ms 6.0856 ms 0.66 0.09 - 21400 B 1.17
Xlsb_ExcelReader 29.453 ms 0.4849 ms 0.0750 ms 0.49 0.01 - 19256 B 1.05
Xlsb_Sylvan 35.637 ms 1.3697 ms 0.3557 ms 0.59 0.01 - 346670 B 18.95
Xlsb_ExcelReader_Materialized 31.829 ms 0.1802 ms 0.0279 ms 0.52 0.01 - 28952 B 1.58
Xlsb_ExcelReader_Prefetch 17.463 ms 1.0287 ms 0.1592 ms 0.29 0.01 - 36098 B 1.97
Xlsb_ExcelReader_Memory 29.084 ms 0.1168 ms 0.0181 ms 0.48 0.01 - 8896 B 0.49
Xlsb_ExcelReader_Memory_Prefetch 17.574 ms 0.9866 ms 0.2562 ms 0.29 0.01 - 24628 B 1.35
Xls_ExcelReader 12.054 ms 0.2651 ms 0.0410 ms 0.20 0.00 - 11576 B 0.63
Xls_Sylvan 21.758 ms 0.3603 ms 0.0936 ms 0.36 0.01 - 190366 B 10.41
Xls_ExcelReader_Materialized 14.441 ms 0.7039 ms 0.1828 ms 0.24 0.00 - 21272 B 1.16
Xls_ExcelReader_Memory 11.918 ms 0.0048 ms 0.0007 ms 0.20 0.00 - 11576 B 0.63
Csv_ExcelReader 6.500 ms 0.1310 ms 0.0340 ms 0.11 0.00 - 376 B 0.02
Csv_Sylvan 5.402 ms 0.1680 ms 0.0436 ms 0.09 0.00 - 41226 B 2.25
Csv_ExcelReader_Materialized 24.313 ms 0.5176 ms 0.1344 ms 0.40 0.01 2218.7500 37442984 B 2,047.07
Csv_ExcelReader_Memory 6.254 ms 0.0131 ms 0.0020 ms 0.10 0.00 - 312 B 0.02

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 Gen0 Allocated Alloc Ratio
Xlsx_ExcelParser 70.79 ms 1.872 ms 0.486 ms 1.00 428.5714 8.03 MB 1.00
Xlsb_ExcelParser 38.33 ms 0.691 ms 0.107 ms 0.54 500.0000 8.03 MB 1.00

ExcelReader.Benchmarks.RecordWriteBenchmark


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 50000 12.688 ms 0.7088 ms 0.1841 ms 1.00 0.02 500.0000 500.0000 500.0000 4.02 MB 1.00
Xlsb 50000 8.234 ms 0.1197 ms 0.0311 ms 0.65 0.01 500.0000 500.0000 500.0000 4.02 MB 1.00
Xls 50000 4.619 ms 0.1693 ms 0.0440 ms 0.36 0.01 273.4375 273.4375 273.4375 4.03 MB 1.00
Csv 50000 5.337 ms 0.4115 ms 0.1069 ms 0.42 0.01 500.0000 500.0000 500.0000 4 MB 1.00
XlsxMapped 50000 14.060 ms 0.6694 ms 0.1738 ms 1.11 0.02 500.0000 500.0000 500.0000 4.02 MB 1.00
XlsbMapped 50000 9.082 ms 0.7437 ms 0.1931 ms 0.72 0.02 500.0000 500.0000 500.0000 4.02 MB 1.00
CsvMapped 50000 6.001 ms 0.1018 ms 0.0157 ms 0.47 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 7763 2.61GHz, 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_ExcelReader 65536 62.13 ms 1.544 ms 0.401 ms 1.00 0.01 - - - 2.19 MB 1.00
Xlsx_ExcelReader_Prefetch 65536 53.75 ms 25.857 ms 4.001 ms 0.87 0.06 - - - 2.25 MB 1.03
Xlsx_Sylvan 65536 291.28 ms 28.294 ms 7.348 ms 4.69 0.11 500.0000 - - 17.41 MB 7.96
Xlsx_ExcelReader_Materialized 65536 94.64 ms 9.398 ms 2.441 ms 1.52 0.04 833.3333 666.6667 166.6667 15.26 MB 6.97
Xlsx_ExcelReader_Materialized_Interned 65536 89.74 ms 5.541 ms 0.857 ms 1.44 0.01 833.3333 666.6667 166.6667 15.26 MB 6.98
Xlsb_ExcelReader 65536 54.24 ms 0.733 ms 0.190 ms 0.87 0.01 - - - 2.19 MB 1.00
Xlsb_ExcelReader_Prefetch 65536 40.97 ms 2.069 ms 0.320 ms 0.66 0.01 - - - 2.3 MB 1.05
Xlsb_Sylvan 65536 93.71 ms 15.913 ms 2.463 ms 1.51 0.04 1166.6667 1000.0000 333.3333 17.38 MB 7.94
Xlsb_ExcelReader_Materialized 65536 80.23 ms 6.286 ms 1.633 ms 1.29 0.03 833.3333 666.6667 166.6667 15.26 MB 6.97
Xlsb_ExcelReader_Materialized_Interned 65536 80.37 ms 1.922 ms 0.297 ms 1.29 0.01 1000.0000 857.1429 285.7143 15.27 MB 6.98
Xlsb_ExcelReader_Memory 65536 51.92 ms 0.611 ms 0.095 ms 0.84 0.01 - - - 6.47 MB 2.95

ExcelReader.Benchmarks.WriteBenchmark


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
ExcelReaderWriter 50000 11.505 ms 0.0585 ms 0.0090 ms 1.00 0.00 500.0000 500.0000 500.0000 4.02 MB 1.00
ExcelReaderWriterSharedStrings 50000 11.676 ms 0.0602 ms 0.0156 ms 1.01 0.00 500.0000 500.0000 500.0000 4.06 MB 1.01
ExcelReaderWriterPrefetch 50000 10.018 ms 1.0251 ms 0.2662 ms 0.87 0.02 484.3750 484.3750 484.3750 4.03 MB 1.00
ExcelReaderXlsbWriter 50000 8.132 ms 0.4537 ms 0.1178 ms 0.71 0.01 500.0000 500.0000 500.0000 4.02 MB 1.00
ExcelReaderXlsbWriterSharedStrings 50000 8.070 ms 1.2153 ms 0.3156 ms 0.70 0.03 500.0000 500.0000 500.0000 4.06 MB 1.01
ExcelReaderXlsbWriterPrefetch 50000 6.360 ms 0.7341 ms 0.1906 ms 0.55 0.02 492.1875 492.1875 492.1875 4.03 MB 1.00
OfficeIMO 50000 19.157 ms 1.2157 ms 0.3157 ms 1.67 0.03 312.5000 312.5000 312.5000 4.02 MB 1.00
SpreadCheetah 50000 16.307 ms 0.1793 ms 0.0466 ms 1.42 0.00 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 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 Allocated
NativeStrings_Xlsx 20.849 ms 0.0884 ms 0.0137 ms 18448 B
NativeStrings_Csv 5.847 ms 0.0297 ms 0.0077 ms 416 B
ArrowStrings_Xlsx 27.173 ms 0.0885 ms 0.0230 ms 18496 B
StyledRows_Xlsx 7.424 ms 0.0434 ms 0.0067 ms 18632 B

ExcelReader.Benchmarks.XlsReadBenchmark


BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.5 LTS (Noble Numbat)
AMD EPYC 7763 2.62GHz, 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 4.964 ms 0.0109 ms 0.0028 ms 1.00 - - 2.45 KB 1.00
ExcelReaderAsync 50000 5.181 ms 0.0330 ms 0.0086 ms 1.04 - - 2.52 KB 1.03
Sylvan 50000 8.609 ms 0.2602 ms 0.0676 ms 1.73 93.7500 15.6250 1717.73 KB 700.22
OfficeIMO 50000 10.399 ms 0.1534 ms 0.0237 ms 2.09 640.6250 - 10499.25 KB 4,279.95

ExcelReader.Benchmarks.XlsWriteBenchmark


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
XlsWriter 50000 5.013 ms 0.0855 ms 0.0222 ms 1.00 0.01 492.1875 492.1875 492.1875 16.03 MB 1.00
XlsxWriter 50000 11.562 ms 0.3936 ms 0.1022 ms 2.31 0.02 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 7763 2.61GHz, 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 Allocated Alloc Ratio
EndToEnd 65536 61.331 ms 0.3712 ms 0.0574 ms 1.00 2294168 B 1.00
EndToEnd_Prefetch 65536 50.753 ms 6.6185 ms 1.0242 ms 0.83 2391668 B 1.04
SharedStringPrologue 65536 19.949 ms 0.2593 ms 0.0674 ms 0.33 773304 B 0.34
Stored_EndToEnd 65536 30.158 ms 0.5432 ms 0.1411 ms 0.49 2293088 B 1.00
Stored_SharedStringPrologue 65536 4.872 ms 0.1677 ms 0.0435 ms 0.08 772224 B 0.34
IndexParse_Utf8Parser 65536 3.145 ms 0.0147 ms 0.0038 ms 0.05 - 0.00
IndexParse_DigitLoop 65536 1.925 ms 0.0322 ms 0.0084 ms 0.03 - 0.00

@GabrielMarquezMatte
GabrielMarquezMatte merged commit 72c5781 into master Sep 28, 2026
58 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