Skip to content

Performance improvements - #509

Merged
codebude merged 32 commits into
masterfrom
performance
May 3, 2024
Merged

Performance improvements#509
codebude merged 32 commits into
masterfrom
performance

Conversation

@Shane32

@Shane32 Shane32 commented Apr 30, 2024

Copy link
Copy Markdown
Owner

System

BenchmarkDotNet v0.13.12, Windows 10 (10.0.19045.4291/22H2/2022Update)
13th Gen Intel Core i9-13900K, 1 CPU, 32 logical and 24 physical cores
.NET SDK 8.0.202
  [Host]     : .NET 8.0.3 (8.0.324.11423), X64 RyuJIT AVX2
  DefaultJob : .NET 8.0.3 (8.0.324.11423), X64 RyuJIT AVX2

Before

Method Mean Error StdDev Gen0 Gen1 Allocated
CreateQRCode 245.4 us 4.88 us 5.80 us 17.0898 0.2441 317.99 KB
CreateQRCodeLong 7,531.1 us 34.13 us 31.92 us 265.6250 15.6250 4920.13 KB

After

Method Mean Error StdDev Gen0 Allocated
CreateQRCode 100.7 us 0.26 us 0.22 us 1.2207 23.18 KB
CreateQRCodeLong 1,842.1 us 3.19 us 2.83 us 23.4375 433.53 KB

Notes

Most of the performance improvements in this PR fall into a few categories:

  • Use BitArray instead of string
  • Eliminate concatenation and instead write/copy into buffers using offsets and counts
  • Preallocation of arrays/lists to proper length
  • Eliminate array allocation when unnecessary (e.g. don't call AddRange)
  • Eliminate LINQ use
  • Improve lookup tables / dictionaries

Progress

So far about half the code has been converted to use BitArray. There is still a notable amount of code that still uses strings that remains to be optimized. Also the Polynom class/constructor is heavily used and should be optimized.

Comment thread QRCoder/QRCodeGenerator.cs Outdated
Comment thread QRCoder/QRCodeGenerator.cs
Comment thread QRCoder/QRCodeGenerator.cs
@Shane32

Shane32 commented Apr 30, 2024

Copy link
Copy Markdown
Owner Author

FYI, I have not yet gone back through all my changes to add comments and perform a self-review, etc.

@Shane32

Shane32 commented Apr 30, 2024

Copy link
Copy Markdown
Owner Author

By the way, I plan to attempt using ArrayPool for further optimizations but not in this PR.

@Shane32

Shane32 commented May 1, 2024

Copy link
Copy Markdown
Owner Author

@codebude I think this PR has enough changes. The GitHub comparison should be reasonable enough to follow. I would like to follow up with some other PRs:

  • Improve readability (code comments, rename variables, split into multiple files, etc)
  • Fix bug (?) with string handling
  • Utilize ArrayPool and other memory optimizations

@Shane32 Shane32 changed the title [WIP] Performance improvements Performance improvements May 1, 2024
@Shane32

Shane32 commented May 1, 2024

Copy link
Copy Markdown
Owner Author

The benchmarks are updated in the PR description, showing 60-75% memory reduction and 100-400% speed increase. Notably, Gen1 collections have been reduced enough that BenchmarkDotNet has stopped listing them!

Most likely further PRs will further reduce memory requirements, but not increase speed.

@Shane32

Shane32 commented May 1, 2024

Copy link
Copy Markdown
Owner Author

I'm not planning to re-engineer the mathematics, like to use vector math or anything. While I'm sure it's possible, that's not my forte.

Comment thread QRCoder/QRCodeGenerator.cs Outdated
Comment thread QRCoder/QRCodeGenerator.cs Outdated
Comment thread QRCoder/QRCodeGenerator.cs Outdated
Comment thread QRCoder/QRCodeGenerator.cs Outdated
Comment thread QRCoder/QRCodeGenerator.cs Outdated
Comment thread QRCoder/QRCodeGenerator.cs Outdated
Comment thread QRCoder/QRCodeGenerator.cs Outdated
Comment thread QRCoder/QRCodeGenerator.cs Outdated
Comment thread QRCoder/QRCodeGenerator.cs Outdated
Comment thread QRCoder/QRCodeGenerator.cs Outdated
Shane32 and others added 5 commits May 2, 2024 08:55
Co-authored-by: Günther Foidl <gue@korporal.at>
Co-authored-by: Günther Foidl <gue@korporal.at>
Co-authored-by: Günther Foidl <gue@korporal.at>
Co-authored-by: Günther Foidl <gue@korporal.at>
Co-authored-by: Günther Foidl <gue@korporal.at>
@Shane32

Shane32 commented May 3, 2024

Copy link
Copy Markdown
Owner Author

Benchmarks updated. New test results shaved 10us (10%) from short test and 20us (1%) from long test.

@Shane32

Shane32 commented May 3, 2024

Copy link
Copy Markdown
Owner Author

Eliminating foreach across a BitArray and implementing IEquatable for Point cut down memory requirements for small QR codes by an additional 80%, and an additional 60% for large QR codes.

@codebude

codebude commented May 3, 2024

Copy link
Copy Markdown
Collaborator

Benchmarks updated. New test results shaved 10us (10%) from short test and 20us (1%) from long test.

But memory usage improved massively. :-)

