Show a patch.

GET /api/patches/85/
Content-Type: application/json
Vary: Accept

    "id": 85,
    "url": "",
    "web_url": "",
    "project": {
        "id": 1,
        "url": "",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "",
        "list_email": "",
        "web_url": "",
        "scm_url": "git://",
        "webscm_url": ""
    "msgid": "<>",
    "date": "2014-07-23T12:28:53",
    "name": "[dpdk-dev,1/2] ethdev: add a new rte_eth_xstats_get method to retrieve extended statistics",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": true,
    "hash": "dd49e794e730b2ca5aba3a6f785bb42242b828f8",
    "submitter": {
        "id": 8,
        "url": "",
        "name": "Olivier Matz",
        "email": ""
    "delegate": null,
    "mbox": "",
    "series": [],
    "comments": "",
    "check": "pending",
    "checks": "",
    "tags": {},
    "headers": {
        "X-List-Received-Date": "Wed, 23 Jul 2014 12:27:39 -0000",
        "List-Post": "<>",
        "X-Mailman-Version": "2.1.15",
        "List-Unsubscribe": "<>,\n\t<>",
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\; s=20130820;\n\th=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to\n\t:references;\n\tbh=79IrNNyjuq0/r28B6bjGdCnDAETKlHZT1RREyRL7sVY=;\n\tb=RvvsWQ+oG6gl3SuvyY+jn3dRvg7GiIqjJ3Gzq/v4liWbW/1bNfAW2hBb3z4JfHyvV9\n\tZOCLMS27guFIcrpexaYL4BH1hWln3TuqQP3T2soUnsGmtGMZ1vVaU7XIh3AAQhbIrSKn\n\t07Qextr5njckSznnW4WHmVLwG6v8Qeq3AgdWibWkTHf7W2H366lxsii+euSJuzegGzhG\n\tD28mOma8Sln0deaqmR5rb5SSmJOpUzQJCr1AuvZmY/0q+ve+ND3cLv0hBFQ1MRcfbgp/\n\tURqsARTljVQ+wpPcLnlCMRvbx2fnnwopNui5aargm1//HTE4XRlSkLb3GZpNREbXBMpI\n\tThKw==",
        "List-Archive": "<>",
        "X-Received": "by with SMTP id ay6mr1443385wjb.84.1406118541613; \n\tWed, 23 Jul 2014 05:29:01 -0700 (PDT)",
        "List-Subscribe": "<>,\n\t<>",
        "Precedence": "list",
        "List-Help": "<>",
        "From": "Olivier Matz <>",
        "Message-Id": "<>",
        "Date": "Wed, 23 Jul 2014 14:28:53 +0200",
        "To": "",
        "References": "<>",
        "In-Reply-To": "<>",
        "X-Mailer": "git-send-email 2.0.1",
        "List-Id": "patches and discussions about DPDK <>",
        "X-BeenThere": "",
        "Return-Path": "<>",
        "X-Gm-Message-State": "ALoCoQmKKMUOJmKEm+ZGc+v8IJMF49QJ+O13z40MFOvwBZ4n8Zl8KTLfKEj7RZ3f1GzT5PoKzdXm",
        "Received": [
            "from (\n\t[]) by (Postfix) with ESMTP id 2000C594D\n\tfor <>; Wed, 23 Jul 2014 14:27:39 +0200 (CEST)",
            "by with SMTP id w62so1128679wes.1\n\tfor <>; Wed, 23 Jul 2014 05:29:02 -0700 (PDT)",
            "from (\n\t[]) by with ESMTPSA id\n\tch5sm5882484wjb.18.2014. for <multiple recipients>\n\t(version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128);\n\tWed, 23 Jul 2014 05:29:01 -0700 (PDT)"
        "Subject": "[dpdk-dev] [PATCH 1/2] ethdev: add a new rte_eth_xstats_get method\n\tto retrieve extended statistics"
    "content": "This method can be implemented by a poll mode driver to provide\nnon-standard statistics (which are not part of the generic statistics\nstructure). Each statistic is returned in a generic form: \"name\" and\n\"value\" and can be used to dump PMD-specific statistics in the same way\nthan ethtool in linux kernel.\n\nIf the PMD does not provide the xstats_get and xstats_set functions, the\nethdev API will return the generic statistics in the xstats format\n(name, value).\n\nThis commit opens the door for a clean-up of the generic statistics\nstructure, only keeping statistics that are really common to all PMDs\nand moving specific ones into the xstats API.\n\nReviewed-by: David Marchand <>\nSigned-off-by: Olivier Matz <>\n---\n lib/librte_ether/rte_ethdev.c | 137 ++++++++++++++++++++++++++++++++++++++++++\n lib/librte_ether/rte_ethdev.h |  60 +++++++++++++++++-\n 2 files changed, 195 insertions(+), 2 deletions(-)",
    "diff": "diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c\nindex fd1010a..b71b679 100644\n--- a/lib/librte_ether/rte_ethdev.c\n+++ b/lib/librte_ether/rte_ethdev.c\n@@ -114,6 +114,48 @@ static uint8_t nb_ports = 0;\n /* spinlock for eth device callbacks */\n static rte_spinlock_t rte_eth_dev_cb_lock = RTE_SPINLOCK_INITIALIZER;\n \n+/* store statistics names and its offset in stats structure  */\n+struct rte_eth_xstats_name_off {\n+\tchar name[RTE_ETH_XSTATS_NAME_SIZE];\n+\tunsigned offset;\n+};\n+\n+static struct rte_eth_xstats_name_off rte_stats_strings[] = {\n+\t {\"rx_packets\", offsetof(struct rte_eth_stats, ipackets)},\n+\t {\"tx_packets\", offsetof(struct rte_eth_stats, opackets)},\n+\t {\"rx_bytes\", offsetof(struct rte_eth_stats, ibytes)},\n+\t {\"tx_bytes\", offsetof(struct rte_eth_stats, obytes)},\n+\t {\"tx_errors\", offsetof(struct rte_eth_stats, oerrors)},\n+\t {\"rx_missed_errors\", offsetof(struct rte_eth_stats, imissed)},\n+\t {\"rx_crc_errors\", offsetof(struct rte_eth_stats, ibadcrc)},\n+\t {\"rx_bad_length_errors\", offsetof(struct rte_eth_stats, ibadlen)},\n+\t {\"rx_errors\", offsetof(struct rte_eth_stats, ierrors)},\n+\t {\"alloc_rx_buff_failed\", offsetof(struct rte_eth_stats, rx_nombuf)},\n+\t {\"fdir_match\", offsetof(struct rte_eth_stats, fdirmatch)},\n+\t {\"fdir_miss\", offsetof(struct rte_eth_stats, fdirmiss)},\n+\t {\"tx_flow_control_xon\", offsetof(struct rte_eth_stats, tx_pause_xon)},\n+\t {\"rx_flow_control_xon\", offsetof(struct rte_eth_stats, rx_pause_xon)},\n+\t {\"tx_flow_control_xoff\", offsetof(struct rte_eth_stats, tx_pause_xoff)},\n+\t {\"rx_flow_control_xoff\", offsetof(struct rte_eth_stats, rx_pause_xoff)},\n+};\n+#define RTE_NB_STATS (sizeof(rte_stats_strings) / sizeof(rte_stats_strings[0]))\n+\n+static struct rte_eth_xstats_name_off rte_rxq_stats_strings[] = {\n+\t{\"rx_packets\", offsetof(struct rte_eth_stats, q_ipackets)},\n+\t{\"rx_bytes\", offsetof(struct rte_eth_stats, q_ibytes)},\n+};\n+#define RTE_NB_RXQ_STATS (sizeof(rte_rxq_stats_strings) /\t\\\n+\t\tsizeof(rte_rxq_stats_strings[0]))\n+\n+static struct rte_eth_xstats_name_off rte_txq_stats_strings[] = {\n+\t{\"tx_packets\", offsetof(struct rte_eth_stats, q_opackets)},\n+\t{\"tx_bytes\", offsetof(struct rte_eth_stats, q_obytes)},\n+\t{\"tx_errors\", offsetof(struct rte_eth_stats, q_errors)},\n+};\n+#define RTE_NB_TXQ_STATS (sizeof(rte_txq_stats_strings) /\t\\\n+\t\tsizeof(rte_txq_stats_strings[0]))\n+\n+\n /**\n  * The user application callback description.\n  *\n@@ -1201,6 +1243,101 @@ rte_eth_stats_reset(uint8_t port_id)\n \t(*dev->dev_ops->stats_reset)(dev);\n }\n \n+/* retrieve ethdev extended statistics */\n+int\n+rte_eth_xstats_get(uint8_t port_id, struct rte_eth_xstats *xstats,\n+\tunsigned n)\n+{\n+\tstruct rte_eth_stats eth_stats;\n+\tstruct rte_eth_dev *dev;\n+\tunsigned count, i, q;\n+\tuint64_t val;\n+\tchar *stats_ptr;\n+\n+\tif (port_id >= nb_ports) {\n+\t\tPMD_DEBUG_TRACE(\"Invalid port_id=%d\\n\", port_id);\n+\t\treturn -1;\n+\t}\n+\tdev = &rte_eth_devices[port_id];\n+\n+\t/* implemented by the driver */\n+\tif (dev->dev_ops->xstats_get != NULL)\n+\t\treturn (*dev->dev_ops->xstats_get)(dev, xstats, n);\n+\n+\t/* else, return generic statistics */\n+\tcount = RTE_NB_STATS;\n+\tcount += dev->data->nb_rx_queues * RTE_NB_RXQ_STATS;\n+\tcount += dev->data->nb_tx_queues * RTE_NB_TXQ_STATS;\n+\tif (n < count)\n+\t\treturn count;\n+\n+\t/* now fill the xstats structure */\n+\n+\tcount = 0;\n+\tmemset(&eth_stats, 0, sizeof(eth_stats));\n+\trte_eth_stats_get(port_id, &eth_stats);\n+\n+\t/* global stats */\n+\tfor (i = 0; i < RTE_NB_STATS; i++) {\n+\t\tstats_ptr = (char *)&eth_stats + rte_stats_strings[i].offset;\n+\t\tval = *(uint64_t *)stats_ptr;\n+\t\tsnprintf(xstats[count].name, sizeof(xstats[count].name),\n+\t\t\t\"%s\", rte_stats_strings[i].name);\n+\t\txstats[count++].value = val;\n+\t}\n+\n+\t/* per-rxq stats */\n+\tfor (q = 0; q < dev->data->nb_rx_queues; q++) {\n+\t\tfor (i = 0; i < RTE_NB_RXQ_STATS; i++) {\n+\t\t\tstats_ptr = (char *)&eth_stats;\n+\t\t\tstats_ptr += rte_rxq_stats_strings[i].offset;\n+\t\t\tstats_ptr += q * sizeof(uint64_t);\n+\t\t\tval = *(uint64_t *)stats_ptr;\n+\t\t\tsnprintf(xstats[count].name, sizeof(xstats[count].name),\n+\t\t\t\t\"rx_queue_%u_%s\", q,\n+\t\t\t\trte_rxq_stats_strings[i].name);\n+\t\t\txstats[count++].value = val;\n+\t\t}\n+\t}\n+\n+\t/* per-txq stats */\n+\tfor (q = 0; q < dev->data->nb_tx_queues; q++) {\n+\t\tfor (i = 0; i < RTE_NB_TXQ_STATS; i++) {\n+\t\t\tstats_ptr = (char *)&eth_stats;\n+\t\t\tstats_ptr += rte_txq_stats_strings[i].offset;\n+\t\t\tstats_ptr += q * sizeof(uint64_t);\n+\t\t\tval = *(uint64_t *)stats_ptr;\n+\t\t\tsnprintf(xstats[count].name, sizeof(xstats[count].name),\n+\t\t\t\t\"tx_queue_%u_%s\", q,\n+\t\t\t\trte_txq_stats_strings[i].name);\n+\t\t\txstats[count++].value = val;\n+\t\t}\n+\t}\n+\n+\treturn count;\n+}\n+\n+/* reset ethdev extended statistics */\n+void\n+rte_eth_xstats_reset(uint8_t port_id)\n+{\n+\tstruct rte_eth_dev *dev;\n+\n+\tif (port_id >= nb_ports) {\n+\t\tPMD_DEBUG_TRACE(\"Invalid port_id=%d\\n\", port_id);\n+\t\treturn;\n+\t}\n+\tdev = &rte_eth_devices[port_id];\n+\n+\t/* implemented by the driver */\n+\tif (dev->dev_ops->xstats_reset != NULL) {\n+\t\t(*dev->dev_ops->xstats_reset)(dev);\n+\t\treturn;\n+\t}\n+\n+\t/* fallback to default */\n+\trte_eth_stats_reset(port_id);\n+}\n \n static int\n set_queue_stats_mapping(uint8_t port_id, uint16_t queue_id, uint8_t stat_idx,\ndiff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h\nindex 50df654..4076c33 100644\n--- a/lib/librte_ether/rte_ethdev.h\n+++ b/lib/librte_ether/rte_ethdev.h\n@@ -908,6 +908,21 @@ struct rte_eth_dev_info {\n \tuint32_t tx_offload_capa; /**< Device TX offload capabilities. */\n };\n \n+/** Maximum name length for a extended statitics counter */\n+#define RTE_ETH_XSTATS_NAME_SIZE 64\n+\n+/**\n+ * An Ethernet device extended statistic structure\n+ *\n+ * This structure is used by ethdev->eth_xstats_get() to provide\n+ * statistics that are not provided in the generic rte_eth_stats\n+ * structure.\n+ */\n+struct rte_eth_xstats {\n+\tchar name[RTE_ETH_XSTATS_NAME_SIZE];\n+\tuint64_t value;\n+};\n+\n struct rte_eth_dev;\n \n struct rte_eth_dev_callback;\n@@ -1028,6 +1043,13 @@ typedef void (*eth_stats_get_t)(struct rte_eth_dev *dev,\n typedef void (*eth_stats_reset_t)(struct rte_eth_dev *dev);\n /**< @internal Reset global I/O statistics of an Ethernet device to 0. */\n \n+typedef int (*eth_xstats_get_t)(struct rte_eth_dev *dev,\n+\tstruct rte_eth_xstats *stats, unsigned n);\n+/**< @internal Get extended stats of an Ethernet device. */\n+\n+typedef void (*eth_xstats_reset_t)(struct rte_eth_dev *dev);\n+/**< @internal Reset extended stats of an Ethernet device. */\n+\n typedef int (*eth_queue_stats_mapping_set_t)(struct rte_eth_dev *dev,\n \t\t\t\t\t     uint16_t queue_id,\n \t\t\t\t\t     uint8_t stat_idx,\n@@ -1376,8 +1398,10 @@ struct eth_dev_ops {\n \teth_allmulticast_enable_t  allmulticast_enable;/**< RX multicast ON. */\n \teth_allmulticast_disable_t allmulticast_disable;/**< RX multicast OF. */\n \teth_link_update_t          link_update;   /**< Get device link state. */\n-\teth_stats_get_t            stats_get;     /**< Get device statistics. */\n-\teth_stats_reset_t          stats_reset;   /**< Reset device statistics. */\n+\teth_stats_get_t            stats_get;     /**< Get generic device statistics. */\n+\teth_stats_reset_t          stats_reset;   /**< Reset generic device statistics. */\n+\teth_xstats_get_t           xstats_get;    /**< Get extended device statistics. */\n+\teth_xstats_reset_t         xstats_reset;  /**< Reset extended device statistics. */\n \teth_queue_stats_mapping_set_t queue_stats_mapping_set;\n \t/**< Configure per queue stat counter mapping. */\n \teth_dev_infos_get_t        dev_infos_get; /**< Get device info. */\n@@ -2005,6 +2029,38 @@ extern void rte_eth_stats_get(uint8_t port_id, struct rte_eth_stats *stats);\n extern void rte_eth_stats_reset(uint8_t port_id);\n \n /**\n+ * Retrieve extended statistics of an Ethernet device.\n+ *\n+ * @param port_id\n+ *   The port identifier of the Ethernet device.\n+ * @param stats\n+ *   A pointer to a table of structure of type *rte_eth_xstats*\n+ *   to be filled with the values of device statistics names and value.\n+ *   This parameter can be set to NULL if n is 0.\n+ * @param n\n+ *   The size of the stats table, which should be large enough to store\n+ *   all the statistics of the device.\n+ * @return\n+ *   - positive value lower or equal to n: success. The return value\n+ *     is the number of entries filled in the stats table.\n+ *   - positive value higher than n: error, the given statistics table\n+ *     is too small. Thereturn value corresponds to the size that should\n+ *     be given to succeed. The entries in the table are not valid and\n+ *     shall not be used by the caller.\n+ *   - negative value on error (invalid port id)\n+ */\n+extern int rte_eth_xstats_get(uint8_t port_id,\n+\tstruct rte_eth_xstats *xstats, unsigned n);\n+\n+/**\n+ * Reset extended statistics of an Ethernet device.\n+ *\n+ * @param port_id\n+ *   The port identifier of the Ethernet device.\n+ */\n+extern void rte_eth_xstats_reset(uint8_t port_id);\n+\n+/**\n  *  Set a mapping for the specified transmit queue to the specified per-queue\n  *  statistics counter.\n  *\n",
    "prefixes": [