Skip to content
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

Use System.Memory for < .NET 5 and avoid (some) unnecessary allocations #483

Merged
merged 1 commit into from
May 30, 2023

Conversation

gfoidl
Copy link
Collaborator

@gfoidl gfoidl commented May 30, 2023

Unfortunately #482 got merged too fast, so I couldn't have a look and provide my feedback over there, thus here's a PR with my suggestions 😉

  • For targets before .NET 5 the System.Memory package is used, which provides Span, and Memory for these targets
    So the code can be simplified a bit by re-using parts of the code

  • internal MemoryStreamExtension.WriteBytes renamed to MemoryStreamExtension.Write so that the usage as extension solely becomes stream.Write, so for .NET 5 (when built with VS 2022 as CI does ?!) the C# compiler can avoid some allocations by refering to assembly's static data segment, namely for patterns like package.Write(new byte[] { 0x1, 0x2, ... }. See sharplab example for this (the PrivateImplementationDetails refers to static data, no further allocation))

stream.WriteByteArray(Types.Int.ToByteArray((short)(19 + (12 * amount))));
stream.WriteByteArray(new byte[] { 0x02, 0xf0, 0x80, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00 });
stream.Write(Int.ToByteArray((short)(19 + (12 * amount))));
stream.Write(new byte[] { 0x02, 0xf0, 0x80, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00 });
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

These byte-array allocations are avoided for newer targets.
Could be done for older targets too (by using a static readonly field), but as this code was so before I don't think we should optimize for these targets -- and for the newer ones we get this optimization for free.

var package = new System.IO.MemoryStream(packageSize);
const int packageSize = 19 + 12; // 19 header + 12 for 1 request
var dataToSend = new byte[packageSize];
var package = new MemoryStream(dataToSend);
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Instead of a ToArray on the MS we can just give it our buffer and use that buffer later on.
Avoids allocations (of the MS buffer).

@mycroes
Copy link
Member

mycroes commented May 30, 2023

Hi @gfoidl,

Sorry for acting so quickly 😆. I was considering some of the reductions you applied here, however I was very much satisfied with the fact someone else did most of the work on this. I fully agree on adding the System.Memory dependency though and making these improvements. Again your keen eye spotted some nice optimizations (the Write method naming).

I have to look into the build environment, not sure what platform we use on AppVeyor, which is what's used to deploy the package as well. I recently did my first GitHub actions workflow to publish to NuGet (VisconFactoryIntelligence/AdsClient/blob/main/.github/workflows/dotnet.yml, which also isn't actually based on VS2022, but I guess this works out with dotnet as well).

Anyway, thanks for your time and feedback, will merge and release this as well.

@mycroes mycroes merged commit f0256fd into S7NetPlus:develop May 30, 2023
@gfoidl gfoidl deleted the span-memory branch May 30, 2023 20:08
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