hsa: unify echo test setup
[vpp.git] / src / plugins / hs_apps / echo_client.c
index d449045..344f4af 100644 (file)
 
 static ec_main_t ec_main;
 
-#define EC_DBG (0)
-#define DBG(_fmt, _args...)                                                   \
-  if (EC_DBG)                                                                 \
-  clib_warning (_fmt, ##_args)
+#define ec_err(_fmt, _args...) clib_warning (_fmt, ##_args);
+
+#define ec_dbg(_fmt, _args...)                                                \
+  do                                                                          \
+    {                                                                         \
+      if (ec_main.cfg.verbose)                                                \
+       ec_err (_fmt, ##_args);                                               \
+    }                                                                         \
+  while (0)
+
+#define ec_cli(_fmt, _args...) vlib_cli_output (vm, _fmt, ##_args)
 
 static void
 signal_evt_to_cli_i (void *codep)
@@ -143,7 +150,7 @@ send_data_chunk (ec_main_t *ecm, ec_session_t *es)
       es->bytes_to_send -= rv;
       es->bytes_sent += rv;
 
-      if (EC_DBG)
+      if (ecm->cfg.verbose)
        {
           ELOG_TYPE_DECLARE (e) =
             {
@@ -169,7 +176,7 @@ receive_data_chunk (ec_worker_t *wrk, ec_session_t *es)
   svm_fifo_t *rx_fifo = es->data.rx_fifo;
   int n_read, i;
 
-  if (ecm->test_bytes)
+  if (ecm->cfg.test_bytes)
     {
       if (!ecm->is_dgram)
        n_read =
@@ -186,7 +193,7 @@ receive_data_chunk (ec_worker_t *wrk, ec_session_t *es)
 
   if (n_read > 0)
     {
-      if (EC_DBG)
+      if (ecm->cfg.verbose)
        {
           ELOG_TYPE_DECLARE (e) =
             {
@@ -201,15 +208,15 @@ receive_data_chunk (ec_worker_t *wrk, ec_session_t *es)
          ed->data[0] = n_read;
        }
 
-      if (ecm->test_bytes)
+      if (ecm->cfg.test_bytes)
        {
          for (i = 0; i < n_read; i++)
            {
              if (wrk->rx_buf[i] != ((es->bytes_received + i) & 0xff))
                {
-                 clib_warning ("read %d error at byte %lld, 0x%x not 0x%x",
-                               n_read, es->bytes_received + i, wrk->rx_buf[i],
-                               ((es->bytes_received + i) & 0xff));
+                 ec_err ("read %d error at byte %lld, 0x%x not 0x%x", n_read,
+                         es->bytes_received + i, wrk->rx_buf[i],
+                         ((es->bytes_received + i) & 0xff));
                  ecm->test_failed = 1;
                }
            }
@@ -265,7 +272,7 @@ ec_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
       ecm->prev_conns = vec_len (conns_this_batch);
       if (ecm->repeats == 500000)
        {
-         clib_warning ("stuck clients");
+         ec_err ("stuck clients");
        }
     }
   else
@@ -313,7 +320,7 @@ ec_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
            }
          else
            {
-             clib_warning ("session AWOL?");
+             ec_err ("session AWOL?");
              vec_delete (conns_this_batch, 1, i);
            }
 
@@ -340,16 +347,15 @@ VLIB_REGISTER_NODE (echo_clients_node) = {
 static void
 ec_reset_runtime_config (ec_main_t *ecm)
 {
+  hs_test_cfg_init (&ecm->cfg);
   ecm->n_clients = 1;
   ecm->quic_streams = 1;
   ecm->bytes_to_send = 8192;
-  ecm->no_return = 0;
+  ecm->echo_bytes = 0;
   ecm->fifo_size = 64 << 10;
   ecm->connections_per_batch = 1000;
   ecm->private_segment_count = 0;
   ecm->private_segment_size = 256 << 20;
-  ecm->no_output = 0;
-  ecm->test_bytes = 0;
   ecm->test_failed = 0;
   ecm->tls_engine = CRYPTO_ENGINE_OPENSSL;
   ecm->no_copy = 0;
@@ -480,39 +486,71 @@ quic_ec_qsession_connected_callback (u32 app_index, u32 api_context,
 {
   session_endpoint_cfg_t sep = SESSION_ENDPOINT_CFG_NULL;
   ec_main_t *ecm = &ec_main;
-  vnet_connect_args_t *a = 0;
-  session_handle_t handle;
+  vnet_connect_args_t _a, *a = &_a;
   u32 stream_n;
   int rv;
 
-  DBG ("QUIC Connection handle %d", session_handle (s));
+  ec_dbg ("QUIC Connection handle %d", session_handle (s));
 
-  vec_validate (a, 1);
   a->uri = (char *) ecm->connect_uri;
   if (parse_uri (a->uri, &sep))
     return -1;
-  sep.parent_handle = handle = session_handle (s);
+  sep.parent_handle = session_handle (s);
 
   for (stream_n = 0; stream_n < ecm->quic_streams; stream_n++)
     {
       clib_memset (a, 0, sizeof (*a));
       a->app_index = ecm->app_index;
-      a->api_context = -1 - api_context;
+      a->api_context = -2 - api_context;
       clib_memcpy (&a->sep_ext, &sep, sizeof (sep));
 
-      DBG ("QUIC opening stream %d", stream_n);
+      ec_dbg ("QUIC opening stream %d", stream_n);
       if ((rv = vnet_connect (a)))
        {
          clib_error ("Stream session %d opening failed: %d", stream_n, rv);
          return -1;
        }
-      DBG ("QUIC stream %d connected", stream_n);
+      ec_dbg ("QUIC stream %d connected", stream_n);
     }
-  /*
-   * 's' is no longer valid, its underlying pool could have been moved in
-   * vnet_connect()
-   */
-  vec_free (a);
+  return 0;
+}
+
+static int
+ec_ctrl_send (hs_test_cmd_t cmd)
+{
+  ec_main_t *ecm = &ec_main;
+  session_t *s;
+  int rv;
+
+  ecm->cfg.cmd = cmd;
+  if (ecm->ctrl_session_handle == SESSION_INVALID_HANDLE)
+    {
+      ec_dbg ("ctrl session went away");
+      return -1;
+    }
+
+  s = session_get_from_handle_if_valid (ecm->ctrl_session_handle);
+
+  ec_dbg ("sending test paramters to the server..");
+  if (ecm->cfg.verbose)
+    hs_test_cfg_dump (&ecm->cfg, 1);
+
+  rv = svm_fifo_enqueue (s->tx_fifo, sizeof (ecm->cfg), (u8 *) &ecm->cfg);
+  ASSERT (rv == sizeof (ecm->cfg));
+  session_send_io_evt_to_thread (s->tx_fifo, SESSION_IO_EVT_TX);
+  return 0;
+}
+
+static int
+ec_ctrl_session_connected_callback (session_t *s)
+{
+  ec_main_t *ecm = &ec_main;
+
+  s->opaque = HS_CTRL_HANDLE;
+  ecm->ctrl_session_handle = session_handle (s);
+
+  /* send test parameters to the server */
+  ec_ctrl_send (HS_TEST_CMD_SYNC);
   return 0;
 }
 
@@ -525,12 +563,15 @@ quic_ec_session_connected_callback (u32 app_index, u32 api_context,
   ec_worker_t *wrk;
   u32 thread_index;
 
+  if (PREDICT_FALSE (api_context == HS_CTRL_HANDLE))
+    return ec_ctrl_session_connected_callback (s);
+
   if (PREDICT_FALSE (ecm->run_test != EC_STARTING))
     return -1;
 
   if (err)
     {
-      clib_warning ("connection %d failed!", api_context);
+      ec_err ("connection %d failed!", api_context);
       ecm->run_test = EC_EXITING;
       signal_evt_to_cli (EC_CLI_CONNECTS_FAILED);
       return 0;
@@ -539,7 +580,7 @@ quic_ec_session_connected_callback (u32 app_index, u32 api_context,
   if (s->listener_handle == SESSION_INVALID_HANDLE)
     return quic_ec_qsession_connected_callback (app_index, api_context, s,
                                                err);
-  DBG ("STREAM Connection callback %d", api_context);
+  ec_dbg ("STREAM Connection callback %d", api_context);
 
   thread_index = s->thread_index;
   ASSERT (thread_index == vlib_get_thread_index ()
@@ -553,7 +594,7 @@ quic_ec_session_connected_callback (u32 app_index, u32 api_context,
   es = ec_session_alloc (wrk);
 
   es->bytes_to_send = ecm->bytes_to_send;
-  es->bytes_to_receive = ecm->no_return ? 0ULL : ecm->bytes_to_send;
+  es->bytes_to_receive = ecm->echo_bytes ? ecm->bytes_to_send : 0ULL;
   es->data.rx_fifo = s->rx_fifo;
   es->data.rx_fifo->shr->client_session_index = es->data.session_index;
   es->data.tx_fifo = s->tx_fifo;
@@ -597,7 +638,8 @@ ec_session_connected_callback (u32 app_index, u32 api_context, session_t *s,
 
   if (err)
     {
-      clib_warning ("connection %d failed!", api_context);
+      ec_err ("connection %d failed! %U", api_context, format_session_error,
+             err);
       ecm->run_test = EC_EXITING;
       signal_evt_to_cli (EC_CLI_CONNECTS_FAILED);
       return 0;
@@ -607,6 +649,9 @@ ec_session_connected_callback (u32 app_index, u32 api_context, session_t *s,
   ASSERT (thread_index == vlib_get_thread_index ()
          || session_transport_service_type (s) == TRANSPORT_SERVICE_CL);
 
+  if (PREDICT_FALSE (api_context == HS_CTRL_HANDLE))
+    return ec_ctrl_session_connected_callback (s);
+
   wrk = ec_worker_get (thread_index);
 
   /*
@@ -615,7 +660,7 @@ ec_session_connected_callback (u32 app_index, u32 api_context, session_t *s,
   es = ec_session_alloc (wrk);
 
   es->bytes_to_send = ecm->bytes_to_send;
-  es->bytes_to_receive = ecm->no_return ? 0ULL : ecm->bytes_to_send;
+  es->bytes_to_receive = ecm->echo_bytes ? ecm->bytes_to_send : 0ULL;
   es->data.rx_fifo = s->rx_fifo;
   es->data.rx_fifo->shr->client_session_index = es->data.session_index;
   es->data.tx_fifo = s->tx_fifo;
@@ -652,7 +697,7 @@ ec_session_reset_callback (session_t *s)
   vnet_disconnect_args_t _a = { 0 }, *a = &_a;
 
   if (s->session_state == SESSION_STATE_READY)
-    clib_warning ("Reset active connection %U", format_session, s, 2);
+    ec_err ("Reset active connection %U", format_session, s, 2);
 
   a->handle = session_handle (s);
   a->app_index = ecm->app_index;
@@ -671,6 +716,13 @@ ec_session_disconnect_callback (session_t *s)
 {
   ec_main_t *ecm = &ec_main;
   vnet_disconnect_args_t _a = { 0 }, *a = &_a;
+
+  if (session_handle (s) == ecm->ctrl_session_handle)
+    {
+      ec_dbg ("ctrl session disconnect");
+      ecm->ctrl_session_handle = SESSION_INVALID_HANDLE;
+    }
+
   a->handle = session_handle (s);
   a->app_index = ecm->app_index;
   vnet_disconnect_session (a);
@@ -687,6 +739,68 @@ ec_session_disconnect (session_t *s)
   vnet_disconnect_session (a);
 }
 
+static int
+ec_ctrl_session_rx_callback (session_t *s)
+{
+  ec_main_t *ecm = &ec_main;
+  int rx_bytes;
+  hs_test_cfg_t cfg = { 0 };
+
+  rx_bytes = svm_fifo_dequeue (s->rx_fifo, sizeof (cfg), (u8 *) &cfg);
+  if (rx_bytes != sizeof (cfg))
+    {
+      ec_err ("invalid cfg length %d (expected %d)", rx_bytes, sizeof (cfg));
+      signal_evt_to_cli (EC_CLI_CONNECTS_FAILED);
+      return -1;
+    }
+
+  ec_dbg ("control message received:");
+  if (ecm->cfg.verbose)
+    hs_test_cfg_dump (&cfg, 1);
+
+  switch (cfg.cmd)
+    {
+    case HS_TEST_CMD_SYNC:
+      switch (ecm->run_test)
+       {
+       case EC_STARTING:
+         if (!hs_test_cfg_verify (&cfg, &ecm->cfg))
+           {
+             ec_err ("invalid config received from server!");
+             signal_evt_to_cli (EC_CLI_CONNECTS_FAILED);
+             return -1;
+           }
+         signal_evt_to_cli (EC_CLI_CFG_SYNC);
+         break;
+
+       case EC_RUNNING:
+         ec_dbg ("test running..");
+         break;
+
+       case EC_EXITING:
+         /* post test sync */
+         signal_evt_to_cli (EC_CLI_CFG_SYNC);
+         break;
+
+       default:
+         ec_err ("unexpected test state! %d", ecm->run_test);
+         break;
+       }
+      break;
+    case HS_TEST_CMD_START:
+      signal_evt_to_cli (EC_CLI_START);
+      break;
+    case HS_TEST_CMD_STOP:
+      signal_evt_to_cli (EC_CLI_STOP);
+      break;
+    default:
+      ec_err ("unexpected cmd! %d", cfg.cmd);
+      break;
+    }
+
+  return 0;
+}
+
 static int
 ec_session_rx_callback (session_t *s)
 {
@@ -694,6 +808,9 @@ ec_session_rx_callback (session_t *s)
   ec_worker_t *wrk;
   ec_session_t *es;
 
+  if (PREDICT_FALSE (s->opaque == HS_CTRL_HANDLE))
+    return ec_ctrl_session_rx_callback (s);
+
   if (PREDICT_FALSE (ecm->run_test != EC_RUNNING))
     {
       ec_session_disconnect (s);
@@ -859,7 +976,7 @@ ec_connect_rpc (void *args)
 
       if (rv)
        {
-         clib_warning ("connect returned: %U", format_session_error, rv);
+         ec_err ("connect returned: %U", format_session_error, rv);
          ecm->run_test = EC_EXITING;
          signal_evt_to_cli (EC_CLI_CONNECTS_FAILED);
          break;
@@ -881,9 +998,89 @@ ec_program_connects (void)
                                        0);
 }
 
-#define ec_cli(_fmt, _args...)                                                \
-  if (!ecm->no_output)                                                        \
-  vlib_cli_output (vm, _fmt, ##_args)
+static clib_error_t *
+ec_ctrl_connect_rpc ()
+{
+  session_error_t rv;
+  ec_main_t *ecm = &ec_main;
+  vnet_connect_args_t _a = {}, *a = &_a;
+
+  a->api_context = HS_CTRL_HANDLE;
+  ecm->cfg.cmd = HS_TEST_CMD_SYNC;
+  clib_memcpy (&a->sep_ext, &ecm->connect_sep, sizeof (ecm->connect_sep));
+  a->sep_ext.transport_proto = TRANSPORT_PROTO_TCP;
+  a->app_index = ecm->app_index;
+
+  rv = vnet_connect (a);
+  if (rv)
+    {
+      ec_err ("ctrl connect returned: %U", format_session_error, rv);
+      ecm->run_test = EC_EXITING;
+      signal_evt_to_cli (EC_CLI_CONNECTS_FAILED);
+    }
+  return 0;
+}
+
+static void
+ec_ctrl_connect (void)
+{
+  session_send_rpc_evt_to_thread_force (transport_cl_thread (),
+                                       ec_ctrl_connect_rpc, 0);
+}
+
+static void
+ec_ctrl_session_disconnect ()
+{
+  ec_main_t *ecm = &ec_main;
+  vnet_disconnect_args_t _a, *a = &_a;
+  session_error_t err;
+
+  a->handle = ecm->ctrl_session_handle;
+  a->app_index = ecm->app_index;
+  err = vnet_disconnect_session (a);
+  if (err)
+    ec_err ("vnet_disconnect_session: %U", format_session_error, err);
+}
+
+static int
+ec_ctrl_test_sync ()
+{
+  ec_main_t *ecm = &ec_main;
+  ecm->cfg.test = HS_TEST_TYPE_ECHO;
+  return ec_ctrl_send (HS_TEST_CMD_SYNC);
+}
+
+static int
+ec_ctrl_test_start ()
+{
+  return ec_ctrl_send (HS_TEST_CMD_START);
+}
+
+static int
+ec_ctrl_test_stop ()
+{
+  return ec_ctrl_send (HS_TEST_CMD_STOP);
+}
+
+#define ec_wait_for_signal(_sig)                                              \
+  vlib_process_wait_for_event_or_clock (vm, ecm->syn_timeout);                \
+  event_type = vlib_process_get_events (vm, &event_data);                     \
+  switch (event_type)                                                         \
+    {                                                                         \
+    case ~0:                                                                  \
+      ec_cli ("Timeout while waiting for " #_sig);                            \
+      error =                                                                 \
+       clib_error_return (0, "failed: timeout while waiting for " #_sig);    \
+      goto cleanup;                                                           \
+    case _sig:                                                                \
+      break;                                                                  \
+    default:                                                                  \
+      ec_cli ("unexpected event while waiting for " #_sig ": %d",             \
+             event_type);                                                    \
+      error =                                                                 \
+       clib_error_return (0, "failed: unexpected event: %d", event_type);    \
+      goto cleanup;                                                           \
+    }
 
 static clib_error_t *
 ec_command_fn (vlib_main_t *vm, unformat_input_t *input,
@@ -932,10 +1129,11 @@ ec_command_fn (vlib_main_t *vm, unformat_input_t *input,
        ;
       else if (unformat (line_input, "syn-timeout %f", &ecm->syn_timeout))
        ;
-      else if (unformat (line_input, "no-return"))
-       ecm->no_return = 1;
-      else if (unformat (line_input, "fifo-size %d", &ecm->fifo_size))
-       ecm->fifo_size <<= 10;
+      else if (unformat (line_input, "echo-bytes"))
+       ecm->echo_bytes = 1;
+      else if (unformat (line_input, "fifo-size %U", unformat_memory_size,
+                        &ecm->fifo_size))
+       ;
       else if (unformat (line_input, "private-segment-count %d",
                         &ecm->private_segment_count))
        ;
@@ -960,10 +1158,10 @@ ec_command_fn (vlib_main_t *vm, unformat_input_t *input,
        ecm->attach_flags = APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
       else if (unformat (line_input, "secret %lu", &ecm->appns_secret))
        ;
-      else if (unformat (line_input, "no-output"))
-       ecm->no_output = 1;
+      else if (unformat (line_input, "verbose"))
+       ecm->cfg.verbose = 1;
       else if (unformat (line_input, "test-bytes"))
-       ecm->test_bytes = 1;
+       ecm->cfg.test_bytes = 1;
       else if (unformat (line_input, "tls-engine %d", &ecm->tls_engine))
        ;
       else
@@ -976,11 +1174,12 @@ ec_command_fn (vlib_main_t *vm, unformat_input_t *input,
 
 parse_config:
 
-  ecm->expected_connections = ecm->n_clients * ecm->quic_streams;
+  ecm->cfg.num_test_sessions = ecm->expected_connections =
+    ecm->n_clients * ecm->quic_streams;
 
   if (!ecm->connect_uri)
     {
-      clib_warning ("No uri provided. Using default: %s", default_uri);
+      ec_cli ("No uri provided. Using default: %s", default_uri);
       ecm->connect_uri = format (0, "%s%c", default_uri, 0);
     }
 
@@ -1001,10 +1200,28 @@ parse_config:
       goto cleanup;
     }
 
+  if (ecm->echo_bytes)
+    ecm->cfg.test = HS_TEST_TYPE_BI;
+  else
+    ecm->cfg.test = HS_TEST_TYPE_UNI;
+
+  ec_ctrl_connect ();
+  ec_wait_for_signal (EC_CLI_CFG_SYNC);
+
+  if (ec_ctrl_test_start () < 0)
+    {
+      ec_cli ("failed to send start command");
+      goto cleanup;
+    }
+  ec_wait_for_signal (EC_CLI_START);
+
   /*
    * Start. Fire off connect requests
    */
 
+  /* update data port */
+  ecm->connect_sep.port = hs_make_data_port (ecm->connect_sep.port);
+
   ecm->syn_start_time = vlib_time_now (vm);
   ec_program_connects ();
 
@@ -1021,7 +1238,7 @@ parse_config:
              ecm->ready_connections);
       error = clib_error_return (0, "failed: syn timeout with %d sessions",
                                 ecm->ready_connections);
-      goto cleanup;
+      goto stop_test;
 
     case EC_CLI_CONNECTS_DONE:
       delta = vlib_time_now (vm) - ecm->syn_start_time;
@@ -1032,13 +1249,13 @@ parse_config:
 
     case EC_CLI_CONNECTS_FAILED:
       error = clib_error_return (0, "failed: connect returned");
-      goto cleanup;
+      goto stop_test;
 
     default:
-      ec_cli ("unexpected event(1): %d", event_type);
-      error = clib_error_return (0, "failed: unexpected event(1): %d",
-                                event_type);
-      goto cleanup;
+      ec_cli ("unexpected event(2): %d", event_type);
+      error =
+       clib_error_return (0, "failed: unexpected event(2): %d", event_type);
+      goto stop_test;
     }
 
   /*
@@ -1055,7 +1272,7 @@ parse_config:
              vlib_time_now (ecm->vlib_main), ecm->ready_connections);
       error = clib_error_return (0, "failed: timeout with %d sessions",
                                 ecm->ready_connections);
-      goto cleanup;
+      goto stop_test;
 
     case EC_CLI_TEST_DONE:
       ecm->test_end_time = vlib_time_now (vm);
@@ -1063,10 +1280,10 @@ parse_config:
       break;
 
     default:
-      ec_cli ("unexpected event(2): %d", event_type);
-      error = clib_error_return (0, "failed: unexpected event(2): %d",
-                                event_type);
-      goto cleanup;
+      ec_cli ("unexpected event(3): %d", event_type);
+      error =
+       clib_error_return (0, "failed: unexpected event(3): %d", event_type);
+      goto stop_test;
     }
 
   /*
@@ -1077,11 +1294,11 @@ parse_config:
     {
       ec_cli ("zero delta-t?");
       error = clib_error_return (0, "failed: zero delta-t");
-      goto cleanup;
+      goto stop_test;
     }
 
-  total_bytes = (ecm->no_return ? ecm->tx_total : ecm->rx_total);
-  transfer_type = ecm->no_return ? "half-duplex" : "full-duplex";
+  total_bytes = (ecm->echo_bytes ? ecm->rx_total : ecm->tx_total);
+  transfer_type = ecm->echo_bytes ? "full-duplex" : "half-duplex";
   ec_cli ("%lld bytes (%lld mbytes, %lld gbytes) in %.2f seconds", total_bytes,
          total_bytes / (1ULL << 20), total_bytes / (1ULL << 30), delta);
   ec_cli ("%.2f bytes/second %s", ((f64) total_bytes) / (delta),
@@ -1089,14 +1306,33 @@ parse_config:
   ec_cli ("%.4f gbit/second %s", (((f64) total_bytes * 8.0) / delta / 1e9),
          transfer_type);
 
-  if (ecm->test_bytes && ecm->test_failed)
+  if (ecm->cfg.test_bytes && ecm->test_failed)
     error = clib_error_return (0, "failed: test bytes");
 
+stop_test:
+  ecm->run_test = EC_EXITING;
+
+  /* send stop test command to the server */
+  if (ec_ctrl_test_stop () < 0)
+    {
+      ec_cli ("failed to send stop command");
+      goto cleanup;
+    }
+  ec_wait_for_signal (EC_CLI_STOP);
+
+  /* post test sync */
+  if (ec_ctrl_test_sync () < 0)
+    {
+      ec_cli ("failed to send post sync command");
+      goto cleanup;
+    }
+  ec_wait_for_signal (EC_CLI_CFG_SYNC);
+
+  /* disconnect control session */
+  ec_ctrl_session_disconnect ();
+
 cleanup:
 
-  /*
-   * Cleanup
-   */
   ecm->run_test = EC_EXITING;
   vlib_process_wait_for_event_or_clock (vm, 10e-3);
 
@@ -1121,10 +1357,10 @@ VLIB_CLI_COMMAND (ec_command, static) = {
   .path = "test echo clients",
   .short_help =
     "test echo clients [nclients %d][[m|g]bytes <bytes>]"
-    "[test-timeout <time>][syn-timeout <time>][no-return][fifo-size <size>]"
+    "[test-timeout <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>]"
-    "[uri <tcp://ip/port>][test-bytes][no-output]",
+    "[uri <tcp://ip/port>][test-bytes][verbose]",
   .function = ec_command_fn,
   .is_mp_safe = 1,
 };