New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Create array in-place without an intermediate Vec #1
Conversation
Thank you! As I mentioned on Reddit, I'm going to sit on this one for now. It looks like a great contribution, but unfortunately I simply lack the knowledge and experience right now to fully understand the safety of this code, and won't feel comfortable about merging it until I do. |
It might help to know that the safety analysis is based on (i.e. copied verbatim from) the MaybeUninit documentation that shows how to do the exact same thing, only for arrays of fixed size, and without the serde part. So one could say that, if not the actual code, the approach was vetted by experts. The biggest difference is that the code in the PR drops the already-deserialized array elements in case of error. |
I was curious about the actual performance difference, and had a few minutes this morning so whipped up a quick benchmark:
I'm not sure what it means that there's significantly more "outliers" with the MaybeUninit array (this is consistent across multiple runs), but the time speaks volumes about the benefits of this approach! |
That's really impressive. Although it's not surprising that allocation would take about 20ns, whereas writing into the array directly would be (almost) free, it's different to see it in actual measurement. What array sizes did you use for the benchmark, and what was the serialization format? |
I've now pushed a commit to the PR that avoids the whole dropping loop if On an unrelated note, I now see that the document example proceeds to drop the initialized elements using |
I've now pushed another commit to the PR, which extracts the "array-filling" functionality into a separate function and provides both a safe version (containing your original code, which is really elegant) and my unsafe version, switching between them based on a configuration switch. This switch could be exported through a crate "feature", so that users who prefer the no-unsafe version can request it. Feel free to revert this commit if it is not what you want and you decide to merge the PR. If you decide to use it, it might be a good idea to re-run the benchmark, just in case exposing |
Going on your theory (which I happen to agree with) that lots of small arrays is likely to be the most common use case for this crate, as well as the fact that I wanted to target the benchmarking at the actual allocation and not at the "fill 'er up" to populate the data, the benchmarks used I suppose it could be conceivable that there might be some amount of overhead in "initializing" the I'm going to give your new commits a look-through, but barring anything shocking in them I think I'm ready to merge your PR. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like these changes, especially after my own benchmarking has shown such marked performance difference between my original approach and this. After reviewing this and the MaybeUninit
documentation, I'm reasonably comfortable that the use of unsafe
here is safe.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please roll back this latest commit, I think the option to provide safe/unsafe versions at compile time, while interesting, adds too much additional complexity while offering little if any gain in return.
…ling" This reverts commit 47c71fa.
Fair enough - done. |
Thank you! |
Here is a commit that should speed up deserialization by avoiding the intermediate allocation.
Although unsafe appears to be complex compared to the original code, creating a vector for each array might represent a significant performance hit, especially in code bases with many small arrays. (Generics are often used to create small arrays whose sizes are e.g. 2 or 3 to represent two- or three-dimensional vectors.)