Optimize AlignmentPatterns - #699
Conversation
📝 WalkthroughWalkthroughThe PR replaces dictionary-backed alignment data with version-indexed point arrays, changes point coordinates to bytes, and updates alignment pattern placement to consume arrays and render reserved 5×5 regions by row. ChangesAlignment pattern pipeline
Estimated code review effort: 3 (Moderate) | ~20 minutes Possibly related PRs
Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Quoting coderabbitai:
No actionable comments were generated in the recent review. 🎉
😃 one AI hasn't found something reviewing a other AI1...(same model in the background?).
Footnotes
-
note the "Summary by CodeRabbit" in the TOP got added later on by CodeRabbit. ↩
Not sure what "other AI" you're referring to? No AI was used in making this PR, nor its description. |
Makes sense, but should we leave the IEquatable implementation anyway? It really hurts performance if needed and missing. See #509 (comment) But if unneeded we can remove it .... |
The Finally, benchmarks show an improvement in performance, not a regression. |
|
Fair. Just indicating that
to help prevent the same mistake in the future. |
Summary
This PR applies a round of optimizations to the calculation and placement of alignment patterns.
First, several improvements reduce the amount of memory allocated by
CreateAlignmentPatternTable:AlignmentPatternstructure has been removed. It was wrapper around a list of Points and aVersionproperty. As theVersionproperty wasn't used, there is no need for the structure.Pointstructure has been reduced from twointproperties to twobyteproperties. Given that the result of the method is essentially a table of Points, this reduces the amount of memory needed to store the actual data by a factor 4.List<Point>toPoint[].All of the above contribute to less memory being needed to store the result and keep it referenced for later usage. In addition, some memory allocations have been reduced in the process to produce that result:
alignmentPatternBaseValuesis avoided. It's values are now bytes instead of ints.List<Point>is used as a buffer to store intermediate results, instead of a list per version.Some changes have been made to reduce execution time:
pointsintermediate list has been removed. As a result, theIEquatable<Point>implementation is no longer needed and removed.alignmentPatternBaseValuesare now the coordinates of the upper left corners of the alignment patters, not the center points. This saves two substractions per point.I ran a simple benchmark to measure the results.
On master:
This PR:
Memory allocations have been reduced by a factor 6. Even though the method is executed only once, it's nice to see that it is now 7 times faster. More optimizations are possible but deemed unnecessary, as they would also reduce the readability of the code.
Secondly, some improvements have been made to the
PlaceAlignmentPatternsmethod.Obviously, placement already benefits from the fact that
AlignmentPatterns.FromVersionnow returns aPoint[]instead of (a struct around) aList<Point>, and does so by indexing into an array instead of a dictionary.On top of that:
yandxloops have been swapped to improve data locality, and avoid redundant indexing into theModuleMatrixarray.xloop has been unrolled, primarily to reduce branches and branch mispredictions.alignmentPatternRectis avoided.The results are visible in the existing
QRCodeGeneratorBenchmark.On master:
This PR:
Test plan
All modified code is exercised by existing unit tests. Benchmarks show the performance benefit.
Summary by CodeRabbit