printf("%s%s", name, buf);
}
+static void
+nic_xstats_display_periodic(portid_t port_id)
+{
+ struct xstat_display_info *xstats_info;
+ uint64_t *prev_values, *curr_values;
+ uint64_t diff_value, value_rate;
+ struct timespec cur_time;
+ uint64_t *ids_supp;
+ size_t ids_supp_sz;
+ uint64_t diff_ns;
+ unsigned int i;
+ int rc;
+
+ xstats_info = &ports[port_id].xstats_info;
+
+ ids_supp_sz = xstats_info->ids_supp_sz;
+ if (ids_supp_sz == 0)
+ return;
+
+ printf("\n");
+
+ ids_supp = xstats_info->ids_supp;
+ prev_values = xstats_info->prev_values;
+ curr_values = xstats_info->curr_values;
+
+ rc = rte_eth_xstats_get_by_id(port_id, ids_supp, curr_values,
+ ids_supp_sz);
+ if (rc != (int)ids_supp_sz) {
+ fprintf(stderr,
+ "Failed to get values of %zu xstats for port %u - return code %d\n",
+ ids_supp_sz, port_id, rc);
+ return;
+ }
+
+ diff_ns = 0;
+ if (clock_gettime(CLOCK_TYPE_ID, &cur_time) == 0) {
+ uint64_t ns;
+
+ ns = cur_time.tv_sec * NS_PER_SEC;
+ ns += cur_time.tv_nsec;
+
+ if (xstats_info->prev_ns != 0)
+ diff_ns = ns - xstats_info->prev_ns;
+ xstats_info->prev_ns = ns;
+ }
+
+ printf("%-31s%-17s%s\n", " ", "Value", "Rate (since last show)");
+ for (i = 0; i < ids_supp_sz; i++) {
+ diff_value = (curr_values[i] > prev_values[i]) ?
+ (curr_values[i] - prev_values[i]) : 0;
+ prev_values[i] = curr_values[i];
+ value_rate = diff_ns > 0 ?
+ (double)diff_value / diff_ns * NS_PER_SEC : 0;
+
+ printf(" %-25s%12"PRIu64" %15"PRIu64"\n",
+ xstats_display[i].name, curr_values[i], value_rate);
+ }
+}
+
void
nic_stats_display(portid_t port_id)
{
PRIu64" Tx-bps: %12"PRIu64"\n", mpps_rx, mbps_rx * 8,
mpps_tx, mbps_tx * 8);
+ if (xstats_display_num > 0)
+ nic_xstats_display_periodic(port_id);
+
printf(" %s############################%s\n",
nic_stats_border, nic_stats_border);
}
"(only if interactive is disabled).\n");
printf(" --stats-period=PERIOD: statistics will be shown "
"every PERIOD seconds (only if interactive is disabled).\n");
+ printf(" --display-xstats xstat_name1[,...]: comma-separated list of "
+ "extended statistics to show. Used with --stats-period "
+ "specified or interactive commands that show Rx/Tx statistics "
+ "(i.e. 'show port stats').\n");
printf(" --nb-cores=N: set the number of forwarding cores "
"(1 <= N <= %d).\n", nb_lcores);
printf(" --nb-ports=N: set the number of forwarding ports "
return 0;
}
+static int
+parse_xstats_list(const char *in_str, struct rte_eth_xstat_name **xstats,
+ unsigned int *xstats_num)
+{
+ int max_names_nb, names_nb, nonempty_names_nb;
+ int name, nonempty_name;
+ int stringlen;
+ char **names;
+ char *str;
+ int ret;
+ int i;
+
+ names = NULL;
+ str = strdup(in_str);
+ if (str == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ stringlen = strlen(str);
+
+ for (i = 0, max_names_nb = 1; str[i] != '\0'; i++) {
+ if (str[i] == ',')
+ max_names_nb++;
+ }
+
+ names = calloc(max_names_nb, sizeof(*names));
+ if (names == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ names_nb = rte_strsplit(str, stringlen, names, max_names_nb, ',');
+ if (names_nb < 0) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ nonempty_names_nb = 0;
+ for (i = 0; i < names_nb; i++) {
+ if (names[i][0] == '\0')
+ continue;
+ nonempty_names_nb++;
+ }
+ *xstats = calloc(nonempty_names_nb, sizeof(**xstats));
+ if (*xstats == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ for (name = nonempty_name = 0; name < names_nb; name++) {
+ if (names[name][0] == '\0')
+ continue;
+ rte_strscpy((*xstats)[nonempty_name].name, names[name],
+ sizeof((*xstats)[nonempty_name].name));
+ nonempty_name++;
+ }
+
+ *xstats_num = nonempty_names_nb;
+ ret = 0;
+
+out:
+ free(names);
+ free(str);
+ return ret;
+}
+
static int
parse_link_speed(int n)
{
#endif
{ "tx-first", 0, 0, 0 },
{ "stats-period", 1, 0, 0 },
+ { "display-xstats", 1, 0, 0 },
{ "nb-cores", 1, 0, 0 },
{ "nb-ports", 1, 0, 0 },
{ "coremask", 1, 0, 0 },
stats_period = n;
break;
}
+ if (!strcmp(lgopts[opt_idx].name, "display-xstats")) {
+ char rc;
+
+ rc = parse_xstats_list(optarg, &xstats_display,
+ &xstats_display_num);
+ if (rc != 0)
+ rte_exit(EXIT_FAILURE,
+ "Failed to parse display-xstats argument: %d\n",
+ rc);
+ }
if (!strcmp(lgopts[opt_idx].name,
"eth-peers-configfile")) {
if (init_peer_eth_addrs(optarg) != 0)
* specified on command-line. */
uint16_t stats_period; /**< Period to show statistics (disabled by default) */
+/** Extended statistics to show. */
+struct rte_eth_xstat_name *xstats_display;
+
+unsigned int xstats_display_num; /**< Size of extended statistics to show */
+
/*
* In container, it cannot terminate the process which running with 'stats-period'
* option. Set flag to exit stats period loop after received SIGINT/SIGTERM.
static void dev_event_callback(const char *device_name,
enum rte_dev_event_type type,
void *param);
+static void fill_xstats_display_info(void);
/*
* Check if all the ports are started.
/* Holds the registered mbuf dynamic flags names. */
char dynf_names[64][RTE_MBUF_DYN_NAMESIZE];
+
/*
* Helper function to check if socket is already discovered.
* If yes, return positive value. If not, return zero.
return ret;
}
+static int
+alloc_xstats_display_info(portid_t pi)
+{
+ uint64_t **ids_supp = &ports[pi].xstats_info.ids_supp;
+ uint64_t **prev_values = &ports[pi].xstats_info.prev_values;
+ uint64_t **curr_values = &ports[pi].xstats_info.curr_values;
+
+ if (xstats_display_num == 0)
+ return 0;
+
+ *ids_supp = calloc(xstats_display_num, sizeof(**ids_supp));
+ if (*ids_supp == NULL)
+ goto fail_ids_supp;
+
+ *prev_values = calloc(xstats_display_num,
+ sizeof(**prev_values));
+ if (*prev_values == NULL)
+ goto fail_prev_values;
+
+ *curr_values = calloc(xstats_display_num,
+ sizeof(**curr_values));
+ if (*curr_values == NULL)
+ goto fail_curr_values;
+
+ ports[pi].xstats_info.allocated = true;
+
+ return 0;
+
+fail_curr_values:
+ free(*prev_values);
+fail_prev_values:
+ free(*ids_supp);
+fail_ids_supp:
+ return -ENOMEM;
+}
+
+static void
+free_xstats_display_info(portid_t pi)
+{
+ if (!ports[pi].xstats_info.allocated)
+ return;
+ free(ports[pi].xstats_info.ids_supp);
+ free(ports[pi].xstats_info.prev_values);
+ free(ports[pi].xstats_info.curr_values);
+ ports[pi].xstats_info.allocated = false;
+}
+
+/** Fill helper structures for specified port to show extended statistics. */
+static void
+fill_xstats_display_info_for_port(portid_t pi)
+{
+ unsigned int stat, stat_supp;
+ const char *xstat_name;
+ struct rte_port *port;
+ uint64_t *ids_supp;
+ int rc;
+
+ if (xstats_display_num == 0)
+ return;
+
+ if (pi == (portid_t)RTE_PORT_ALL) {
+ fill_xstats_display_info();
+ return;
+ }
+
+ port = &ports[pi];
+ if (port->port_status != RTE_PORT_STARTED)
+ return;
+
+ if (!port->xstats_info.allocated && alloc_xstats_display_info(pi) != 0)
+ rte_exit(EXIT_FAILURE,
+ "Failed to allocate xstats display memory\n");
+
+ ids_supp = port->xstats_info.ids_supp;
+ for (stat = stat_supp = 0; stat < xstats_display_num; stat++) {
+ xstat_name = xstats_display[stat].name;
+ rc = rte_eth_xstats_get_id_by_name(pi, xstat_name,
+ ids_supp + stat_supp);
+ if (rc != 0) {
+ fprintf(stderr, "No xstat '%s' on port %u - skip it %u\n",
+ xstat_name, pi, stat);
+ continue;
+ }
+ stat_supp++;
+ }
+
+ port->xstats_info.ids_supp_sz = stat_supp;
+}
+
+/** Fill helper structures for all ports to show extended statistics. */
+static void
+fill_xstats_display_info(void)
+{
+ portid_t pi;
+
+ if (xstats_display_num == 0)
+ return;
+
+ RTE_ETH_FOREACH_DEV(pi)
+ fill_xstats_display_info_for_port(pi);
+}
+
int
start_port(portid_t pid)
{
}
}
+ fill_xstats_display_info_for_port(pid);
+
printf("Done\n");
return 0;
}
port_flow_flush(pi);
rte_eth_dev_close(pi);
}
+
+ free_xstats_display_info(pi);
}
remove_invalid_ports();
if (mempools[i])
mempool_free_mp(mempools[i]);
}
+ free(xstats_display);
printf("\nBye...\n");
}
"rte_zmalloc(%d struct rte_port) failed\n",
RTE_MAX_ETHPORTS);
}
+ for (i = 0; i < RTE_MAX_ETHPORTS; i++)
+ ports[i].xstats_info.allocated = false;
for (i = 0; i < RTE_MAX_ETHPORTS; i++)
LIST_INIT(&ports[i].flow_tunnel_list);
/* Initialize ports NUMA structures */
uint32_t items:1;
};
+/** Information for an extended statistics to show. */
+struct xstat_display_info {
+ /** Supported xstats IDs in the order of xstats_display */
+ uint64_t *ids_supp;
+ size_t ids_supp_sz;
+ uint64_t *prev_values;
+ uint64_t *curr_values;
+ uint64_t prev_ns;
+ bool allocated;
+};
+
/**
* The data structure associated with each port.
*/
const struct rte_eth_rxtx_callback *tx_set_dynf_cb[RTE_MAX_QUEUES_PER_PORT+1];
/** Associated port which is supposed to handle "transfer" flows */
portid_t flow_transfer_proxy;
+ struct xstat_display_info xstats_info;
};
/**
extern uint16_t stats_period;
+extern struct rte_eth_xstat_name *xstats_display;
+extern unsigned int xstats_display_num;
+
extern uint16_t hairpin_mode;
#ifdef RTE_LIB_LATENCYSTATS
Display statistics every PERIOD seconds, if interactive mode is disabled.
The default value is 0, which means that the statistics will not be displayed.
+* ``--display-xstats xstat_name1[,...]``
+
+ Display comma-separated list of extended statistics every PERIOD seconds
+ as specified in ``--stats-period`` or when used with interactive commands
+ that show Rx/Tx statistics (i.e. 'show port stats').
+
* ``--nb-cores=N``
Set the number of forwarding cores,