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

adding span version of ReceiveMessageFrom #46285

Merged
merged 8 commits into from
Feb 2, 2021

Conversation

ovebastiansen
Copy link
Contributor

I followed the other examples of overloads with span and it seems like the normal is duplication of code, since the other methods are not that long. Should I keep it like this or call the span version from the byte[] version, and remove some of the duplication?

fix #43933

@Dotnet-GitSync-Bot
Copy link
Collaborator

Note regarding the new-api-needs-documentation label:

This serves as a reminder for when your PR is modifying a ref *.cs file and adding/modifying public APIs, to please make sure the API implementation in the src *.cs file is documented with triple slash comments, so the PR reviewers can sign off that change.

@ghost
Copy link

ghost commented Dec 21, 2020

Tagging subscribers to this area: @dotnet/ncl
See info in area-owners.md if you want to be subscribed.

Issue Details

I followed the other examples of overloads with span and it seems like the normal is duplication of code, since the other methods are not that long. Should I keep it like this or call the span version from the byte[] version, and remove some of the duplication?

fix #43933

Author: ovebastiansen
Assignees: -
Labels:

area-System.Net.Sockets, new-api-needs-documentation

Milestone: -

@wfurt
Copy link
Member

wfurt commented Dec 24, 2020

thanks for the contribution @ovebastiansen. It seems like you simply duplicated all the code we use with byte[] for Span<byte>. I think it would be better to spanify the impementaiton and update existing code to covert byte[] buffer, int offset, int size to Span and use the new implementation. The cost is low and I think we could avoid unnecessary code duplication.

@ovebastiansen
Copy link
Contributor Author

ovebastiansen commented Dec 24, 2020 via email

@ovebastiansen
Copy link
Contributor Author

/azp run runtime

@azure-pipelines
Copy link

Commenter does not have sufficient privileges for PR 46285 in repo dotnet/runtime

@geoffkizer
Copy link
Contributor

It's kind of weird to add this just for ReceiveMessageFrom, but not ReceiveFrom or SendTo. I don't think we'd want to ship 6.0 like that.

@ovebastiansen
Copy link
Contributor Author

I can fix those two as well then in this PR. Does the code otherwise look ok now?

@geoffkizer
Copy link
Contributor

The reason we have duplication in a lot of these cases is because the sync implementation in SocketAsyncContext ends up treating Span<byte> differently than byte[] -- it can't store the Span<byte> on the heap, so it pins it and treats it as a native pointer. This isn't ideal, because it means the buffer is pinned for the duration of the call, as opposed to just when we actually call into the kernel.

In theory the code shouldn't need to do this pinning, but it that's a separate issue and isn't trivial to fix.

Addign @stephentoub in case he has any thoughts to add.

@ovebastiansen
Copy link
Contributor Author

does that mean I should duplicate or keep it like this?

@geoffkizer
Copy link
Contributor

Unfortunately, I think it means we should duplicate the code in the same way we do for Receive today. That is, the byte[] overload should use byte[] all the way down and not pin, and the Span overload should use Span all the way down, and pin when it creates the Operation object.

It would be good to fix this in the future; I'll file a separate issue on this.

@geoffkizer
Copy link
Contributor

We need tests for these overloads too.

Adding @antonfirsov who has looked at these tests most recently. Anton, what's the best way to test these new overloads?

@ovebastiansen
Copy link
Contributor Author

Ok, then I will go back to the first implementation, with the duplication. And I will also try to fix the other two methods you mentioned. I just figured they where tracked somewhere else in the sockets mega issue ;)

@geoffkizer
Copy link
Contributor

Yeah, they are all tracked in #43935

@geoffkizer
Copy link
Contributor

I added an issue re Span and pinning and code duplication, here: #46600

@geoffkizer
Copy link
Contributor

#46862 from @antonfirsov should make testing this easy, we just need to ensure we have the right hooks enabled for the new overloads.

@antonfirsov
Copy link
Member

antonfirsov commented Jan 13, 2021

Sorry, despite the tagging I somehow missed this PR 😞 I also didn't think through the fact that there is no span overload for ReceiveMessageFrom while working on #46862, and added a "span" version of the tests in autopilot mode:

public sealed class ReceiveMessageFrom_SpanSync : ReceiveMessageFrom<SocketHelperSpanSync>
{
public ReceiveMessageFrom_SpanSync(ITestOutputHelper output) : base(output) { }
}

On master, that test is now duplicate of the array test. In order to make pick up the span overload, SocketHelperSpanSync should be extended with an override of ReceiveMessageFromAsync:

public class SocketHelperSpanSync : SocketHelperArraySync
{
public override bool ValidatesArrayArguments => false;
public override Task<int> ReceiveAsync(Socket s, ArraySegment<byte> buffer) =>
Task.Run(() => s.Receive((Span<byte>)buffer, SocketFlags.None));
public override Task<int> SendAsync(Socket s, ArraySegment<byte> buffer) =>
Task.Run(() => s.Send((ReadOnlySpan<byte>)buffer, SocketFlags.None));
public override bool UsesSync => true;
}

