Compress SafeSocketHandle.Unix booleans#112417
Conversation
|
Tagging subscribers to this area: @dotnet/ncl |
This comment was marked as outdated.
This comment was marked as outdated.
Does it actually? If the fields were otherwise of a size divisible by eight, there's no difference on 64-bit between an extra byte field and an extra 7 boolean fields; the size of the object will still be rounded up to the next 8 byte boundary. Unless there's a real savings, I'd rather keep the code simple. |
|
@EgorBot -intel using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
using System.Net;
using System.Net.Sockets;
BenchmarkSwitcher.FromAssembly(typeof(SocketBench).Assembly).Run(args);
[MemoryDiagnoser]
public class SocketBench
{
private Socket? _listener;
private Socket? _receiver;
private Socket? _sender;
private CancellationTokenSource? _cts;
private byte[] _sendBuffer = new byte[16];
[Benchmark]
public int Send() => _sender!.Send(_sendBuffer);
[Benchmark]
public async Task<int> SendAsync() => await _sender!.SendAsync(_sendBuffer, SocketFlags.None, default);
[Benchmark]
public void CreateClose()
{
Socket sock = new Socket(SocketType.Stream, ProtocolType.Tcp);
sock.Dispose();
}
[GlobalSetup(Targets = [nameof(Send), nameof(SendAsync)])]
public async Task Setup()
{
_listener = new Socket(SocketType.Stream, ProtocolType.Tcp);
_listener.Bind(new IPEndPoint(IPAddress.IPv6Loopback, 0));
IPEndPoint serverEp = (IPEndPoint)_listener.LocalEndPoint!;
_listener.Listen();
Task<Socket> acceptTask = _listener.AcceptAsync();
_sender = new Socket(SocketType.Stream, ProtocolType.Tcp);
await _sender.ConnectAsync(serverEp);
_receiver = await acceptTask;
_cts = new CancellationTokenSource();
_ = RunServer();
async Task RunServer()
{
byte[] rcvBuffer = new byte[16];
try
{
while (!_cts.Token.IsCancellationRequested)
{
await _receiver.ReceiveAsync(rcvBuffer, _cts.Token);
}
}
catch (OperationCanceledException) { }
}
}
[GlobalCleanup(Targets = [nameof(Send), nameof(SendAsync)])]
public void Cleanup()
{
_cts?.Cancel();
_receiver?.Dispose();
_listener?.Dispose();
_sender?.Dispose();
}
} |
|
The socket allocation cost went down @stephentoub if you think this is not worth the added complexity, I'll close this. |
There was a problem hiding this comment.
Copilot reviewed 1 out of 1 changed files in this pull request and generated no comments.
Comments suppressed due to low confidence (2)
src/libraries/System.Net.Sockets/src/System/Net/Sockets/SafeSocketHandle.Unix.cs:144
- The setter for IsNonBlocking does not handle the transition from non-blocking to blocking correctly, which could lead to unexpected socket behavior.
set { if (value) _flags |= Flags.NonBlocking; else _flags &= ~Flags.NonBlocking; }
src/libraries/System.Net.Sockets/src/System/Net/Sockets/SafeSocketHandle.Unix.cs:187
- The change in IsDisconnected property behavior from a private setter to a flag check might lead to unintended side effects.
internal bool IsDisconnected => (_flags & Flags.IsDisconnected) != 0;
Ok, thanks. Looking at the type's fields, removing those bools causes it to cross a threshold that lowers the number of words by 1. I'm ok with it, if others are. |
| if (value) _flags |= Flags.LastConnectFailed; | ||
| else _flags &= ~Flags.LastConnectFailed; |
There was a problem hiding this comment.
nit: These are reusing same pattern, perhaps you can write a simple helper for this purpose.
|
/azp run runtime-libraries-coreclr outerloop |
|
Azure Pipelines successfully started running 1 pipeline(s). |
|
/azp run runtime-libraries-coreclr outerloop |
|
Azure Pipelines will not run the associated pipelines, because the pull request was updated after the run command was issued. Review the pull request again and issue a new run command. |
|
/azp run runtime-libraries-coreclr outerloop |
|
Azure Pipelines successfully started running 1 pipeline(s). |
|
/ba-g CI failures are unrelated |
There are 7 (+1 on Mac) bool fields in
SafeSocketHandle.Unixwhich can be collapsed into a single byte field, saving 6 bytes per socket instance. The extra cost of the flag read/writes should be negligible.