mirror of
https://github.com/sshnet/SSH.NET.git
synced 2026-09-10 09:15:47 +00:00
fdbc4d3e36
Apply similar treatment to PipeStream as #1322 did to ShellStream PipeStream now behaves much more Stream-like. In particular, it performs partial reads (instead of blocking until a certain amount of data is available), blocks until data is available (instead of returning 0 prematurely) and removes the Stream-unlike properties `BlockLastReadBuffer` and `MaxBufferLength`. Sadly I gave up trying to make a benchmark compatible with all the quirks of the previous implementation, but a dumb throughput test (reading and writing simultaneously) shows about 5.2GB/s with this implementation compared to 140MB/s previously. Some cleanup of its usage in the library followed. Co-authored-by: Wojciech Nagórski <wojtpl2@gmail.com>
117 lines
4.4 KiB
C#
117 lines
4.4 KiB
C#
using BenchmarkDotNet.Attributes;
|
|
|
|
using Renci.SshNet.Common;
|
|
using Renci.SshNet.IntegrationTests.TestsFixtures;
|
|
|
|
namespace Renci.SshNet.IntegrationBenchmarks
|
|
{
|
|
[MemoryDiagnoser]
|
|
[SimpleJob]
|
|
public class SshClientBenchmark : IntegrationBenchmarkBase
|
|
{
|
|
private static readonly Dictionary<TerminalModes, uint> ShellStreamTerminalModes = new Dictionary<TerminalModes, uint>
|
|
{
|
|
{ TerminalModes.ECHO, 0 }
|
|
};
|
|
|
|
private readonly InfrastructureFixture _infrastructureFixture;
|
|
private SshClient? _sshClient;
|
|
|
|
public SshClientBenchmark()
|
|
{
|
|
_infrastructureFixture = InfrastructureFixture.Instance;
|
|
}
|
|
|
|
[GlobalSetup]
|
|
public async Task Setup()
|
|
{
|
|
await GlobalSetup().ConfigureAwait(false);
|
|
_sshClient = new SshClient(_infrastructureFixture.SshServerHostName, _infrastructureFixture.SshServerPort, _infrastructureFixture.User.UserName, _infrastructureFixture.User.Password);
|
|
await _sshClient.ConnectAsync(CancellationToken.None).ConfigureAwait(false);
|
|
}
|
|
|
|
[GlobalCleanup]
|
|
public async Task Cleanup()
|
|
{
|
|
await GlobalCleanup().ConfigureAwait(false);
|
|
}
|
|
|
|
[Benchmark]
|
|
public void Connect()
|
|
{
|
|
using var sshClient = new SshClient(_infrastructureFixture.SshServerHostName, _infrastructureFixture.SshServerPort, _infrastructureFixture.User.UserName, _infrastructureFixture.User.Password);
|
|
sshClient.Connect();
|
|
}
|
|
|
|
[Benchmark]
|
|
public async Task ConnectAsync()
|
|
{
|
|
using var sshClient = new SshClient(_infrastructureFixture.SshServerHostName, _infrastructureFixture.SshServerPort, _infrastructureFixture.User.UserName, _infrastructureFixture.User.Password);
|
|
await sshClient.ConnectAsync(CancellationToken.None).ConfigureAwait(false);
|
|
}
|
|
|
|
[Benchmark]
|
|
public string ConnectAndRunCommand()
|
|
{
|
|
using var sshClient = new SshClient(_infrastructureFixture.SshServerHostName, _infrastructureFixture.SshServerPort, _infrastructureFixture.User.UserName, _infrastructureFixture.User.Password);
|
|
sshClient.Connect();
|
|
return sshClient.RunCommand("echo $'test !@#$%^&*()_+{}:,./<>[];\\|'").Result;
|
|
}
|
|
|
|
[Benchmark]
|
|
public async Task<string> ConnectAsyncAndRunCommand()
|
|
{
|
|
using var sshClient = new SshClient(_infrastructureFixture.SshServerHostName, _infrastructureFixture.SshServerPort, _infrastructureFixture.User.UserName, _infrastructureFixture.User.Password);
|
|
await sshClient.ConnectAsync(CancellationToken.None).ConfigureAwait(false);
|
|
return sshClient.RunCommand("echo $'test !@#$%^&*()_+{}:,./<>[];\\|'").Result;
|
|
}
|
|
|
|
[Benchmark]
|
|
public string RunCommand()
|
|
{
|
|
return _sshClient!.RunCommand("echo $'test !@#$%^&*()_+{}:,./<>[];\\|'").Result;
|
|
}
|
|
|
|
[Benchmark]
|
|
public string RunBigCommand()
|
|
{
|
|
using var command = _sshClient!.CreateCommand("head -c 10000000 /dev/urandom | base64"); // 10MB of data please
|
|
|
|
var asyncResult = command.BeginExecute();
|
|
|
|
command.OutputStream.CopyTo(Stream.Null);
|
|
|
|
return command.EndExecute(asyncResult);
|
|
}
|
|
|
|
[Benchmark]
|
|
public string ShellStreamReadLine()
|
|
{
|
|
using (var shellStream = _sshClient!.CreateShellStream("xterm", 80, 24, 800, 600, 1024, ShellStreamTerminalModes))
|
|
{
|
|
shellStream.WriteLine("for i in $(seq 500); do echo \"Within cells. Interlinked. $i\"; sleep 0.001; done; echo \"Username:\";");
|
|
|
|
while (true)
|
|
{
|
|
var line = shellStream.ReadLine()!;
|
|
|
|
if (line.EndsWith("500", StringComparison.Ordinal))
|
|
{
|
|
return line;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
[Benchmark]
|
|
public string? ShellStreamExpect()
|
|
{
|
|
using (var shellStream = _sshClient!.CreateShellStream("xterm", 80, 24, 800, 600, 1024, ShellStreamTerminalModes))
|
|
{
|
|
shellStream.WriteLine("for i in $(seq 500); do echo \"Within cells. Interlinked. $i\"; sleep 0.001; done; echo \"Username:\";");
|
|
return shellStream.Expect("Username:");
|
|
}
|
|
}
|
|
}
|
|
}
|