internal static Client[] StartClients(EndPoint endPoint, ClientCommonOptions options, CancellationToken cancellationToken) { var clientTasks = Enumerable.Range(0, options.Connections) .Select(async _ => { var c = options.Tcp ? (Client) new TcpTlsClient(endPoint, options) : new QuicClient(endPoint, options); await c.ConnectAsync().ConfigureAwait(false); return(c); }) .ToArray(); Task.WaitAll(clientTasks); var clients = clientTasks.Select(i => i.Result).ToArray(); foreach (var client in clients) { Helpers.Dispatch(() => client.Run(cancellationToken)); } return(clients); }
internal static void MonitorResults(Client[] clients, ClientCommonOptions options, CancellationTokenSource cancellationSource) { if (!options.CsvOutput) { if (options.Tcp) { Console.WriteLine( $"Test running SSL with {options.Connections} connections and {options.MessageSize}B messages."); } else { Console.WriteLine( $"Test running QUIC with {options.Connections} connections, {options.Streams} streams per connection and {options.MessageSize}B messages. Provider: {QuicImplementationProviders.Default.GetType().Name}."); } } int GetCurrentRequestCount() { return(clients.Sum(c => c.GetRequestCount())); } List <TimeSpan>[][] latencies = Enumerable.Range(0, options.Connections).Select(_ => Enumerable.Range(0, Math.Max(options.Streams, 1)).Select(_ => new List <TimeSpan>()).ToArray()) .ToArray(); long startCount = 0; if (options.WarmupTime > 0) { Helpers.InterruptibleWait((int)(options.WarmupTime * 1000), cancellationSource.Token); startCount = GetCurrentRequestCount(); CalculateLatencies(clients, latencies); } long previousCount = startCount; Stopwatch sw = Stopwatch.StartNew(); TimeSpan previousElapsed = TimeSpan.Zero; TimeSpan elapsed = TimeSpan.Zero; double currentRps = 0; double averageRps = 0; double dataThroughput = 0; double previousAverageRps = 0; double drift = 0; double avgLatency = 0; double p50Latency = 0; double p95Latency = 0; double p99Latency = 0; double pmaxLatency = 0; List <Column> columns = new List <Column> { new Column("Timestamp", 16, () => $"{elapsed}"), new Column("Current RPS", 16, () => $"{currentRps:0.000}"), new Column("Average RPS", 16, () => $"{averageRps:0.000}"), new Column("Drift (%)", 11, () => $"{drift:0.000}"), new Column("Throughput (MiB/s)", 20, () => $"{dataThroughput:0.000}"), }; if (!options.NoWait) { // latency measurements make sense only when we are waiting for the server's reply columns.Add(new Column("Latency-avg (ms)", 20, () => $"{avgLatency:0.000}")); columns.Add(new Column("Latency-p50 (ms)", 20, () => $"{p50Latency:0.000}")); columns.Add(new Column("Latency-p95 (ms)", 20, () => $"{p95Latency:0.000}")); columns.Add(new Column("Latency-p99 (ms)", 20, () => $"{p99Latency:0.000}")); columns.Add(new Column("Latency-max (ms)", 20, () => $"{pmaxLatency:0.000}")); } PrintHeader(columns, options.CsvOutput); void UpdateMeasurements() { elapsed = sw.Elapsed; long totalCount = GetCurrentRequestCount(); currentRps = (totalCount - previousCount) / (elapsed - previousElapsed).TotalSeconds; averageRps = (totalCount - startCount) / elapsed.TotalSeconds; dataThroughput = currentRps * options.MessageSize / (1024 * 1024); drift = (averageRps - previousAverageRps) / previousAverageRps * 100; if (!options.NoWait) { (avgLatency, p50Latency, p95Latency, p99Latency, pmaxLatency) = CalculateLatencies(clients, latencies); } previousElapsed = elapsed; previousCount = totalCount; previousAverageRps = averageRps; } if (options.DurationTime > 0) { cancellationSource.CancelAfter(TimeSpan.FromSeconds(options.DurationTime)); } int delay = options.ReportingInterval > 0 ? (int)(options.ReportingInterval * 1000) : -1; while (!cancellationSource.IsCancellationRequested) { Helpers.InterruptibleWait(delay, cancellationSource.Token); UpdateMeasurements(); PrintColumns(columns, options.CsvOutput); } }
protected Client(EndPoint endPoint, ClientCommonOptions options) { _latencies = Enumerable.Range(0, Math.Max(options.Streams, 1)).Select(_ => new List <TimeSpan>()).ToArray(); _options = options; _sendBuffer = Helpers.CreateMessageBuffer(options.MessageSize); }