Skip to content

Conversation

@NightOwl888
Copy link
Contributor

  • You've read the Contributor Guide and Code of Conduct.
  • You've included unit or integration tests for your change, where applicable.
  • You've included inline docs for your change, where applicable.
  • There's an open issue for the PR that you are making. If you'd like to propose a change, please open an issue to discuss the change or find an existing issue.

Lucene.Net.Store (DataInput + DataOutput): Use stack or array pool for temporary byte buffers

Description

This optimizes the temporary buffers used when converting between UTF16 and UTF8 by putting them on the stack with fallback to the array pool for large strings.

Benchmarks

I increased the payload to 100 string fields per document (a GUID value) and this was the result. The biggest impact is the amount allocated while writing an index.

Index Files

BenchmarkDotNet=v0.12.1, OS=Windows 10.0.19045
Intel Core i7-8850H CPU 2.60GHz (Coffee Lake), 1 CPU, 12 logical and 6 physical cores
.NET Core SDK=9.0.304
  [Host]              : .NET Core 8.0.19 (CoreCLR 8.0.1925.36514, CoreFX 8.0.1925.36514), X64 RyuJIT
  000-4.8.0-beta00014 : .NET Core 8.0.19 (CoreCLR 8.0.1925.36514, CoreFX 8.0.1925.36514), X64 RyuJIT
  001-4.8.0-beta00015 : .NET Core 8.0.19 (CoreCLR 8.0.1925.36514, CoreFX 8.0.1925.36514), X64 RyuJIT
  002-4.8.0-beta00016 : .NET Core 8.0.19 (CoreCLR 8.0.1925.36514, CoreFX 8.0.1925.36514), X64 RyuJIT
  003-4.8.0-beta00017 : .NET Core 8.0.19 (CoreCLR 8.0.1925.36514, CoreFX 8.0.1925.36514), X64 RyuJIT
  004-1 - before      : .NET Core 8.0.19 (CoreCLR 8.0.1925.36514, CoreFX 8.0.1925.36514), X64 RyuJIT
  005-2 - unicodeutil : .NET Core 8.0.19 (CoreCLR 8.0.1925.36514, CoreFX 8.0.1925.36514), X64 RyuJIT
  006-3 - utf8        : .NET Core 8.0.19 (CoreCLR 8.0.1925.36514, CoreFX 8.0.1925.36514), X64 RyuJIT

InvocationCount=1  IterationCount=15  LaunchCount=2  
UnrollFactor=1  WarmupCount=10  
Method Job NuGetReferences Mean Error StdDev Gen 0 Gen 1 Gen 2 Allocated
IndexFiles 000-4.8.0-beta00014 Lucene.Net.Analysis.Common 4.8.0-beta00014 1,006.4 ms 53.97 ms 79.11 ms 44000.0000 7000.0000 6000.0000 231.96 MB
IndexFiles 001-4.8.0-beta00015 Lucene.Net.Analysis.Common 4.8.0-beta00015 725.8 ms 28.72 ms 41.19 ms 44000.0000 7000.0000 6000.0000 232 MB
IndexFiles 002-4.8.0-beta00016 Lucene.Net.Analysis.Common 4.8.0-beta00016 734.8 ms 33.88 ms 48.59 ms 44000.0000 7000.0000 6000.0000 232.05 MB
IndexFiles 003-4.8.0-beta00017 Lucene.Net.Analysis.Common 4.8.0-beta00017 710.4 ms 50.10 ms 71.85 ms 44000.0000 8000.0000 7000.0000 223.4 MB
IndexFiles 004 - before Lucene.Net.Analysis.Common 4.8.0-ci0000003128 780.6 ms 42.24 ms 63.22 ms 44000.0000 8000.0000 7000.0000 223.08 MB
IndexFiles 005 - after Lucene.Net.Analysis.Common 4.8.0-ci0000003129 734.2 ms 29.08 ms 42.63 ms 43000.0000 8000.0000 7000.0000 217.16 MB

ReadStoredFields

