Support Optional Units on secnetperf Arguments (#4015)

This commit is contained in:
Nick Banks 2024-01-08 20:03:04 -05:00 коммит произвёл GitHub
Родитель ee1bc7001c
Коммит 5949785334
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
6 изменённых файлов: 198 добавлений и 65 удалений

Просмотреть файл

@ -12,7 +12,7 @@
"Tls": ["schannel", "openssl", "openssl3"],
"Arch": ["x64", "x86", "arm", "arm64"],
"Exe": "secnetperf",
"Arguments": "-exec:maxtput -target:$RemoteAddress -bind:$LocalAddress:4434 -ip:4 -up:12000 -timed:1 -ptput:1 -pconn:1 -pstream:1 -tcp:0"
"Arguments": "-exec:maxtput -target:$RemoteAddress -bind:$LocalAddress:4434 -ip:4 -up:12s -ptput:1 -tcp:0"
},
"Variables": [
{
@ -46,7 +46,7 @@
"Tls": ["schannel", "openssl", "openssl3"],
"Arch": ["x64", "x86", "arm", "arm64"],
"Exe": "secnetperf",
"Arguments": "-exec:maxtput -target:$RemoteAddress -bind:$LocalAddress:4434 -ip:4 -up:12000 -timed:1 -ptput:1 -pconn:1 -pstream:1 -tcp:1"
"Arguments": "-exec:maxtput -target:$RemoteAddress -bind:$LocalAddress:4434 -ip:4 -up:12s -ptput:1 -tcp:1"
},
"Variables": [
],
@ -65,7 +65,7 @@
"Tls": ["openssl", "openssl3"],
"Arch": ["x64", "arm"],
"Exe": "secnetperf",
"Arguments": "-exec:maxtput -target:$RemoteAddress -bind:$LocalAddress:4434 -ip:4 -up:12000 -timed:1 -ptput:1 -pconn:1 -pstream:1 -tcp:0"
"Arguments": "-exec:maxtput -target:$RemoteAddress -bind:$LocalAddress:4434 -ip:4 -up:12s -ptput:1 -tcp:0"
},
"Variables": [
{
@ -99,7 +99,7 @@
"Tls": ["openssl", "openssl3"],
"Arch": ["x64", "arm"],
"Exe": "secnetperf",
"Arguments": "-exec:maxtput -target:$RemoteAddress -bind:$LocalAddress:4434 -ip:4 -up:12000 -timed:1 -ptput:1 -pconn:1 -pstream:1 -tcp:1"
"Arguments": "-exec:maxtput -target:$RemoteAddress -bind:$LocalAddress:4434 -ip:4 -up:12s -ptput:1 -tcp:1"
},
"Variables": [
],
@ -118,7 +118,7 @@
"Tls": ["schannel", "openssl", "openssl3"],
"Arch": ["x64", "x86", "arm", "arm64"],
"Exe": "secnetperf",
"Arguments": "-exec:maxtput -target:$RemoteAddress -bind:$LocalAddress:4434 -ip:4 -down:12000 -timed:1 -ptput:1 -pconn:1 -tcp:0"
"Arguments": "-exec:maxtput -target:$RemoteAddress -bind:$LocalAddress:4434 -ip:4 -down:12s -ptput:1 -pconn:1 -tcp:0"
},
"Variables": [
{
@ -144,7 +144,7 @@
"Tls": ["schannel", "openssl", "openssl3"],
"Arch": ["x64", "x86", "arm", "arm64"],
"Exe": "secnetperf",
"Arguments": "-exec:maxtput -target:$RemoteAddress -bind:$LocalAddress:4434 -ip:4 -down:12000 -timed:1 -ptput:1 -pconn:1 -tcp:1"
"Arguments": "-exec:maxtput -target:$RemoteAddress -bind:$LocalAddress:4434 -ip:4 -down:12s -ptput:1 -pconn:1 -tcp:1"
},
"Variables": [
],
@ -163,7 +163,7 @@
"Tls": ["openssl", "openssl3"],
"Arch": ["x64", "arm"],
"Exe": "secnetperf",
"Arguments": "-exec:maxtput -target:$RemoteAddress -bind:$LocalAddress:4434 -ip:4 -down:12000 -timed:1 -ptput:1 -pconn:1 -tcp:0"
"Arguments": "-exec:maxtput -target:$RemoteAddress -bind:$LocalAddress:4434 -ip:4 -down:12s -ptput:1 -pconn:1 -tcp:0"
},
"Variables": [
{
@ -189,7 +189,7 @@
"Tls": ["openssl", "openssl3"],
"Arch": ["x64", "arm"],
"Exe": "secnetperf",
"Arguments": "-exec:maxtput -target:$RemoteAddress -bind:$LocalAddress:4434 -ip:4 -down:12000 -timed:1 -ptput:1 -pconn:1 -tcp:1"
"Arguments": "-exec:maxtput -target:$RemoteAddress -bind:$LocalAddress:4434 -ip:4 -down:12s -ptput:1 -pconn:1 -tcp:1"
},
"Variables": [
],
@ -214,10 +214,10 @@
{
"Name": "ConnectionCount",
"Local": {
"1": "-conns:1 -requests:1 -runtime:30000",
"40": "-conns:40 -requests:1 -runtime:10000",
"250": "-conns:250 -requests:30 -runtime:10000",
"1000": "-conns:1 -requests:1000 -runtime:10000"
"1": "-conns:1 -requests:1 -run:30s",
"40": "-conns:40 -requests:1 -run:10s",
"250": "-conns:250 -requests:30 -run:10s",
"1000": "-conns:1 -requests:1000 -run:10s"
},
"Default": "250"
},
@ -259,10 +259,10 @@
{
"Name": "ConnectionCount",
"Local": {
"1": "-conns:1 -requests:1 -runtime:30000",
"40": "-conns:40 -requests:1 -runtime:10000",
"250": "-conns:250 -requests:30 -runtime:10000",
"1000": "-conns:1 -requests:1000 -runtime:10000"
"1": "-conns:1 -requests:1 -run:30s",
"40": "-conns:40 -requests:1 -run:10s",
"250": "-conns:250 -requests:30 -run:10s",
"1000": "-conns:1 -requests:1000 -run:10s"
},
"Default": "250"
},
@ -304,10 +304,10 @@
{
"Name": "ConnectionCount",
"Local": {
"1": "-conns:1 -requests:1 -runtime:30000",
"40": "-conns:40 -requests:1 -runtime:10000",
"250": "-conns:250 -requests:30 -runtime:10000",
"1000": "-conns:1 -requests:1000 -runtime:10000"
"1": "-conns:1 -requests:1 -run:30s",
"40": "-conns:40 -requests:1 -run:10s",
"250": "-conns:250 -requests:30 -run:10s",
"1000": "-conns:1 -requests:1000 -run:10s"
},
"Default": "250"
},
@ -349,10 +349,10 @@
{
"Name": "ConnectionCount",
"Local": {
"1": "-conns:1 -requests:1 -runtime:30000",
"40": "-conns:40 -requests:1 -runtime:10000",
"250": "-conns:250 -requests:30 -runtime:10000",
"1000": "-conns:1 -requests:1000 -runtime:10000"
"1": "-conns:1 -requests:1 -run:30s",
"40": "-conns:40 -requests:1 -run:10s",
"250": "-conns:250 -requests:30 -run:10s",
"1000": "-conns:1 -requests:1000 -run:10s"
},
"Default": "250"
},
@ -388,7 +388,7 @@
"Tls": ["schannel", "openssl", "openssl3"],
"Arch": ["x64", "x86", "arm", "arm64"],
"Exe": "secnetperf",
"Arguments": "-exec:maxtput -target:$RemoteAddress -affinitize:1 -inctarget:1 -rconn:1 -conns:800 -share:1 -run:10000 -tcp:0 -prate:1"
"Arguments": "-exec:maxtput -target:$RemoteAddress -affinitize:1 -rconn:1 -conns:800 -share:1 -run:10s -tcp:0 -prate:1"
},
"Variables": [],
"AllowLoopback": false,
@ -405,7 +405,7 @@
"Tls": ["schannel", "openssl", "openssl3"],
"Arch": ["x64", "x86", "arm", "arm64"],
"Exe": "secnetperf",
"Arguments": "-exec:maxtput -target:$RemoteAddress -affinitize:1 -inctarget:1 -rconn:1 -conns:800 -share:1 -run:10000 -tcp:1 -prate:1"
"Arguments": "-exec:maxtput -target:$RemoteAddress -affinitize:1 -rconn:1 -conns:800 -share:1 -run:10s -tcp:1 -prate:1"
},
"Variables": [],
"AllowLoopback": false,
@ -422,7 +422,7 @@
"Tls": ["openssl", "openssl3"],
"Arch": ["x64", "arm"],
"Exe": "secnetperf",
"Arguments": "-exec:maxtput -target:$RemoteAddress -affinitize:1 -inctarget:1 -rconn:1 -conns:800 -share:1 -run:10000 -tcp:0 -prate:1"
"Arguments": "-exec:maxtput -target:$RemoteAddress -affinitize:1 -rconn:1 -conns:800 -share:1 -run:10s -tcp:0 -prate:1"
},
"Variables": [],
"AllowLoopback": false,
@ -439,7 +439,7 @@
"Tls": ["openssl", "openssl3"],
"Arch": ["x64", "arm"],
"Exe": "secnetperf",
"Arguments": "-exec:maxtput -target:$RemoteAddress -affinitize:1 -inctarget:1 -rconn:1 -conns:800 -share:1 -run:10000 -tcp:1 -prate:1"
"Arguments": "-exec:maxtput -target:$RemoteAddress -affinitize:1 -rconn:1 -conns:800 -share:1 -run:10s -tcp:1 -prate:1"
},
"Variables": [],
"AllowLoopback": false,

Просмотреть файл

@ -30,9 +30,9 @@ QuicHandleExtraData(
_In_opt_z_ const char* FileName
)
{
CXPLAT_FRE_ASSERT(Length >= sizeof(uint32_t) + sizeof(uint32_t));
uint32_t RunTime;
uint64_t RunTime;
uint64_t CachedCompletedRequests;
CXPLAT_FRE_ASSERT(Length >= sizeof(RunTime) + sizeof(CachedCompletedRequests));
CxPlatCopyMemory(&RunTime, ExtraData, sizeof(RunTime));
ExtraData += sizeof(RunTime);
CxPlatCopyMemory(&CachedCompletedRequests, ExtraData, sizeof(CachedCompletedRequests));
@ -42,7 +42,7 @@ QuicHandleExtraData(
RestOfBufferLength &= 0xFFFFFFFC; // Round down to nearest multiple of 4
uint32_t MaxCount = CXPLAT_MIN((uint32_t)CachedCompletedRequests, RestOfBufferLength);
uint32_t RPS = (uint32_t)((CachedCompletedRequests * 1000ull) / (uint64_t)RunTime);
uint32_t RPS = (uint32_t)((CachedCompletedRequests * 1000ull * 1000ull) / RunTime);
if (RPS == 0) {
printf("Error: No requests were completed\n");
return;

Просмотреть файл

@ -15,6 +15,58 @@ Abstract:
#include "PerfClient.cpp.clog.h"
#endif
const char* TimeUnits[] = { "m", "ms", "us", "s" };
const uint64_t TimeMult[] = { 60 * 1000 * 1000, 1000, 1, 1000 * 1000 };
const char* SizeUnits[] = { "gb", "mb", "kb", "b" };
const uint64_t SizeMult[] = { 1000 * 1000 * 1000, 1000 * 1000, 1000, 1 };
_Success_(return != false)
bool
TryGetVariableUnitValue(
_In_ int argc,
_In_reads_(argc) _Null_terminated_ char* argv[],
_In_z_ const char** names,
_Out_ uint64_t* pValue,
_Out_ bool* isTimed
)
{
*isTimed = false; // Default
// Search for the first matching name.
char* value = nullptr;
while (*names && (value = (char*)GetValue(argc, argv, *names)) == nullptr) {
names++;
}
if (!value) { return false; }
// Search to see if the value has a time unit specified at the end.
for (uint32_t i = 0; i < ARRAYSIZE(TimeUnits); ++i) {
size_t len = strlen(TimeUnits[i]);
if (len < strlen(value) &&
_strnicmp(value + strlen(value) - len, TimeUnits[i], len) == 0) {
*isTimed = true;
value[strlen(value) - len] = '\0';
*pValue = (uint64_t)atoi(value) * TimeMult[i];
return true;
}
}
// Search to see if the value has a size unit specified at the end.
for (uint32_t i = 0; i < ARRAYSIZE(SizeUnits); ++i) {
size_t len = strlen(SizeUnits[i]);
if (len < strlen(value) &&
_strnicmp(value + strlen(value) - len, SizeUnits[i], len) == 0) {
value[strlen(value) - len] = '\0';
*pValue = (uint64_t)atoi(value) * SizeMult[i];
return true;
}
}
// Default to bytes if no unit is specified.
*pValue = (uint64_t)atoi(value);
return true;
}
QUIC_STATUS
PerfClient::Init(
_In_ int argc,
@ -121,19 +173,25 @@ PerfClient::Init(
WriteOutput("'iosize' too small'!\n");
return QUIC_STATUS_INVALID_PARAMETER;
}
TryGetValue(argc, argv, "request", &Upload);
TryGetValue(argc, argv, "upload", &Upload);
TryGetValue(argc, argv, "up", &Upload);
TryGetValue(argc, argv, "response", &Download);
TryGetValue(argc, argv, "download", &Download);
TryGetValue(argc, argv, "down", &Download);
TryGetValue(argc, argv, "timed", &Timed);
bool IsTimeUnit = false;
const char* UploadVarNames[] = {"upload", "up", "request", nullptr};
if (TryGetVariableUnitValue(argc, argv, UploadVarNames, &Upload, &IsTimeUnit)) {
Timed = IsTimeUnit ? 1 : 0;
}
const char* DownloadVarNames[] = {"download", "down", "response", nullptr};
if (TryGetVariableUnitValue(argc, argv, DownloadVarNames, &Download, &IsTimeUnit)) {
Timed = IsTimeUnit ? 1 : 0;
}
const char* RunVarNames[] = {"runtime", "time", "run", nullptr};
TryGetVariableUnitValue(argc, argv, RunVarNames, &RunTime, &IsTimeUnit);
//TryGetValue(argc, argv, "inline", &SendInline);
TryGetValue(argc, argv, "rconn", &RepeatConnections);
TryGetValue(argc, argv, "rc", &RepeatConnections);
TryGetValue(argc, argv, "rstream", &RepeatStreams);
TryGetValue(argc, argv, "runtime", &RunTime);
TryGetValue(argc, argv, "time", &RunTime);
TryGetValue(argc, argv, "run", &RunTime);
TryGetValue(argc, argv, "rs", &RepeatStreams);
if ((RepeatConnections || RepeatStreams) && !RunTime) {
WriteOutput("Must specify a 'runtime' if using a repeat parameter!\n");
@ -199,7 +257,7 @@ PerfClient::Init(
RequestBuffer.Init(IoSize, Timed ? UINT64_MAX : Download);
if (PrintLatency) {
if (RunTime) {
MaxLatencyIndex = ((uint64_t)RunTime / 1000) * PERF_MAX_REQUESTS_PER_SECOND;
MaxLatencyIndex = ((uint64_t)RunTime / (1000 * 1000)) * PERF_MAX_REQUESTS_PER_SECOND;
if (MaxLatencyIndex > (UINT32_MAX / sizeof(uint32_t))) {
MaxLatencyIndex = UINT32_MAX / sizeof(uint32_t);
WriteOutput("Warning! Limiting request latency tracking to %llu requests\n",
@ -282,8 +340,8 @@ void
PerfClient::Wait(
_In_ int Timeout
) {
if (Timeout == 0) {
Timeout = RunTime;
if (Timeout == 0 && RunTime != 0) {
Timeout = RunTime < 1000 ? 1 : (int)US_TO_MS(RunTime);
}
if (Timeout) {
@ -304,11 +362,11 @@ PerfClient::Wait(
if (PrintIoRate) {
if (CompletedConnections) {
unsigned long long HPS = CompletedConnections * 1000 / RunTime;
unsigned long long HPS = CompletedConnections * 1000 * 1000 / RunTime;
WriteOutput("Result: %llu HPS\n", HPS);
}
if (CompletedStreams) {
unsigned long long RPS = CompletedStreams * 1000 / RunTime;
unsigned long long RPS = CompletedStreams * 1000 * 1000 / RunTime;
WriteOutput("Result: %llu RPS\n", RPS);
}
} else if (!PrintThroughput && !PrintLatency) {
@ -775,7 +833,7 @@ PerfClientStream::Send() {
SendComplete = true;
} else if (Client.Timed &&
CxPlatTimeDiff64(StartTime, CxPlatTimeUs64()) >= MS_TO_US(Client.Upload)) {
CxPlatTimeDiff64(StartTime, CxPlatTimeUs64()) >= Client.Upload) {
Flags |= QUIC_SEND_FLAG_FIN;
SendComplete = true;
}
@ -854,7 +912,7 @@ PerfClientStream::OnReceive(
OnReceiveShutdown(Now);
} else if (Connection.Client.Timed) {
if (Now == 0) Now = CxPlatTimeUs64();
if (CxPlatTimeDiff64(RecvStartTime, Now) >= MS_TO_US(Connection.Client.Download)) {
if (CxPlatTimeDiff64(RecvStartTime, Now) >= Connection.Client.Download) {
if (Connection.Client.UseTCP) {
auto SendData = Connection.Worker.TcpSendDataPool.Alloc();
SendData->StreamId = (uint32_t)Entry.Signature;

Просмотреть файл

@ -176,7 +176,7 @@ struct PerfClient {
QUIC_ADDR RemoteAddr {0};
uint32_t CibirIdLength {0};
uint8_t CibirId[7]; // {offset, values}
uint8_t IncrementTarget {FALSE};
uint8_t IncrementTarget {TRUE};
// Local execution parameters
uint32_t WorkerCount;
uint8_t AffinitizeWorkers {FALSE};
@ -198,13 +198,13 @@ struct PerfClient {
uint32_t ConnectionCount {1};
uint32_t StreamCount {0};
uint32_t IoSize {PERF_DEFAULT_IO_SIZE};
uint32_t Upload {0};
uint32_t Download {0};
uint64_t Upload {0};
uint64_t Download {0};
uint8_t Timed {FALSE};
//uint8_t SendInline {FALSE};
uint8_t RepeatConnections {FALSE};
uint8_t RepeatStreams {FALSE};
uint32_t RunTime {0};
uint64_t RunTime {0};
struct PerfIoBuffer {
QUIC_BUFFER* Buffer {nullptr};

Просмотреть файл

@ -52,7 +52,7 @@ PrintHelp(
" -ip:<0/4/6> A hint for the resolving the hostname to an IP address. (def:0)\n"
" -port:<####> The UDP port of the server. (def:%u)\n"
" -cibir:<hex_bytes> A CIBIR well-known idenfitier.\n"
" -inctarget:<0/1> Append unique ID to target hostname for each worker (def:0).\n"
" -inctarget:<0/1> Append unique ID to target hostname for each worker (def:1).\n"
"\n"
" Local options:\n"
" -threads:<####> The max number of worker threads to use.\n"
@ -76,14 +76,13 @@ PrintHelp(
" Scenario options:\n"
" -conns:<####> The number of connections to use. (def:1)\n"
" -streams:<####> The number of streams to send on at a time. (def:0)\n"
" -upload:<####> The length of bytes to send on each stream. (def:0)\n"
" -download:<####> The length of bytes to receive on each stream. (def:0)\n"
" -upload:<####>[unit] The length of bytes to send on each stream, with an optional (time or length) unit. (def:0)\n"
" -download:<####>[unit] The length of bytes to receive on each stream, with an optional (time or length) unit. (def:0)\n"
" -iosize:<####> The size of each send request queued.\n"
" -timed:<0/1> Indicates the upload/download args are times (in ms). (def:0)\n"
//" -inline:<0/1> Create new streams on callbacks. (def:0)\n"
" -rconn:<0/1> Repeat the scenario at the connection level. (def:0)\n"
" -rstream:<0/1> Repeat the scenario at the stream level. (def:0)\n"
" -runtime:<####> The total runtime (in ms). Only relevant for repeat scenarios. (def:0)\n"
" -runtime:<####>[unit] The total runtime, with an optional unit (def unit is us). Only relevant for repeat scenarios. (def:0)\n"
"\n"
"Both (client & server) options:\n"
" -exec:<profile> Execution profile to use {lowlat, maxtput, scavenger, realtime}.\n"

Просмотреть файл

@ -10,7 +10,13 @@ The server generally is meant to be run zero or minimal additional arguments.
> secnetperf
```
There are a few arguments that can be passed to the server:
or perhaps the following for high throughput tests:
```
> secnetperf -exec:maxtput
```
There are all the arguments that can be passed to the server:
Argument | Usage | Meaning
--- | --- | ---
@ -26,10 +32,16 @@ stats | `-stats:<0,1>` | Prints out statistics at the end of each connection.
# Client
Since tests are client-driven, the client side of secnetperf generally has several arguments passed in to specify which scenarios to run.
Since tests are client-driven, the client side of secnetperf generally has several arguments passed in to specify which scenarios to run. For example, for a simple download test:
```
> secnetperf -test:client -target:perf-server -download:10000000
> secnetperf -target:perf-server -down:1gb
```
or for a repeated request/response style exchange
```
> secnetperf -target:perf-server -rstream:1 -run:10s -up:500 -down:4000
```
The `target` must be specified to indicate the hostname of the server to connect to. Note that `server`, `to`, `remote`, and `peer` are all aliases for `target`.
@ -81,10 +93,74 @@ Alias | Usage | Meaning
--- | --- | ---
conns | `-conns:<value>` | The number of connections to use.
streams, requests | `-streams:<value>` | The number of streams to send on at a time.
upload, up, request | `-upload:<value>` | The length of bytes to send on each stream.
download, down, response | `-download:<value>` | The length of bytes to receive on each stream.
upload, up, request | `-upload:<value>[units]` | The length of bytes (or optional time or length unit) to send on each stream.
download, down, response | `-download:<value>[units]` | The length of bytes (or optional time or length unit) to receive on each stream.
iosize | `-iosize:<value>` | The size of each send request queued.
timed | `-timed:<0,1>` | Indicates the upload/download args are times (in ms).
rconn | `-rconn:<0,1>` | Repeat the scenario at the connection level.
rstream | `-rstream:<0,1>` | Repeat the scenario at the stream level.
runtime, run, time | `-runtime:<value>` | The total runtime (in ms). Only relevant for repeat scenarios.
rconn, rc | `-rconn:<0,1>` | Repeat the scenario at the connection level.
rstream, rs | `-rstream:<0,1>` | Repeat the scenario at the stream level.
runtime, run, time | `-runtime:<value>[units]` | The total runtime (in us, or optional unit). Only relevant for repeat scenarios.
## Example Scenarios
Download for 5 seconds, printing throughput information
```
> secnetperf -target:localhost -exec:maxtput -down:5s -ptput:1
Started!
Download: 2996595053 bytes @ 4793496 kbps (5001.101 ms).
App Main returning status 0
```
Upload for 1 MB on 10 different streams, printing throughput information
```
> secnetperf -target:localhost -exec:maxtput -up:10mb -streams:10 -ptput:1
Started!
Upload: 10000000 bytes @ 1517393 kbps (52.722 ms).
Upload: 10000000 bytes @ 1513403 kbps (52.861 ms).
Upload: 10000000 bytes @ 1055868 kbps (75.767 ms).
Upload: 10000000 bytes @ 655189 kbps (122.102 ms).
Upload: 10000000 bytes @ 458289 kbps (174.562 ms).
Upload: 10000000 bytes @ 457202 kbps (174.977 ms).
Upload: 10000000 bytes @ 404422 kbps (197.813 ms).
Upload: 10000000 bytes @ 403960 kbps (198.039 ms).
Upload: 10000000 bytes @ 403632 kbps (198.200 ms).
Upload: 10000000 bytes @ 403057 kbps (198.483 ms).
App Main returning status 0
```
Upload for 10 seconds on 10 different connections, printing throughput information
```
> secnetperf -target:localhost -exec:maxtput -up:10s -conns:10 -ptput:1
Started!
Upload: 3590914048 bytes @ 2869166 kbps (10012.423 ms).
Upload: 3586523136 bytes @ 2865446 kbps (10013.163 ms).
Upload: 1803091968 bytes @ 1439601 kbps (10019.950 ms).
Upload: 1765015552 bytes @ 1408638 kbps (10023.949 ms).
Upload: 1161232384 bytes @ 925992 kbps (10032.325 ms).
Upload: 1208811520 bytes @ 963208 kbps (10039.870 ms).
Upload: 1170145280 bytes @ 932025 kbps (10043.895 ms).
Upload: 1198981120 bytes @ 954894 kbps (10044.932 ms).
Upload: 1228996608 bytes @ 977891 kbps (10054.261 ms).
Upload: 1196163072 bytes @ 951211 kbps (10060.125 ms).
App Main returning status 0
```
Send 512 byte requests, receive 4 KB responses on a single connection repeatidly for 7 seconds, printing total requests per second (RPS) and latency at the end
```
> secnetperf -target:localhost -rstream:1 -run:7s -up:512 -down:4kb -plat:1
Started!
Result: 21566 RPS, Latency,us 0th: 39, 50th: 44, 90th: 46, 99th: 108, 99.9th: 166, 99.99th: 235, 99.999th: 7456, 99.9999th: 7567, Max: 7567
App Main returning status 0
```
Do ths same as above, but using TCP/TLS instead of QUIC
```
> secnetperf -target:localhost -rstream:1 -run:7s -up:512 -down:4kb -plat:1 -tcp:1
Started!
Result: 30555 RPS, Latency,us 0th: 24, 50th: 32, 90th: 34, 99th: 81, 99.9th: 131, 99.99th: 192, 99.999th: 456, 99.9999th: 1766, Max: 1766
App Main returning status 0
```