Skip to content

Commit

Permalink
ethdev: new method to retrieve extended statistics
Browse files Browse the repository at this point in the history
This method can be implemented by a poll mode driver to provide
non-standard statistics (which are not part of the generic statistics
structure). Each statistic is returned in a generic form: "name" and
"value" and can be used to dump PMD-specific statistics in the same way
than ethtool in linux kernel.

If the PMD does not provide the xstats_get and xstats_set functions, the
ethdev API will return the generic statistics in the xstats format
(name, value).

This commit opens the door for a clean-up of the generic statistics
structure, only keeping statistics that are really common to all PMDs
and moving specific ones into the xstats API.

Signed-off-by: Olivier Matz <olivier.matz@6wind.com>
Reviewed-by: David Marchand <david.marchand@6wind.com>
Acked-by: Bruce Richardson <bruce.richardson@intel.com>
[Thomas: fix some comments]
Acked-by: Thomas Monjalon <thomas.monjalon@6wind.com>
  • Loading branch information
olivier-matz-6wind authored and Thomas Monjalon committed Sep 23, 2014
1 parent fbe37a7 commit ce757f5
Show file tree
Hide file tree
Showing 2 changed files with 195 additions and 2 deletions.
137 changes: 137 additions & 0 deletions lib/librte_ether/rte_ethdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,48 @@ static uint8_t nb_ports = 0;
/* spinlock for eth device callbacks */
static rte_spinlock_t rte_eth_dev_cb_lock = RTE_SPINLOCK_INITIALIZER;

/* store statistics names and its offset in stats structure */
struct rte_eth_xstats_name_off {
char name[RTE_ETH_XSTATS_NAME_SIZE];
unsigned offset;
};

static struct rte_eth_xstats_name_off rte_stats_strings[] = {
{"rx_packets", offsetof(struct rte_eth_stats, ipackets)},
{"tx_packets", offsetof(struct rte_eth_stats, opackets)},
{"rx_bytes", offsetof(struct rte_eth_stats, ibytes)},
{"tx_bytes", offsetof(struct rte_eth_stats, obytes)},
{"tx_errors", offsetof(struct rte_eth_stats, oerrors)},
{"rx_missed_errors", offsetof(struct rte_eth_stats, imissed)},
{"rx_crc_errors", offsetof(struct rte_eth_stats, ibadcrc)},
{"rx_bad_length_errors", offsetof(struct rte_eth_stats, ibadlen)},
{"rx_errors", offsetof(struct rte_eth_stats, ierrors)},
{"alloc_rx_buff_failed", offsetof(struct rte_eth_stats, rx_nombuf)},
{"fdir_match", offsetof(struct rte_eth_stats, fdirmatch)},
{"fdir_miss", offsetof(struct rte_eth_stats, fdirmiss)},
{"tx_flow_control_xon", offsetof(struct rte_eth_stats, tx_pause_xon)},
{"rx_flow_control_xon", offsetof(struct rte_eth_stats, rx_pause_xon)},
{"tx_flow_control_xoff", offsetof(struct rte_eth_stats, tx_pause_xoff)},
{"rx_flow_control_xoff", offsetof(struct rte_eth_stats, rx_pause_xoff)},
};
#define RTE_NB_STATS (sizeof(rte_stats_strings) / sizeof(rte_stats_strings[0]))

static struct rte_eth_xstats_name_off rte_rxq_stats_strings[] = {
{"rx_packets", offsetof(struct rte_eth_stats, q_ipackets)},
{"rx_bytes", offsetof(struct rte_eth_stats, q_ibytes)},
};
#define RTE_NB_RXQ_STATS (sizeof(rte_rxq_stats_strings) / \
sizeof(rte_rxq_stats_strings[0]))

static struct rte_eth_xstats_name_off rte_txq_stats_strings[] = {
{"tx_packets", offsetof(struct rte_eth_stats, q_opackets)},
{"tx_bytes", offsetof(struct rte_eth_stats, q_obytes)},
{"tx_errors", offsetof(struct rte_eth_stats, q_errors)},
};
#define RTE_NB_TXQ_STATS (sizeof(rte_txq_stats_strings) / \
sizeof(rte_txq_stats_strings[0]))


/**
* The user application callback description.
*
Expand Down Expand Up @@ -1201,6 +1243,101 @@ rte_eth_stats_reset(uint8_t port_id)
(*dev->dev_ops->stats_reset)(dev);
}

/* retrieve ethdev extended statistics */
int
rte_eth_xstats_get(uint8_t port_id, struct rte_eth_xstats *xstats,
unsigned n)
{
struct rte_eth_stats eth_stats;
struct rte_eth_dev *dev;
unsigned count, i, q;
uint64_t val;
char *stats_ptr;

if (port_id >= nb_ports) {
PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
return -1;
}
dev = &rte_eth_devices[port_id];

/* implemented by the driver */
if (dev->dev_ops->xstats_get != NULL)
return (*dev->dev_ops->xstats_get)(dev, xstats, n);

/* else, return generic statistics */
count = RTE_NB_STATS;
count += dev->data->nb_rx_queues * RTE_NB_RXQ_STATS;
count += dev->data->nb_tx_queues * RTE_NB_TXQ_STATS;
if (n < count)
return count;

/* now fill the xstats structure */

count = 0;
memset(&eth_stats, 0, sizeof(eth_stats));
rte_eth_stats_get(port_id, &eth_stats);

/* global stats */
for (i = 0; i < RTE_NB_STATS; i++) {
stats_ptr = (char *)&eth_stats + rte_stats_strings[i].offset;
val = *(uint64_t *)stats_ptr;
snprintf(xstats[count].name, sizeof(xstats[count].name),
"%s", rte_stats_strings[i].name);
xstats[count++].value = val;
}

/* per-rxq stats */
for (q = 0; q < dev->data->nb_rx_queues; q++) {
for (i = 0; i < RTE_NB_RXQ_STATS; i++) {
stats_ptr = (char *)&eth_stats;
stats_ptr += rte_rxq_stats_strings[i].offset;
stats_ptr += q * sizeof(uint64_t);
val = *(uint64_t *)stats_ptr;
snprintf(xstats[count].name, sizeof(xstats[count].name),
"rx_queue_%u_%s", q,
rte_rxq_stats_strings[i].name);
xstats[count++].value = val;
}
}

/* per-txq stats */
for (q = 0; q < dev->data->nb_tx_queues; q++) {
for (i = 0; i < RTE_NB_TXQ_STATS; i++) {
stats_ptr = (char *)&eth_stats;
stats_ptr += rte_txq_stats_strings[i].offset;
stats_ptr += q * sizeof(uint64_t);
val = *(uint64_t *)stats_ptr;
snprintf(xstats[count].name, sizeof(xstats[count].name),
"tx_queue_%u_%s", q,
rte_txq_stats_strings[i].name);
xstats[count++].value = val;
}
}

return count;
}

/* reset ethdev extended statistics */
void
rte_eth_xstats_reset(uint8_t port_id)
{
struct rte_eth_dev *dev;

if (port_id >= nb_ports) {
PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
return;
}
dev = &rte_eth_devices[port_id];

/* implemented by the driver */
if (dev->dev_ops->xstats_reset != NULL) {
(*dev->dev_ops->xstats_reset)(dev);
return;
}

/* fallback to default */
rte_eth_stats_reset(port_id);
}

static int
set_queue_stats_mapping(uint8_t port_id, uint16_t queue_id, uint8_t stat_idx,
Expand Down
60 changes: 58 additions & 2 deletions lib/librte_ether/rte_ethdev.h
Original file line number Diff line number Diff line change
Expand Up @@ -908,6 +908,21 @@ struct rte_eth_dev_info {
uint32_t tx_offload_capa; /**< Device TX offload capabilities. */
};

/** Maximum name length for extended statistics counters */
#define RTE_ETH_XSTATS_NAME_SIZE 64

/**
* An Ethernet device extended statistic structure
*
* This structure is used by ethdev->eth_xstats_get() to provide
* statistics that are not provided in the generic rte_eth_stats
* structure.
*/
struct rte_eth_xstats {
char name[RTE_ETH_XSTATS_NAME_SIZE];
uint64_t value;
};

struct rte_eth_dev;

struct rte_eth_dev_callback;
Expand Down Expand Up @@ -1028,6 +1043,13 @@ typedef void (*eth_stats_get_t)(struct rte_eth_dev *dev,
typedef void (*eth_stats_reset_t)(struct rte_eth_dev *dev);
/**< @internal Reset global I/O statistics of an Ethernet device to 0. */

typedef int (*eth_xstats_get_t)(struct rte_eth_dev *dev,
struct rte_eth_xstats *stats, unsigned n);
/**< @internal Get extended stats of an Ethernet device. */

typedef void (*eth_xstats_reset_t)(struct rte_eth_dev *dev);
/**< @internal Reset extended stats of an Ethernet device. */

typedef int (*eth_queue_stats_mapping_set_t)(struct rte_eth_dev *dev,
uint16_t queue_id,
uint8_t stat_idx,
Expand Down Expand Up @@ -1376,8 +1398,10 @@ struct eth_dev_ops {
eth_allmulticast_enable_t allmulticast_enable;/**< RX multicast ON. */
eth_allmulticast_disable_t allmulticast_disable;/**< RX multicast OF. */
eth_link_update_t link_update; /**< Get device link state. */
eth_stats_get_t stats_get; /**< Get device statistics. */
eth_stats_reset_t stats_reset; /**< Reset device statistics. */
eth_stats_get_t stats_get; /**< Get generic device statistics. */
eth_stats_reset_t stats_reset; /**< Reset generic device statistics. */
eth_xstats_get_t xstats_get; /**< Get extended device statistics. */
eth_xstats_reset_t xstats_reset; /**< Reset extended device statistics. */
eth_queue_stats_mapping_set_t queue_stats_mapping_set;
/**< Configure per queue stat counter mapping. */
eth_dev_infos_get_t dev_infos_get; /**< Get device info. */
Expand Down Expand Up @@ -2004,6 +2028,38 @@ extern void rte_eth_stats_get(uint8_t port_id, struct rte_eth_stats *stats);
*/
extern void rte_eth_stats_reset(uint8_t port_id);

/**
* Retrieve extended statistics of an Ethernet device.
*
* @param port_id
* The port identifier of the Ethernet device.
* @param xstats
* A pointer to a table of structure of type *rte_eth_xstats*
* to be filled with device statistics names and values.
* This parameter can be set to NULL if n is 0.
* @param n
* The size of the stats table, which should be large enough to store
* all the statistics of the device.
* @return
* - positive value lower or equal to n: success. The return value
* is the number of entries filled in the stats table.
* - positive value higher than n: error, the given statistics table
* is too small. The return value corresponds to the size that should
* be given to succeed. The entries in the table are not valid and
* shall not be used by the caller.
* - negative value on error (invalid port id)
*/
extern int rte_eth_xstats_get(uint8_t port_id,
struct rte_eth_xstats *xstats, unsigned n);

/**
* Reset extended statistics of an Ethernet device.
*
* @param port_id
* The port identifier of the Ethernet device.
*/
extern void rte_eth_xstats_reset(uint8_t port_id);

/**
* Set a mapping for the specified transmit queue to the specified per-queue
* statistics counter.
Expand Down

0 comments on commit ce757f5

Please sign in to comment.