BenchmarkDotNet=v0.12.1, OS=Windows 10.0.19045
Intel Core i7-8850H CPU 2.60GHz (Coffee Lake), 1 CPU, 12 logical and 6 physical cores
.NET Core SDK=9.0.304
  [Host]              : .NET Core 8.0.19 (CoreCLR 8.0.1925.36514, CoreFX 8.0.1925.36514), X64 RyuJIT
  000-4.8.0-beta00014 : .NET Core 8.0.19 (CoreCLR 8.0.1925.36514, CoreFX 8.0.1925.36514), X64 RyuJIT
  001-4.8.0-beta00015 : .NET Core 8.0.19 (CoreCLR 8.0.1925.36514, CoreFX 8.0.1925.36514), X64 RyuJIT
  002-4.8.0-beta00016 : .NET Core 8.0.19 (CoreCLR 8.0.1925.36514, CoreFX 8.0.1925.36514), X64 RyuJIT
  003-4.8.0-beta00017 : .NET Core 8.0.19 (CoreCLR 8.0.1925.36514, CoreFX 8.0.1925.36514), X64 RyuJIT
  004-1 - before      : .NET Core 8.0.19 (CoreCLR 8.0.1925.36514, CoreFX 8.0.1925.36514), X64 RyuJIT
  005-2 - unicodeutil : .NET Core 8.0.19 (CoreCLR 8.0.1925.36514, CoreFX 8.0.1925.36514), X64 RyuJIT
  006-3 - utf8        : .NET Core 8.0.19 (CoreCLR 8.0.1925.36514, CoreFX 8.0.1925.36514), X64 RyuJIT

IterationCount=15  LaunchCount=2  WarmupCount=10  
Method Job NuGetReferences Mean Error StdDev Gen 0 Gen 1 Gen 2 Allocated
ReadStoredFields 000-4.8.0-beta00014 Lucene.Net.Analysis.Common 4.8.0-beta00014,Lucene.Net.QueryParser 4.8.0-beta00014 104.2 ms 1.90 ms 2.79 ms 6200.0000 200.0000 - 29.37 MB
ReadStoredFields 001-4.8.0-beta00015 Lucene.Net.Analysis.Common 4.8.0-beta00015,Lucene.Net.QueryParser 4.8.0-beta00015 104.7 ms 2.26 ms 3.38 ms 6200.0000 200.0000 - 29.37 MB
ReadStoredFields 002-4.8.0-beta00016 Lucene.Net.Analysis.Common 4.8.0-beta00016,Lucene.Net.QueryParser 4.8.0-beta00016 103.8 ms 1.81 ms 2.65 ms 6200.0000 200.0000 - 29.37 MB
ReadStoredFields 003-4.8.0-beta00017 Lucene.Net.Analysis.Common 4.8.0-beta00017,Lucene.Net.QueryParser 4.8.0-beta00017 104.9 ms 1.71 ms 2.34 ms 6200.0000 200.0000 - 29.37 MB
ReadStoredFields 004 - before Lucene.Net.Analysis.Common 4.8.0-ci0000003128,Lucene.Net.QueryParser 4.8.0-ci0000003128 278.9 ms 10.73 ms 15.39 ms 6000.0000 1000.0000 - 29.37 MB
ReadStoredFields 005 - after Lucene.Net.Analysis.Common 4.8.0-ci0000003129,Lucene.Net.QueryParser 4.8.0-ci0000003129 293.6 ms 6.68 ms 9.57 ms 6000.0000 1000.0000 - 29.35 MB

…cepts spans for both input and output. Also added a GetMaxByteCount() method to determine the amount of buffer to allocate.
…hars() method that accepts a span and moved allocations to the stack or array pool for buffer reuse.
@NightOwl888 NightOwl888 requested a review from paulirwin October 6, 2025 19:40
@NightOwl888 NightOwl888 added the notes:performance-improvement Contains a performance improvement label Oct 6, 2025
@NightOwl888 NightOwl888 marked this pull request as ready for review October 6, 2025 19:40
Copy link
Contributor

@paulirwin paulirwin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me. My only comment is that in general, I think these methods could use unit tests.

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

Labels

notes:performance-improvement Contains a performance improvement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants