{
ec_main_t *ecm = &ec_main;
clib_spinlock_lock (&ecm->rtt_stats.w_lock);
+ ecm->rtt_stats.last_rtt = session_rtt;
ecm->rtt_stats.sum_rtt += session_rtt;
ecm->rtt_stats.n_sum++;
if (session_rtt < ecm->rtt_stats.min_rtt)
clib_spinlock_unlock (&ecm->rtt_stats.w_lock);
}
+static void
+update_rtt_stats_tcp (ec_session_t *es)
+{
+ session_t *s = session_get_from_handle_if_valid (es->vpp_session_handle);
+ if (s)
+ {
+ transport_connection_t *tc;
+ tcp_connection_t *tcpc;
+ tc = transport_get_connection (TRANSPORT_PROTO_TCP, s->connection_index,
+ s->thread_index);
+ if (PREDICT_TRUE (tc != NULL))
+ {
+ tcpc = tcp_get_connection_from_transport (tc);
+ update_rtt_stats (tcpc->srtt * TCP_TICK);
+ }
+ }
+}
+
static void
send_data_chunk (ec_main_t *ecm, ec_session_t *es)
{
bytes_this_chunk = clib_min (bytes_this_chunk, max_enqueue);
if (!ecm->throughput)
bytes_this_chunk = clib_min (bytes_this_chunk, 1460);
- if (ecm->cfg.test_bytes)
+ if (ecm->include_buffer_offset)
{
/* Include buffer offset info to also be able to verify
* out-of-order packets */
{ (u8 *) &test_buf_offset, sizeof (u32) },
{ test_data + test_buf_offset, bytes_this_chunk }
};
+ if (ecm->echo_bytes &&
+ ((es->rtt_stat & EC_UDP_RTT_TX_FLAG) == 0))
+ {
+ es->rtt_udp_buffer_offset = test_buf_offset;
+ es->send_rtt = vlib_time_now (vlib_get_main ());
+ es->rtt_stat |= EC_UDP_RTT_TX_FLAG;
+ }
rv = app_send_dgram_segs ((app_session_t *) es, data_segs, 2,
bytes_this_chunk + sizeof (u32), 0);
if (rv)
u8 *rx_buf_start = wrk->rx_buf;
u32 test_buf_offset = es->bytes_received;
- if (ecm->cfg.test_bytes)
+ if (ecm->include_buffer_offset)
{
n_read =
app_recv ((app_session_t *) es, wrk->rx_buf, vec_len (wrk->rx_buf));
if (ecm->transport_proto == TRANSPORT_PROTO_UDP && ecm->echo_bytes &&
(es->rtt_stat & EC_UDP_RTT_RX_FLAG) == 0)
{
- es->rtt_stat |= EC_UDP_RTT_RX_FLAG;
- update_rtt_stats (vlib_time_now (vlib_get_main ()) - es->send_rtt);
+ /* For periodic reports, verify that the buffer offset matches and we
+ * received the expected dgram, otherwise just match up the first
+ * received one */
+ if (((test_buf_offset == es->rtt_udp_buffer_offset) &&
+ ecm->report_interval) ||
+ !ecm->report_interval)
+ {
+ f64 rtt;
+ es->rtt_stat |= EC_UDP_RTT_RX_FLAG;
+ rtt = vlib_time_now (vlib_get_main ()) - es->send_rtt;
+ if (ecm->rtt_stats.last_rtt > 0)
+ es->jitter =
+ clib_abs (rtt * 1000 - ecm->rtt_stats.last_rtt * 1000);
+ update_rtt_stats (rtt);
+ }
}
if (ecm->cfg.verbose)
{
if (es->bytes_to_send > 0)
{
- if (ecm->transport_proto == TRANSPORT_PROTO_UDP && ecm->echo_bytes &&
- (es->rtt_stat & EC_UDP_RTT_TX_FLAG) == 0)
- {
- es->send_rtt = time_now;
- es->rtt_stat |= EC_UDP_RTT_TX_FLAG;
- }
send_data_chunk (ecm, es);
if (ecm->throughput)
es->time_to_send += ecm->pacing_window_len;
if (s)
{
if (ecm->transport_proto == TRANSPORT_PROTO_TCP)
- {
- transport_connection_t *tc;
- tcp_connection_t *tcpc;
- tc = transport_get_connection (
- TRANSPORT_PROTO_TCP, s->connection_index, s->thread_index);
- if (PREDICT_TRUE (tc != NULL))
- {
- tcpc = tcp_get_connection_from_transport (tc);
- update_rtt_stats (tcpc->srtt * TCP_TICK);
- }
- }
+ update_rtt_stats_tcp (es);
vnet_disconnect_args_t _a, *a = &_a;
a->handle = session_handle (s);
ecm->last_total_rx_bytes = 0;
ecm->last_total_rx_dgrams = 0;
ecm->last_total_tx_dgrams = 0;
+ ecm->report_interval_jitter = 0;
+ ecm->include_buffer_offset = 0;
clib_memset (&ecm->rtt_stats, 0, sizeof (ec_rttstat_t));
ecm->rtt_stats.min_rtt = CLIB_F64_MAX;
if (ecm->rtt_stats.w_lock == NULL)
ec_print_periodic_stats (vlib_main_t *vm, bool print_header, bool print_footer)
{
ec_main_t *ecm = &ec_main;
- f64 time_now, print_delta, interval_start, interval_end;
+ f64 time_now, print_delta, interval_start, interval_end, rtt = 0.0,
+ jitter = 0.0;
u64 total_bytes,
received_bytes = 0, sent_bytes = 0, dgrams_sent = 0, dgrams_received = 0,
last_total_bytes = ecm->last_total_tx_bytes + ecm->last_total_rx_bytes;
{
dgrams_received += sess->dgrams_received;
dgrams_sent += sess->dgrams_sent;
+ sess->rtt_stat = 0;
+ jitter += sess->jitter;
+ }
+ else if (ecm->transport_proto == TRANSPORT_PROTO_TCP)
+ {
+ session_t *s =
+ session_get_from_handle_if_valid (sess->vpp_session_handle);
+ if (s)
+ {
+ update_rtt_stats_tcp (sess);
+ rtt += ecm->rtt_stats.last_rtt;
+ }
}
}
}
if (ecm->transport_proto == TRANSPORT_PROTO_UDP)
{
- u8 *tput = 0;
+ jitter /= ecm->n_clients;
+ rtt = ecm->rtt_stats.last_rtt * 1000;
if (print_header)
{
ec_cli ("-----------------------------------------------------------"
- "-------------");
+ "-------------------------");
if (ecm->report_interval_total)
- ec_cli ("Run time (s) Transmitted Received Throughput "
- "Sent/received dgrams");
+ ec_cli (
+ "Run time (s) Transmitted Received Throughput "
+ "%sSent/received dgrams",
+ (ecm->report_interval_jitter ? "Jitter " : "Roundtrip "));
else
- ec_cli ("Interval (s) Transmitted Received Throughput "
- "Sent/received dgrams");
+ ec_cli (
+ "Interval (s) Transmitted Received Throughput "
+ "%sSent/received dgrams",
+ (ecm->report_interval_jitter ? "Jitter " : "Roundtrip "));
}
if (ecm->report_interval_total)
{
- tput =
- format (tput, "%Ub/s", format_base10,
- flt_round_nearest ((f64) total_bytes /
- (time_now - ecm->test_start_time)) *
- 8);
- ec_cli ("%-13.1f %-13U %-10U %-12s %llu/%llu", interval_end,
- format_base10, sent_bytes, format_base10, received_bytes,
- tput, dgrams_sent, dgrams_received);
+ ec_cli ("%-13.1f %-13U %-10U %+9Ub/s %+9.3fms %llu/%llu",
+ interval_end, format_base10, sent_bytes, format_base10,
+ received_bytes, format_base10,
+ flt_round_nearest ((f64) (total_bytes - last_total_bytes) /
+ print_delta) *
+ 8,
+ (ecm->report_interval_jitter ? jitter : rtt), dgrams_sent,
+ dgrams_received);
}
else
{
- tput =
- format (tput, "%Ub/s", format_base10,
- flt_round_nearest ((f64) (total_bytes - last_total_bytes) /
- print_delta) *
- 8);
- ec_cli ("%.1f-%-9.1f %-13U %-10U %-12s %llu/%llu", interval_start,
- interval_end, format_base10,
+ rtt /= ecm->n_clients;
+ ec_cli ("%.1f-%-9.1f %-13U %-10U %+9Ub/s %+9.3fms %llu/%llu",
+ interval_start, interval_end, format_base10,
sent_bytes - ecm->last_total_tx_bytes, format_base10,
- received_bytes - ecm->last_total_rx_bytes, tput,
+ received_bytes - ecm->last_total_rx_bytes, format_base10,
+ flt_round_nearest ((f64) (total_bytes - last_total_bytes) /
+ print_delta) *
+ 8,
+ (ecm->report_interval_jitter ? jitter : rtt),
(dgrams_sent - ecm->last_total_tx_dgrams),
(dgrams_received - ecm->last_total_rx_dgrams));
}
if (print_footer)
ec_cli ("-------------------------------------------------------------"
- "-----------");
+ "-----------------------");
ecm->last_total_tx_dgrams = dgrams_sent;
ecm->last_total_rx_dgrams = dgrams_received;
- vec_free (tput);
}
else
{
if (print_header)
{
- ec_cli ("-------------------------------------------------");
+ ec_cli (
+ "-------------------------------------------------------------");
if (ecm->report_interval_total)
- ec_cli ("Run time (s) Transmitted Received Throughput");
+ ec_cli (
+ "Run time (s) Transmitted Received Throughput Roundtrip");
else
- ec_cli ("Interval (s) Transmitted Received Throughput");
+ ec_cli (
+ "Interval (s) Transmitted Received Throughput Roundtrip");
}
if (ecm->report_interval_total)
- ec_cli ("%-13.1f %-13U %-10U %Ub/s", interval_end, format_base10,
- sent_bytes, format_base10, received_bytes, format_base10,
+ ec_cli ("%-13.1f %-13U %-10U %+9Ub/s %+7.3fms", interval_end,
+ format_base10, sent_bytes, format_base10, received_bytes,
+ format_base10,
flt_round_nearest ((f64) total_bytes /
(time_now - ecm->test_start_time)) *
- 8);
+ 8,
+ rtt * 1000);
else
- ec_cli ("%.1f-%-9.1f %-13U %-10U %Ub/s", interval_start, interval_end,
- format_base10, sent_bytes - ecm->last_total_tx_bytes,
- format_base10, received_bytes - ecm->last_total_rx_bytes,
- format_base10,
+ ec_cli ("%.1f-%-9.1f %-13U %-10U %+9Ub/s %+7.3fms", interval_start,
+ interval_end, format_base10,
+ sent_bytes - ecm->last_total_tx_bytes, format_base10,
+ received_bytes - ecm->last_total_rx_bytes, format_base10,
flt_round_nearest (((f64) (total_bytes - last_total_bytes)) /
print_delta) *
- 8);
+ 8,
+ rtt * 1000);
if (print_footer)
- ec_cli ("-------------------------------------------------");
+ ec_cli (
+ "-------------------------------------------------------------");
}
ecm->last_print_time = time_now;
ecm->last_total_tx_bytes = sent_bytes;
ec_cli ("%u bytes/second %s",
flt_round_nearest (((f64) total_bytes) / (total_delta)),
transfer_type);
- ec_cli ("%UBps %s", format_base10,
+ ec_cli ("%UB/s %s", format_base10,
flt_round_nearest (((f64) total_bytes) / (total_delta)),
transfer_type);
}
else if (unformat (line_input, "client-batch %d",
&ecm->connections_per_batch))
;
- else if (unformat (line_input, "report-interval %u",
- &ecm->report_interval))
- ;
+ else if (unformat (line_input, "report-jitter"))
+ ecm->report_interval_jitter = 1;
else if (unformat (line_input, "report-interval-total %u",
&ecm->report_interval))
ecm->report_interval_total = 1;
+ else if (unformat (line_input, "report-interval %u",
+ &ecm->report_interval))
+ ;
else if (unformat (line_input, "report-interval"))
ecm->report_interval = 1;
else if (unformat (line_input, "appns %_%v%_", &ecm->appns_id))
else
ecm->cfg.test = HS_TEST_TYPE_UNI;
+ if (ecm->cfg.test_bytes ||
+ (ecm->echo_bytes && ecm->transport_proto == TRANSPORT_PROTO_UDP))
+ ecm->include_buffer_offset = 1;
+
ec_ctrl_connect ();
ec_wait_for_signal (EC_CLI_CFG_SYNC);
"[run-time <time>][syn-timeout <time>][echo-bytes][fifo-size <size>]"
"[private-segment-count <count>][private-segment-size <bytes>[m|g]]"
"[preallocate-fifos][preallocate-sessions][client-batch <batch-size>]"
- "[throughput <bytes>[m|g]][report-interval[-total] <time>][uri "
+ "[throughput <bytes>[m|g]][report-interval[-total] "
+ "<time>][report-jitter][[uri "
"<tcp://ip/port>]"
"[test-bytes][verbose]",
.function = ec_command_fn,
)
func init() {
- RegisterVethTests(EchoBuiltinTest, EchoBuiltinBandwidthTest, EchoBuiltinEchobytesTest, EchoBuiltinRoundtripTest, EchoBuiltinTestbytesTest, EchoBuiltinPeriodicReportTest, EchoBuiltinPeriodicReportTotalTest, TlsSingleConnectionTest)
+ RegisterVethTests(EchoBuiltinTest, EchoBuiltinBandwidthTest, EchoBuiltinEchobytesTest, EchoBuiltinRoundtripTest, EchoBuiltinTestbytesTest, EchoBuiltinPeriodicReportTest, EchoBuiltinPeriodicReportTotalTest, TlsSingleConnectionTest, EchoBuiltinPeriodicReportUDPTest)
RegisterVethMWTests(TcpWithLossTest)
RegisterSoloVeth6Tests(TcpWithLoss6Test)
}
}
func EchoBuiltinPeriodicReportTotalTest(s *VethsSuite) {
- regex := regexp.MustCompile(`(\d?\.\d)\s+(\d+\.\d+)M\s+0\s+\d+\.\d+Mb/s`)
+ regex := regexp.MustCompile(`(\d?\.\d)\s+(\d+\.\d+)M\s+0\s+\d+\.\d+Mb/s\s+(\d?\.\d+)ms`)
serverVpp := s.Containers.ServerVpp.VppInstance
serverVpp.Vppctl("test echo server " +
for i := 0; i < 4; i++ {
mbytes, _ := strconv.ParseFloat(matches[i][2], 32)
s.AssertEqualWithinThreshold(mbytes, 2*(i+1), 0.1)
+ rtt, _ := strconv.ParseFloat(matches[i][3], 32)
+ s.AssertGreaterThan(rtt, 0.0)
}
// Verify reporting times
s.AssertEqual(matches[0][1], "1.0")
}
}
+func EchoBuiltinPeriodicReportUDPTest(s *VethsSuite) {
+ regex := regexp.MustCompile(`(\d?\.\d)-(\d?.\d)\s+(\d+\.\d+)M\s+\d?\.\d+M\s+\d+\.\d+Mb/s\s+(\d?\.\d+)ms\s+(\d+)/(\d+)`)
+ serverVpp := s.Containers.ServerVpp.VppInstance
+
+ serverVpp.Vppctl("test echo server " +
+ " uri udp://" + s.Interfaces.Server.Ip4AddressString() + "/" + s.Ports.Port1)
+
+ clientVpp := s.Containers.ClientVpp.VppInstance
+
+ o := clientVpp.Vppctl("test echo client bytes 6000k throughput 12m report-interval 1 echo-bytes" +
+ " uri udp://" + s.Interfaces.Server.Ip4AddressString() + "/" + s.Ports.Port1)
+ s.Log(o)
+ s.AssertContains(o, "Test started")
+ s.AssertContains(o, "Test finished")
+ if regex.MatchString(o) {
+ matches := regex.FindAllStringSubmatch(o, -1)
+ // Check we got a correct number of reports
+ s.AssertEqual(4, len(matches))
+ // Verify TX numbers
+ for i := 0; i < 4; i++ {
+ mbytes, _ := strconv.ParseFloat(matches[i][3], 32)
+ s.AssertEqualWithinThreshold(mbytes, 1.5, 0.1)
+ rtt, _ := strconv.ParseFloat(matches[i][4], 32)
+ s.AssertGreaterThan(rtt, 0.0)
+ dgramsSent, _ := strconv.ParseUint(matches[i][5], 10, 32)
+ s.AssertEqualWithinThreshold(dgramsSent, 2048, 20)
+ dgramsReceived, _ := strconv.ParseUint(matches[i][6], 10, 32)
+ s.AssertEqualWithinThreshold(dgramsReceived, 2048, 50)
+ }
+ // Verify time interval numbers
+ s.AssertEqual(matches[0][1], "0.0")
+ s.AssertEqual(matches[0][2], "1.0")
+ s.AssertEqual(matches[1][1], "1.0")
+ s.AssertEqual(matches[1][2], "2.0")
+ s.AssertEqual(matches[2][1], "2.0")
+ s.AssertEqual(matches[2][2], "3.0")
+ s.AssertEqual(matches[3][1], "3.0")
+ s.AssertEqual(matches[3][2], "4.0")
+ } else {
+ s.AssertEmpty("invalid echo test client output")
+ }
+}
+
func EchoBuiltinPeriodicReportTest(s *VethsSuite) {
- regex := regexp.MustCompile(`(\d?\.\d)-(\d?.\d)\s+(\d+\.\d+)M\s+0\s+\d+\.\d+Mb/s`)
+ regex := regexp.MustCompile(`(\d?\.\d)-(\d?.\d)\s+(\d+\.\d+)M\s+0\s+\d+\.\d+Mb/s\s+(\d?\.\d+)ms`)
serverVpp := s.Containers.ServerVpp.VppInstance
serverVpp.Vppctl("test echo server " +
for i := 0; i < 4; i++ {
mbytes, _ := strconv.ParseFloat(matches[i][3], 32)
s.AssertEqualWithinThreshold(mbytes, 2, 0.1)
+ rtt, _ := strconv.ParseFloat(matches[i][4], 32)
+ s.AssertGreaterThan(rtt, 0.0)
}
// Verify time interval numbers
s.AssertEqual(matches[0][1], "0.0")