@Shane32

Shane32 commented May 3, 2024

Copy link
Copy Markdown
Owner Author

While all beneficial changes, the memory usage didn't change due to the arithmetic/ref/pointer changes; it measured as identical. The memory usage changes were due to foreach across a BitArray internally cast a bool to an object causing a heap allocation for each bit. Ditto for List<Point>.Contains due to Point not implementing IEquatable. These were accessed across some 'hot' code, and so many unnecessary heap allocations were made.

@gfoidl gfoidl left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

A few nits, otherwise LGTM 👍🏻

Comment thread QRCoder/QRCodeGenerator.cs Outdated
Comment thread QRCoder/QRCodeGenerator.cs Outdated
Comment thread QRCoder/QRCodeGenerator.cs Outdated
@Shane32
Shane32 requested review from codebude and gfoidl May 3, 2024 14:15
@codebude
codebude self-requested a review May 3, 2024 14:37
@codebude
codebude merged commit e36d34d into Shane32:master May 3, 2024
@codebude

codebude commented May 3, 2024

Copy link
Copy Markdown
Collaborator

Merged. Thanks for your great work @Shane32 & @gfoidl ! 👏

@Shane32
Shane32 deleted the performance branch May 3, 2024 18:51
@Shane32 Shane32 added the performance Performance related enhancements or benchmarks label Oct 2, 2025
@Shane32 Shane32 added this to the 1.6.0 milestone Oct 8, 2025
vaernion pushed a commit to Arbeidstilsynet/brevgen2 that referenced this pull request Dec 3, 2025
This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
| [QRCoder](https://github.com/codebude/QRCoder) | `1.4.3` -> `1.6.0` | [![age](https://developer.mend.io/api/mc/badges/age/nuget/QRCoder/1.6.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/nuget/QRCoder/1.6.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/nuget/QRCoder/1.4.3/1.6.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/nuget/QRCoder/1.4.3/1.6.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) |

---

### Release Notes

<details>
<summary>codebude/QRCoder (QRCoder)</summary>

### [`v1.6.0`](https://github.com/codebude/QRCoder/releases/tag/v1.6.0)

#### What has changed

-   \[Enhancement] Huge performance (runtime and memory) optimization in `QrCodeGenerator` (PRs [#&#8203;509](Shane32/QRCoder#509), [#&#8203;519](Shane32/QRCoder#519), [#&#8203;520](Shane32/QRCoder#520), [#&#8203;521](Shane32/QRCoder#521), [#&#8203;524](Shane32/QRCoder#524), [#&#8203;530](Shane32/QRCoder#530), [#&#8203;532](Shane32/QRCoder#532))
-   \[Enhancement] Big performance (runtime and memory) optimization in `BitmapByteQRCode` (PR [#&#8203;566](Shane32/QRCoder#566))
-   \[Enhancement] Added ECC level mismatch detection when using payloads from payload generator (PR [#&#8203;526](Shane32/QRCoder#526))
-   \[Enhancement] Implementation of encoding constraints (EccLevel, EciMode) in SwissQRCode and GiroCode payloads to enforce that the payloads comply with the specifications of the respective standards (PR [#&#8203;533](Shane32/QRCoder#533))
-   \[Enhancement] Added support for trimming (`IsTrimmable` project property) (PR [#&#8203;539](Shane32/QRCoder#539))
-   \[Enhancement] Added XML comments (code documentation) to all public members (PR [#&#8203;561](Shane32/QRCoder#561))
-   \[Enhancement] Added new/third overload to `PngByteQRCode` that accepts colors as System.Drawing.Color (PR [#&#8203;564](Shane32/QRCoder#564))
-   \[Enhancement] Updated the Bitmap header from BITMAPCOREHEADER to BITMAPINFOHEADER in `BitmapByteQRCode` (PR [#&#8203;565](Shane32/QRCoder#565))
-   \[Refactoring] Restructured `QRCodeGenerator` classes into separate files and partially restructured code for better manageability (PRs [#&#8203;516](Shane32/QRCoder#516), [#&#8203;528](Shane32/QRCoder#528), [#&#8203;531](https://github....
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

performance Performance related enhancements or benchmarks

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants