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

Socket benchmarks initial implementation #1970

Open
wants to merge 9 commits into
base: main
Choose a base branch
from

Conversation

liveans
Copy link
Member

@liveans liveans commented Apr 8, 2024

Adds benchmark for Socket
Three different scenarios implemented:

  • ConnectionEstablishment
  • ReadWrite
  • Rps

@sebastienros
Copy link
Member

FYI, a related one I made to measure how many packets per second a set of machines can handle.

https://github.com/sebastienros/PacketsPerSecond/blob/master/Program.cs

@liveans
Copy link
Member Author

liveans commented Apr 19, 2024

Currently dealing with a task in QUIC, I plan to get back to this early next week.

/cc: @CarnaViire

@liveans liveans marked this pull request as ready for review May 11, 2024 12:08
@liveans
Copy link
Member Author

liveans commented May 11, 2024

It's ready for review now @CarnaViire, there are fields and methods which is duplicating with Tls but decided not to touch them for now, I'll address them as a follow-up later, want merge this first.

@@ -3,9 +3,18 @@

namespace System.Net.Benchmarks;

internal abstract class SingleStreamConnection<TStream> : IConnection
Copy link
Member Author

Choose a reason for hiding this comment

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

There were no abstract method in this class, so I deleted it.

Copy link
Contributor

Choose a reason for hiding this comment

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

I believe we'd need to revert the changes in this file.

It is abstract because it cannot be used directly. The protected InnerStream property is technically playing the role of the "abstract method". There's no actual abstract method bc the class is used as a base class in both server and client, and they have different consuming methods (AcceptInboundStreamAsync vs EstablishStreamAsync).

We can pull the full single-stream client connection implementation -- but only a part of server connection implementation -- "up". But it would still leave SingleStreamConnection abstract.

There's how I see it:

1. (move "up" from Tls to Common)

-   ITlsBenchmarkClientConnection
+   IStreamingClientConnection<TOptions>

2. add IStreamingServerConnection : IConnection with AcceptInboundStreamAsync method pulled up from ITlsBenchmarkServerConnection

3. (remove AcceptInboundStreamAsync from ITlsBenchmarkServerConnection)

-   ITlsBenchmarkServerConnection : IConnection
+   ITlsBenchmarkServerConnection : IStreamingServerConnection

4. Keep SingleStreamConnection abstract

5. (move "up" from Apps to Common)

-   SslStreamClientConnection : SingleStreamConnection<SslStream>, ITlsBenchmarkClientConnection
+   SingleStreamConnectionClientConnection<TStream, TOptions> : SingleStreamConnection<TStream>, IStreamingClientConnection<TOptions>

6. add SingleStreamServerConnection<TStream, TOptions> : SingleStreamConnection<TStream>, IStreamingClientConnection<TOptions> with AcceptInboundStreamAsync method impl pulled up from SslStreamBenchmarkServerConnection

7. (remove AcceptInboundStreamAsync from SslStreamBenchmarkServerConnection )

-   SslStreamBenchmarkServerConnection : SingleStreamConnection<SslStream>, ITlsBenchmarkServerConnection
+   SslStreamBenchmarkServerConnection : SingleStreamServerConnection<SslStream>, ITlsBenchmarkServerConnection

This definitely can be done as a follow-up (I mean, not in this PR), and it is even still up to discussion. It technically might be more trouble than worth, but it can support the positioning of "NetworkStream" benchmarks alongside Tls benchmarks as a group of "streaming" benchmarks.

}
'

connection-establishment:
Copy link
Contributor

Choose a reason for hiding this comment

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

It is generally better to have shorter names, if possible, bc it is easier to use them in command line :)

Suggested change
connection-establishment:
connect:

var elapsed = sw.ElapsedTicks * 1.0 / Stopwatch.Frequency;
return (successRequests / elapsed, exceptionRequests);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you pls unify the file endings so that all of the files end with a new line?

}
sw.Restart();
await using var connection = await establishConnectionAsync(options).ConfigureAwait(false);
await using var stream = await connection.EstablishStreamAsync(options).ConfigureAwait(false);
Copy link
Contributor

Choose a reason for hiding this comment

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

Wait, I am a bit confused... we discussed that we need socket benchmarks that call actual Socket APIs :) so that we can have/add scenarios that are impossible to do using Stream APIs (e.g. UDP socket benchmarks)

When we've discussed NetworkStream previously, in my mind that was about an additional benchmark, more intended to compare with SslStream to see the TLS overhead

Copy link
Member Author

Choose a reason for hiding this comment

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

I see, looks like I got confused from our last discussion as well, and didn't actually realize I should be using direct socket APIs here, I'll change the design to use Socket APIs directly.

Copy link
Contributor

Choose a reason for hiding this comment

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

As discussed offline: we won't rewrite the current NetworkStream benchmarks (but most possibly rename them to avoid confusion), and will implement raw Socket API ones alongside as a follow-up


return await SocketBenchmarkClient.RunAsync(args).ConfigureAwait(false);

internal class SocketBenchmarkClient : BenchmarkClient<SocketClientOptions>
Copy link
Contributor

Choose a reason for hiding this comment

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

I was thinking, and I still believe we'd need to separate these benchmarks (which are technically NetworkStream benchmarks) from the to-be-added pure-Socket-API benchmarks. Otherwise it would be hard to navigate within the benchmark class -- this one is big enough already.

And creating a socket is technically a two-liner (var socket = new Socket(...); await socket.ConnectAsync(...);) and it can/should be potentially different in new benchmarks so we can maybe set some socket options based on passed parameters. So IMO there's not really much to reuse? Or am I missing something?

So, currently the proposal is to rename
SocketBenchmark -> NetworkStreamBenchmark,
src/System/Net/Benchmarks/Apps/Socket/ -> src/System/Net/Benchmarks/Apps/Streaming/,
and maybe even
src/System/Net/Benchmarks/Apps/Tls/ -> src/System/Net/Benchmarks/Apps/Streaming/Tls/

WDYT?

cc @rzikm for additional opinions

Copy link
Member Author

Choose a reason for hiding this comment

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

I was thinking, and I still believe we'd need to separate these benchmarks (which are technically NetworkStream benchmarks) from the to-be-added pure-Socket-API benchmarks. Otherwise it would be hard to navigate within the benchmark class -- this one is big enough already.

After thinking a while on my own, I totally agree with this. I'm planning to change this as NetworkStreamBenchmark and add another Benchmark for pure Socket APIs, because we can extend those Socket Benchmarks with UDP and possibly(?) with other protocols as well in the future.

And creating a socket is technically a two-liner (var socket = new Socket(...); await socket.ConnectAsync(...);) and it can/should be potentially different in new benchmarks so we can maybe set some socket options based on passed parameters. So IMO there's not really much to reuse? Or am I missing something?

I also think that we don't have much to reuse here and it is highly possible that some benchmarks can customize their usages of socket while creating connection (even during connection?), maybe we can create a ConnectCallback or something like that as we have in SocketsHttpHandler. (This is what I'm thinking from top of my head)

So, currently the proposal is to rename
SocketBenchmark -> NetworkStreamBenchmark,
src/System/Net/Benchmarks/Apps/Socket/ -> src/System/Net/Benchmarks/Apps/Streaming/,
and maybe even
src/System/Net/Benchmarks/Apps/Tls/ -> src/System/Net/Benchmarks/Apps/Streaming/Tls/

The only question that comes in my mind is, should we keep QUIC under Tls folder here. Technically, it's a stream protocol as well but do we want to keep it as separated? Or you don't have any problem with moving it with Tls?

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.

None yet

3 participants