This should be sufficient to provide the necessary test coverage for this PR.

@antonfirsov antonfirsov self-assigned this Jan 13, 2021
Copy link
Member

@antonfirsov antonfirsov left a comment

Choose a reason for hiding this comment

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

Should be good after some cleanup, updating the tests and removing the code duplication in the Windows PAL.

I have a few (optional) suggestions though.


namespace System.Net.Sockets.Tests
{
public class ReceiveMessageFromSpan
Copy link
Member

@antonfirsov antonfirsov Jan 13, 2021

Choose a reason for hiding this comment

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

The whole class can be deleted now in favor of the SocketTestHelperSpan extension suggested in #46285 (comment).

However, in order to stress slicing, I would alter ReceiveSentMessages_Success to use an ArraySegment with a non-zero offset as a receiveBuffer:

byte[] receiveBuffer = new byte[DatagramSize];

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I tried adding a bigger array receive array and offset it. Mostly seems to be working, checking that the part before the offset is not written to, and that the rest is the same. But now the EAP version fails, somewhere in the code it does not respect the offset it seems, and just tries to write to the start of the array. I have looked at the entrypart of the code and cannot spot an easy reason for this. Can you check it, @antonfirsov?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@antonfirsov Where you able to spot any problems in this? EAP tests fails when running with an offset

Copy link
Member

@antonfirsov antonfirsov Jan 29, 2021

Choose a reason for hiding this comment

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

@ovebastiansen I'm sorry, missed your original comment, looks like a bug, opened an issue: #47637.

Please modify the beginning of your test as following, so you are not blocked by this:

            // [ActiveIssue("https://github.com/dotnet/runtime/issues/47637")]
            int offset = UsesSync ? 10 : 0;

Edit: There was a typo in the original suggestion. Should be UsesSync ? 10 : 0

Copy link
Member

Choose a reason for hiding this comment

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

Even better if you do it like: UsesSync || !PlatformDetection.IsWindows ? 10 : 0

@@ -1564,6 +1564,73 @@ public int ReceiveMessageFrom(byte[] buffer, int offset, int size, ref SocketFla
return bytesTransferred;
}

public int ReceiveMessageFrom(Span<byte> buffer, ref SocketFlags socketFlags, ref EndPoint remoteEP, out IPPacketInformation ipPacketInformation)
Copy link
Member

Choose a reason for hiding this comment

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

The new practice is to add xmldocs right in the dotnet/runtime PR. See 9f73188 from #45083

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hmm, it seems like non of the other methods in this class has it, should I start the it or am I looking at the wrong place?

Copy link
Member

Choose a reason for hiding this comment

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

You can check #47230 and #47229 as examples adding new methods to Socket.cs together with xml docs.

Just copy existing docs, and modify them according to the new overload:
https://docs.microsoft.com/en-us/dotnet/api/system.net.sockets.socket.receivemessagefrom?view=net-5.0

Copy link
Contributor Author

Choose a reason for hiding this comment

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

took a stab at the documentation, copied from the existing, but existing is missing some of the exception actually thrown from the method, so a bit unsure if they should be added.

Copy link
Member

@antonfirsov antonfirsov left a comment

Choose a reason for hiding this comment

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

I think we are good to merge after fixing the merge conflicts and adding the xml docs.

The conflicts are coming from recent PR-s around the area, and I don't expect them to be hard to fix.

@antonfirsov
Copy link
Member

@ovebastiansen I opened #47642 to fix the async Windows bug, if it gets merged before your PR, you don't need to bother with the [ActiveIssue] stuff.

@antonfirsov
Copy link
Member

/azp run runtime-libraries-coreclr outerloop

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

Copy link
Member

@antonfirsov antonfirsov left a comment

Choose a reason for hiding this comment

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

LGTM after fixing two nits.

@antonfirsov
Copy link
Member

Outer loop test failures are unrelated: #41606, #43207, #46619, #40798, #43877, #44352

@antonfirsov
Copy link
Member

Test failure is in the latest (inner) run is #47728.

Copy link
Member

@antonfirsov antonfirsov left a comment

Choose a reason for hiding this comment

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

I just realized we still need to fix stuff in xmldocs, for example adding a copy of the long remarks section of the array overload. Regardless, I want to merge this as-is to unblock follow-up work, and will rather open a separate PR with the docs myself instead of delaying this PR further. new-api-needs-documentation PR-s contain an unfair amount of formal expectations towards community contributors IMO. @carlossanlop thoughts on this?

@ovebastiansen thanks for the work and the patience!

@antonfirsov antonfirsov merged commit 4df29c9 into dotnet:master Feb 2, 2021
@ghost ghost locked as resolved and limited conversation to collaborators Mar 4, 2021
@karelz karelz added this to the 6.0.0 milestone May 20, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add Span overload for Socket.ReceiveMessageFrom
6 participants