get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/113984/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 113984,
    "url": "http://patchwork.dpdk.org/api/patches/113984/?format=api",
    "web_url": "http://patchwork.dpdk.org/project/dpdk/patch/eab9994ef9e9531e6ed03773a1ecd2654a196a3d.1657890738.git.anatoly.burakov@intel.com/",
    "project": {
        "id": 1,
        "url": "http://patchwork.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<eab9994ef9e9531e6ed03773a1ecd2654a196a3d.1657890738.git.anatoly.burakov@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/eab9994ef9e9531e6ed03773a1ecd2654a196a3d.1657890738.git.anatoly.burakov@intel.com",
    "date": "2022-07-15T13:12:53",
    "name": "[20.11,v1,1/2] eal: add lcore busyness telemetry",
    "commit_ref": null,
    "pull_url": null,
    "state": "not-applicable",
    "archived": true,
    "hash": "370c9dfb5499578ca5555e2ee7b28adc3b8ca735",
    "submitter": {
        "id": 4,
        "url": "http://patchwork.dpdk.org/api/people/4/?format=api",
        "name": "Burakov, Anatoly",
        "email": "anatoly.burakov@intel.com"
    },
    "delegate": {
        "id": 1,
        "url": "http://patchwork.dpdk.org/api/users/1/?format=api",
        "username": "tmonjalo",
        "first_name": "Thomas",
        "last_name": "Monjalon",
        "email": "thomas@monjalon.net"
    },
    "mbox": "http://patchwork.dpdk.org/project/dpdk/patch/eab9994ef9e9531e6ed03773a1ecd2654a196a3d.1657890738.git.anatoly.burakov@intel.com/mbox/",
    "series": [
        {
            "id": 24003,
            "url": "http://patchwork.dpdk.org/api/series/24003/?format=api",
            "web_url": "http://patchwork.dpdk.org/project/dpdk/list/?series=24003",
            "date": "2022-07-15T13:12:53",
            "name": "[20.11,v1,1/2] eal: add lcore busyness telemetry",
            "version": 1,
            "mbox": "http://patchwork.dpdk.org/series/24003/mbox/"
        }
    ],
    "comments": "http://patchwork.dpdk.org/api/patches/113984/comments/",
    "check": "warning",
    "checks": "http://patchwork.dpdk.org/api/patches/113984/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@inbox.dpdk.org",
        "Delivered-To": "patchwork@inbox.dpdk.org",
        "Received": [
            "from mails.dpdk.org (mails.dpdk.org [217.70.189.124])\n\tby inbox.dpdk.org (Postfix) with ESMTP id 4AF12A0032;\n\tFri, 15 Jul 2022 15:13:20 +0200 (CEST)",
            "from [217.70.189.124] (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id 2ED1D41156;\n\tFri, 15 Jul 2022 15:13:20 +0200 (CEST)",
            "from mga06.intel.com (mga06b.intel.com [134.134.136.31])\n by mails.dpdk.org (Postfix) with ESMTP id B68F840696\n for <dev@dpdk.org>; Fri, 15 Jul 2022 15:13:17 +0200 (CEST)",
            "from fmsmga003.fm.intel.com ([10.253.24.29])\n by orsmga104.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384;\n 15 Jul 2022 06:13:00 -0700",
            "from silpixa00401191.ir.intel.com ([10.55.128.75])\n by FMSMGA003.fm.intel.com with ESMTP; 15 Jul 2022 06:12:55 -0700"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple;\n d=intel.com; i=@intel.com; q=dns/txt; s=Intel;\n t=1657890797; x=1689426797;\n h=from:to:cc:subject:date:message-id:mime-version:\n content-transfer-encoding;\n bh=dw7sTu2ZkVn8B04SmlghFK8L/JsaJwLdpyrcROpFfR4=;\n b=Fv4PZz2gur6ePn6fXgH4tbagphGfMTRWTclFmcKQP4ch47dcTGIWK0te\n zYsxwi5kuW4mqlJnczgdS6pAH1kPtns2X8eaE0ugyR4GNj+33lXrfXtTX\n av6djWCx8rwzU/o94TBpadE5sJDRwDawxDvqyzDKoDv9ulysriyIsMz6d\n ELLlwAodf5sVwkdV1mI6eXd7i7cYCfTq7QxssOJ7ToklprlNBEdaHnrmG\n hfx+70duy4HEKd2cMzrTUdr0RMwzolW3r7tqstT0y9b2chyP/PWpZcqJO\n Fo82UoRse5t8i1M+7WIC/mkrIt311RADCY5l4xWrg20v8lg/h2DN8xOrL g==;",
        "X-IronPort-AV": [
            "E=McAfee;i=\"6400,9594,10408\"; a=\"347467263\"",
            "E=Sophos;i=\"5.92,274,1650956400\"; d=\"scan'208\";a=\"347467263\"",
            "E=Sophos;i=\"5.92,274,1650956400\"; d=\"scan'208\";a=\"685956355\""
        ],
        "X-ExtLoop1": "1",
        "From": "Anatoly Burakov <anatoly.burakov@intel.com>",
        "To": "dev@dpdk.org, Bruce Richardson <bruce.richardson@intel.com>,\n Nicolas Chautru <nicolas.chautru@intel.com>,\n Fiona Trahe <fiona.trahe@intel.com>,\n Ashish Gupta <ashish.gupta@marvell.com>,\n Declan Doherty <declan.doherty@intel.com>,\n David Hunt <david.hunt@intel.com>, Ray Kinsella <mdr@ashroe.eu>,\n Neil Horman <nhorman@tuxdriver.com>, Thomas Monjalon <thomas@monjalon.net>,\n Ferruh Yigit <ferruh.yigit@intel.com>,\n Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>,\n Jerin Jacob <jerinj@marvell.com>, Nipun Gupta <nipun.gupta@nxp.com>,\n Hemant Agrawal <hemant.agrawal@nxp.com>, Ori Kam <orika@nvidia.com>,\n Honnappa Nagarahalli <honnappa.nagarahalli@arm.com>,\n Konstantin Ananyev <konstantin.ananyev@intel.com>",
        "Cc": "Kevin Laatz <kevin.laatz@intel.com>,\n\tConor Walsh <conor.walsh@intel.com>",
        "Subject": "[20.11 PATCH v1 1/2] eal: add lcore busyness telemetry",
        "Date": "Fri, 15 Jul 2022 13:12:53 +0000",
        "Message-Id": "\n <eab9994ef9e9531e6ed03773a1ecd2654a196a3d.1657890738.git.anatoly.burakov@intel.com>",
        "X-Mailer": "git-send-email 2.25.1",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.29",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n <mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n <mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org"
    },
    "content": "Currently, there is no way to measure lcore busyness in a passive way,\nwithout any modifications to the application. This patch adds a new EAL\nAPI that will be able to passively track core busyness.\n\nThe busyness is calculated by relying on the fact that most DPDK API's\nwill poll for packets. Empty polls can be counted as \"idle\", while\nnon-empty polls can be counted as busy. To measure lcore busyness, we\nsimply call the telemetry timestamping function with the number of polls\na particular code section has processed, and count the number of cycles\nwe've spent processing empty bursts. The more empty bursts we encounter,\nthe less cycles we spend in \"busy\" state, and the less core busyness\nwill be reported.\n\nIn order for all of the above to work without modifications to the\napplication, the library code needs to be instrumented with calls to\nthe lcore telemetry busyness timestamping function. The following parts\nof DPDK are instrumented with lcore telemetry calls:\n\n- All major driver API's:\n  - ethdev\n  - cryptodev\n  - compressdev\n  - regexdev\n  - bbdev\n  - rawdev\n  - eventdev\n- Some additional libraries:\n  - ring\n  - distributor\n\nTo avoid performance impact from having lcore telemetry support, a\nglobal variable is exported by EAL, and a call to timestamping function\nis wrapped into a macro, so that whenever telemetry is disabled, it only\ntakes one additional branch and no function calls are performed. It is\nalso possible to disable it at compile time by commenting out\nRTE_LCORE_BUSYNESS from build config.\n\nThis patch also adds a telemetry endpoint to report lcore busyness, as\nwell as telemetry endpoints to enable/disable lcore telemetry.\n\nSigned-off-by: Kevin Laatz <kevin.laatz@intel.com>\nSigned-off-by: Conor Walsh <conor.walsh@intel.com>\nSigned-off-by: David Hunt <david.hunt@intel.com>\nSigned-off-by: Anatoly Burakov <anatoly.burakov@intel.com>\n---\n config/rte_config.h                           |   2 +\n lib/librte_bbdev/rte_bbdev.h                  |  16 +-\n lib/librte_compressdev/rte_compressdev.c      |   2 +\n lib/librte_cryptodev/rte_cryptodev.h          |   2 +\n lib/librte_distributor/rte_distributor.c      |  17 +-\n .../rte_distributor_single.c                  |  10 +-\n .../common/eal_common_lcore_telemetry.c       | 274 ++++++++++++++++++\n lib/librte_eal/common/meson.build             |   2 +\n lib/librte_eal/include/rte_lcore.h            |  80 +++++\n lib/librte_eal/meson.build                    |   3 +\n lib/librte_eal/version.map                    |   7 +\n lib/librte_ethdev/rte_ethdev.h                |   2 +\n lib/librte_eventdev/rte_eventdev.h            |  20 +-\n lib/librte_rawdev/rte_rawdev.c                |   5 +-\n lib/librte_regexdev/rte_regexdev.h            |   5 +-\n lib/librte_ring/rte_ring_elem.h               |   2 +\n 16 files changed, 429 insertions(+), 20 deletions(-)\n create mode 100644 lib/librte_eal/common/eal_common_lcore_telemetry.c",
    "diff": "diff --git a/config/rte_config.h b/config/rte_config.h\nindex a0b5160ff2..3531f4ef7b 100644\n--- a/config/rte_config.h\n+++ b/config/rte_config.h\n@@ -40,6 +40,8 @@\n #define RTE_LOG_DP_LEVEL RTE_LOG_INFO\n #define RTE_BACKTRACE 1\n #define RTE_MAX_VFIO_CONTAINERS 64\n+#define RTE_LCORE_BUSYNESS 1\n+#define RTE_LCORE_BUSYNESS_PERIOD 4000000ULL\n \n /* bsd module defines */\n #define RTE_CONTIGMEM_MAX_NUM_BUFS 64\ndiff --git a/lib/librte_bbdev/rte_bbdev.h b/lib/librte_bbdev/rte_bbdev.h\nindex 7017124414..78501ce8ce 100644\n--- a/lib/librte_bbdev/rte_bbdev.h\n+++ b/lib/librte_bbdev/rte_bbdev.h\n@@ -623,7 +623,9 @@ rte_bbdev_dequeue_enc_ops(uint16_t dev_id, uint16_t queue_id,\n {\n \tstruct rte_bbdev *dev = &rte_bbdev_devices[dev_id];\n \tstruct rte_bbdev_queue_data *q_data = &dev->data->queues[queue_id];\n-\treturn dev->dequeue_enc_ops(q_data, ops, num_ops);\n+\tconst uint16_t nb_ops = dev->dequeue_enc_ops(q_data, ops, num_ops);\n+\tRTE_LCORE_TELEMETRY_TIMESTAMP(nb_ops);\n+\treturn nb_ops;\n }\n \n /**\n@@ -656,7 +658,9 @@ rte_bbdev_dequeue_dec_ops(uint16_t dev_id, uint16_t queue_id,\n {\n \tstruct rte_bbdev *dev = &rte_bbdev_devices[dev_id];\n \tstruct rte_bbdev_queue_data *q_data = &dev->data->queues[queue_id];\n-\treturn dev->dequeue_dec_ops(q_data, ops, num_ops);\n+\tconst uint16_t nb_ops = dev->dequeue_dec_ops(q_data, ops, num_ops);\n+\tRTE_LCORE_TELEMETRY_TIMESTAMP(nb_ops);\n+\treturn nb_ops;\n }\n \n \n@@ -688,7 +692,9 @@ rte_bbdev_dequeue_ldpc_enc_ops(uint16_t dev_id, uint16_t queue_id,\n {\n \tstruct rte_bbdev *dev = &rte_bbdev_devices[dev_id];\n \tstruct rte_bbdev_queue_data *q_data = &dev->data->queues[queue_id];\n-\treturn dev->dequeue_ldpc_enc_ops(q_data, ops, num_ops);\n+\tconst uint16_t nb_ops = dev->dequeue_ldpc_enc_ops(q_data, ops, num_ops);\n+\tRTE_LCORE_TELEMETRY_TIMESTAMP(nb_ops);\n+\treturn nb_ops;\n }\n \n /**\n@@ -719,7 +725,9 @@ rte_bbdev_dequeue_ldpc_dec_ops(uint16_t dev_id, uint16_t queue_id,\n {\n \tstruct rte_bbdev *dev = &rte_bbdev_devices[dev_id];\n \tstruct rte_bbdev_queue_data *q_data = &dev->data->queues[queue_id];\n-\treturn dev->dequeue_ldpc_dec_ops(q_data, ops, num_ops);\n+\tconst uint16_t nb_ops = dev->dequeue_ldpc_dec_ops(q_data, ops, num_ops);\n+\tRTE_LCORE_TELEMETRY_TIMESTAMP(nb_ops);\n+\treturn nb_ops;\n }\n \n /** Definitions of device event types */\ndiff --git a/lib/librte_compressdev/rte_compressdev.c b/lib/librte_compressdev/rte_compressdev.c\nindex 49a342f400..dfc0f0804d 100644\n--- a/lib/librte_compressdev/rte_compressdev.c\n+++ b/lib/librte_compressdev/rte_compressdev.c\n@@ -582,6 +582,8 @@ rte_compressdev_dequeue_burst(uint8_t dev_id, uint16_t qp_id,\n \tnb_ops = (*dev->dequeue_burst)\n \t\t\t(dev->data->queue_pairs[qp_id], ops, nb_ops);\n \n+\tRTE_LCORE_TELEMETRY_TIMESTAMP(nb_ops);\n+\n \treturn nb_ops;\n }\n \ndiff --git a/lib/librte_cryptodev/rte_cryptodev.h b/lib/librte_cryptodev/rte_cryptodev.h\nindex 0935fd5875..7b89fd9ad7 100644\n--- a/lib/librte_cryptodev/rte_cryptodev.h\n+++ b/lib/librte_cryptodev/rte_cryptodev.h\n@@ -949,6 +949,8 @@ rte_cryptodev_dequeue_burst(uint8_t dev_id, uint16_t qp_id,\n \t\t\t(dev->data->queue_pairs[qp_id], ops, nb_ops);\n \n \trte_cryptodev_trace_dequeue_burst(dev_id, qp_id, (void **)ops, nb_ops);\n+\n+\tRTE_LCORE_TELEMETRY_TIMESTAMP(nb_ops);\n \treturn nb_ops;\n }\n \ndiff --git a/lib/librte_distributor/rte_distributor.c b/lib/librte_distributor/rte_distributor.c\nindex 07e385a259..45b3a61898 100644\n--- a/lib/librte_distributor/rte_distributor.c\n+++ b/lib/librte_distributor/rte_distributor.c\n@@ -58,6 +58,9 @@ rte_distributor_request_pkt(struct rte_distributor *d,\n \n \t\twhile (rte_rdtsc() < t)\n \t\t\trte_pause();\n+\n+\t\t/* this was an empty poll */\n+\t\tRTE_LCORE_TELEMETRY_TIMESTAMP(0);\n \t}\n \n \t/*\n@@ -136,24 +139,28 @@ rte_distributor_get_pkt(struct rte_distributor *d,\n \n \tif (unlikely(d->alg_type == RTE_DIST_ALG_SINGLE)) {\n \t\tif (return_count <= 1) {\n+\t\t\tuint16_t cnt;\n \t\t\tpkts[0] = rte_distributor_get_pkt_single(d->d_single,\n-\t\t\t\tworker_id, return_count ? oldpkt[0] : NULL);\n-\t\t\treturn (pkts[0]) ? 1 : 0;\n+\t\t\t\t\t\t\t\t worker_id, return_count ? oldpkt[0] : NULL);\n+\t\t\tcnt = (pkts[0] != NULL) ? 1 : 0;\n+\t\t\tRTE_LCORE_TELEMETRY_TIMESTAMP(cnt);\n+\t\t\treturn cnt;\n \t\t} else\n \t\t\treturn -EINVAL;\n \t}\n \n \trte_distributor_request_pkt(d, worker_id, oldpkt, return_count);\n \n-\tcount = rte_distributor_poll_pkt(d, worker_id, pkts);\n-\twhile (count == -1) {\n+\twhile ((count = rte_distributor_poll_pkt(d, worker_id, pkts)) == -1) {\n \t\tuint64_t t = rte_rdtsc() + 100;\n \n \t\twhile (rte_rdtsc() < t)\n \t\t\trte_pause();\n \n-\t\tcount = rte_distributor_poll_pkt(d, worker_id, pkts);\n+\t\t/* this was an empty poll */\n+\t\tRTE_LCORE_TELEMETRY_TIMESTAMP(0);\n \t}\n+\tRTE_LCORE_TELEMETRY_TIMESTAMP(count);\n \treturn count;\n }\n \ndiff --git a/lib/librte_distributor/rte_distributor_single.c b/lib/librte_distributor/rte_distributor_single.c\nindex f4725b1d0b..80460ab5d3 100644\n--- a/lib/librte_distributor/rte_distributor_single.c\n+++ b/lib/librte_distributor/rte_distributor_single.c\n@@ -34,8 +34,11 @@ rte_distributor_request_pkt_single(struct rte_distributor_single *d,\n \tint64_t req = (((int64_t)(uintptr_t)oldpkt) << RTE_DISTRIB_FLAG_BITS)\n \t\t\t| RTE_DISTRIB_GET_BUF;\n \twhile (unlikely(__atomic_load_n(&buf->bufptr64, __ATOMIC_RELAXED)\n-\t\t\t& RTE_DISTRIB_FLAGS_MASK))\n+\t\t\t& RTE_DISTRIB_FLAGS_MASK)) {\n \t\trte_pause();\n+\t\t/* this was an empty poll */\n+\t\tRTE_LCORE_TELEMETRY_TIMESTAMP(0);\n+\t}\n \n \t/* Sync with distributor on GET_BUF flag. */\n \t__atomic_store_n(&(buf->bufptr64), req, __ATOMIC_RELEASE);\n@@ -62,8 +65,11 @@ rte_distributor_get_pkt_single(struct rte_distributor_single *d,\n {\n \tstruct rte_mbuf *ret;\n \trte_distributor_request_pkt_single(d, worker_id, oldpkt);\n-\twhile ((ret = rte_distributor_poll_pkt_single(d, worker_id)) == NULL)\n+\twhile ((ret = rte_distributor_poll_pkt_single(d, worker_id)) == NULL) {\n \t\trte_pause();\n+\t\t/* this was an empty poll */\n+\t\tRTE_LCORE_TELEMETRY_TIMESTAMP(0);\n+\t}\n \treturn ret;\n }\n \ndiff --git a/lib/librte_eal/common/eal_common_lcore_telemetry.c b/lib/librte_eal/common/eal_common_lcore_telemetry.c\nnew file mode 100644\nindex 0000000000..5e4ea15ff5\n--- /dev/null\n+++ b/lib/librte_eal/common/eal_common_lcore_telemetry.c\n@@ -0,0 +1,274 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2010-2014 Intel Corporation\n+ */\n+\n+#include <unistd.h>\n+#include <limits.h>\n+#include <string.h>\n+\n+#include <rte_common.h>\n+#include <rte_cycles.h>\n+#include <rte_errno.h>\n+#include <rte_lcore.h>\n+\n+#ifdef RTE_LCORE_BUSYNESS\n+#include <rte_telemetry.h>\n+#endif\n+\n+int __rte_lcore_telemetry_enabled;\n+\n+#ifdef RTE_LCORE_BUSYNESS\n+\n+struct lcore_telemetry {\n+\tint busyness;\n+\t/**< Calculated busyness (gets set/returned by the API) */\n+\tint raw_busyness;\n+\t/**< Calculated busyness times 100. */\n+\tuint64_t interval_ts;\n+\t/**< when previous telemetry interval started */\n+\tuint64_t empty_cycles;\n+\t/**< empty cycle count since last interval */\n+\tuint64_t last_poll_ts;\n+\t/**< last poll timestamp */\n+\tbool last_empty;\n+\t/**< if last poll was empty */\n+\tunsigned int contig_poll_cnt;\n+\t/**< contiguous (always empty/non empty) poll counter */\n+} __rte_cache_aligned;\n+static struct lcore_telemetry telemetry_data[RTE_MAX_LCORE];\n+\n+#define LCORE_BUSYNESS_MAX 100\n+#define LCORE_BUSYNESS_NOT_SET -1\n+#define LCORE_BUSYNESS_MIN 0\n+\n+static void lcore_config_init(void)\n+{\n+\tint lcore_id;\n+\tRTE_LCORE_FOREACH(lcore_id) {\n+\t\tstruct lcore_telemetry *td = &telemetry_data[lcore_id];\n+\n+\t\ttd->interval_ts = 0;\n+\t\ttd->last_poll_ts = 0;\n+\t\ttd->empty_cycles = 0;\n+\t\ttd->last_empty = true;\n+\t\ttd->contig_poll_cnt = 0;\n+\t\ttd->busyness = LCORE_BUSYNESS_NOT_SET;\n+\t\ttd->raw_busyness = 0;\n+\t}\n+}\n+\n+int rte_lcore_busyness(unsigned int lcore_id)\n+{\n+\tconst uint64_t active_thresh = RTE_LCORE_BUSYNESS_PERIOD * 1000;\n+\tstruct lcore_telemetry *tdata;\n+\n+\tif (lcore_id >= RTE_MAX_LCORE)\n+\t\treturn -EINVAL;\n+\ttdata = &telemetry_data[lcore_id];\n+\n+\t/* if the lcore is not active */\n+\tif (tdata->interval_ts == 0)\n+\t\treturn LCORE_BUSYNESS_NOT_SET;\n+\t/* if the core hasn't been active in a while */\n+\telse if ((rte_rdtsc() - tdata->interval_ts) > active_thresh)\n+\t\treturn LCORE_BUSYNESS_NOT_SET;\n+\n+\t/* this core is active, report its busyness */\n+\treturn telemetry_data[lcore_id].busyness;\n+}\n+\n+int rte_lcore_busyness_enabled(void)\n+{\n+\treturn __rte_lcore_telemetry_enabled;\n+}\n+\n+void rte_lcore_busyness_enabled_set(int enable)\n+{\n+\t__rte_lcore_telemetry_enabled = !!enable;\n+\n+\tif (!enable)\n+\t\tlcore_config_init();\n+}\n+\n+static inline int calc_raw_busyness(const struct lcore_telemetry *tdata,\n+\t\t\t\t    const uint64_t empty, const uint64_t total)\n+{\n+\t/*\n+\t * we don't want to use floating point math here, but we want for our\n+\t * busyness to react smoothly to sudden changes, while still keeping the\n+\t * accuracy and making sure that over time the average follows busyness\n+\t * as measured just-in-time. therefore, we will calculate the average\n+\t * busyness using integer math, but shift the decimal point two places\n+\t * to the right, so that 100.0 becomes 10000. this allows us to report\n+\t * integer values (0..100) while still allowing ourselves to follow the\n+\t * just-in-time measurements when we calculate our averages.\n+\t */\n+\tconst int max_raw_idle = LCORE_BUSYNESS_MAX * 100;\n+\n+\t/*\n+\t * at upper end of the busyness scale, going up from 90->100 will take\n+\t * longer than going from 10->20 because of the averaging. to address\n+\t * this, we invert the scale when doing calculations: that is, we\n+\t * effectively calculate average *idle* cycle percentage, not average\n+\t * *busy* cycle percentage. this means that the scale is naturally\n+\t * biased towards fast scaling up, and slow scaling down.\n+\t */\n+\tconst int prev_raw_idle = max_raw_idle - tdata->raw_busyness;\n+\n+\t/* calculate rate of idle cycles, times 100 */\n+\tconst int cur_raw_idle = (int)((empty * max_raw_idle) / total);\n+\n+\t/* smoothen the idleness */\n+\tconst int smoothened_idle = (cur_raw_idle + prev_raw_idle * 4) / 5;\n+\n+\t/* convert idleness back to busyness */\n+\treturn max_raw_idle - smoothened_idle;\n+}\n+\n+void __rte_lcore_telemetry_timestamp(uint16_t nb_rx)\n+{\n+\tconst unsigned int lcore_id = rte_lcore_id();\n+\tuint64_t interval_ts, empty_cycles, cur_tsc, last_poll_ts;\n+\tstruct lcore_telemetry *tdata = &telemetry_data[lcore_id];\n+\tconst bool empty = nb_rx == 0;\n+\tuint64_t diff_int, diff_last;\n+\tbool last_empty;\n+\n+\tlast_empty = tdata->last_empty;\n+\n+\t/* optimization: don't do anything if status hasn't changed */\n+\tif (last_empty == empty && tdata->contig_poll_cnt++ < 32)\n+\t\treturn;\n+\t/* status changed or we're waiting for too long, reset counter */\n+\ttdata->contig_poll_cnt = 0;\n+\n+\tcur_tsc = rte_rdtsc();\n+\n+\tinterval_ts = tdata->interval_ts;\n+\tempty_cycles = tdata->empty_cycles;\n+\tlast_poll_ts = tdata->last_poll_ts;\n+\n+\tdiff_int = cur_tsc - interval_ts;\n+\tdiff_last = cur_tsc - last_poll_ts;\n+\n+\t/* is this the first time we're here? */\n+\tif (interval_ts == 0) {\n+\t\ttdata->busyness = LCORE_BUSYNESS_MIN;\n+\t\ttdata->raw_busyness = 0;\n+\t\ttdata->interval_ts = cur_tsc;\n+\t\ttdata->empty_cycles = 0;\n+\t\ttdata->contig_poll_cnt = 0;\n+\t\tgoto end;\n+\t}\n+\n+\t/* update the empty counter if we got an empty poll earlier */\n+\tif (last_empty)\n+\t\tempty_cycles += diff_last;\n+\n+\t/* have we passed the interval? */\n+\tif (diff_int > RTE_LCORE_BUSYNESS_PERIOD) {\n+\t\tint raw_busyness;\n+\n+\t\t/* get updated busyness value */\n+\t\traw_busyness = calc_raw_busyness(tdata, empty_cycles, diff_int);\n+\n+\t\t/* set a new interval, reset empty counter */\n+\t\ttdata->interval_ts = cur_tsc;\n+\t\ttdata->empty_cycles = 0;\n+\t\ttdata->raw_busyness = raw_busyness;\n+\t\t/* bring busyness back to 0..100 range, biased to round up */\n+\t\ttdata->busyness = (raw_busyness + 50) / 100;\n+\t} else\n+\t\t/* we may have updated empty counter */\n+\t\ttdata->empty_cycles = empty_cycles;\n+\n+end:\n+\t/* update status for next poll */\n+\ttdata->last_poll_ts = cur_tsc;\n+\ttdata->last_empty = empty;\n+}\n+\n+static int\n+lcore_busyness_enable(const char *cmd __rte_unused,\n+\t\t      const char *params __rte_unused,\n+\t\t      struct rte_tel_data *d)\n+{\n+\trte_lcore_busyness_enabled_set(1);\n+\n+\trte_tel_data_start_dict(d);\n+\n+\trte_tel_data_add_dict_int(d, \"busyness_enabled\", 1);\n+\n+\treturn 0;\n+}\n+\n+static int\n+lcore_busyness_disable(const char *cmd __rte_unused,\n+\t\t       const char *params __rte_unused,\n+\t\t       struct rte_tel_data *d)\n+{\n+\trte_lcore_busyness_enabled_set(0);\n+\n+\trte_tel_data_start_dict(d);\n+\n+\trte_tel_data_add_dict_int(d, \"busyness_enabled\", 0);\n+\n+\treturn 0;\n+}\n+\n+static int\n+lcore_handle_busyness(const char *cmd __rte_unused,\n+\t\t      const char *params __rte_unused, struct rte_tel_data *d)\n+{\n+\tchar corenum[64];\n+\tint i;\n+\n+\trte_tel_data_start_dict(d);\n+\n+\tRTE_LCORE_FOREACH(i) {\n+\t\tif (!rte_lcore_is_enabled(i))\n+\t\t\tcontinue;\n+\t\tsnprintf(corenum, sizeof(corenum), \"%d\", i);\n+\t\trte_tel_data_add_dict_int(d, corenum, rte_lcore_busyness(i));\n+\t}\n+\n+\treturn 0;\n+}\n+\n+RTE_INIT(lcore_init_telemetry)\n+{\n+\t__rte_lcore_telemetry_enabled = true;\n+\n+\tlcore_config_init();\n+\n+\trte_telemetry_register_cmd(\"/eal/lcore/busyness\", lcore_handle_busyness,\n+\t\t\t\t   \"return percentage busyness of cores\");\n+\n+\trte_telemetry_register_cmd(\"/eal/lcore/busyness_enable\", lcore_busyness_enable,\n+\t\t\t\t   \"enable lcore busyness measurement\");\n+\n+\trte_telemetry_register_cmd(\"/eal/lcore/busyness_disable\", lcore_busyness_disable,\n+\t\t\t\t   \"disable lcore busyness measurement\");\n+}\n+\n+#else\n+\n+int rte_lcore_busyness(unsigned int lcore_id __rte_unused)\n+{\n+\treturn -ENOTSUP;\n+}\n+\n+int rte_lcore_busyness_enabled(void)\n+{\n+\treturn -ENOTSUP;\n+}\n+\n+void rte_lcore_busyness_enabled_set(int enable __rte_unused)\n+{\n+}\n+\n+void __rte_lcore_telemetry_timestamp(uint16_t nb_rx __rte_unused)\n+{\n+}\n+\n+#endif\ndiff --git a/lib/librte_eal/common/meson.build b/lib/librte_eal/common/meson.build\nindex 39abf7a0a4..8a9668a137 100644\n--- a/lib/librte_eal/common/meson.build\n+++ b/lib/librte_eal/common/meson.build\n@@ -18,6 +18,7 @@ if is_windows\n \t\t'eal_common_fbarray.c',\n \t\t'eal_common_hexdump.c',\n \t\t'eal_common_launch.c',\n+\t\t'eal_common_lcore_telemetry.c',\n \t\t'eal_common_lcore.c',\n \t\t'eal_common_log.c',\n \t\t'eal_common_mcfg.c',\n@@ -51,6 +52,7 @@ sources += files(\n \t'eal_common_hexdump.c',\n \t'eal_common_hypervisor.c',\n \t'eal_common_launch.c',\n+\t'eal_common_lcore_telemetry.c',\n \t'eal_common_lcore.c',\n \t'eal_common_log.c',\n \t'eal_common_mcfg.c',\ndiff --git a/lib/librte_eal/include/rte_lcore.h b/lib/librte_eal/include/rte_lcore.h\nindex 48b87e253a..c49669f271 100644\n--- a/lib/librte_eal/include/rte_lcore.h\n+++ b/lib/librte_eal/include/rte_lcore.h\n@@ -460,6 +460,86 @@ rte_ctrl_thread_create(pthread_t *thread, const char *name,\n \t\tconst pthread_attr_t *attr,\n \t\tvoid *(*start_routine)(void *), void *arg);\n \n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice.\n+ *\n+ * Read busyness value corresponding to an lcore.\n+ *\n+ * @param lcore_id\n+ *   Lcore to read busyness value for.\n+ * @return\n+ *   - value between 0 and 100 on success\n+ *   - -1 if lcore is not active\n+ *   - -EINVAL if lcore is invalid\n+ *   - -ENOMEM if not enough memory available\n+ *   - -ENOTSUP if not supported\n+ */\n+__rte_experimental\n+int\n+rte_lcore_busyness(unsigned int lcore_id);\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice.\n+ *\n+ * Check if lcore busyness telemetry is enabled.\n+ *\n+ * @return\n+ *   - 1 if lcore telemetry is enabled\n+ *   - 0 if lcore telemetry is disabled\n+ *   - -ENOTSUP if not lcore telemetry supported\n+ */\n+__rte_experimental\n+int\n+rte_lcore_busyness_enabled(void);\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice.\n+ *\n+ * Enable or disable busyness telemetry.\n+ *\n+ * @param enable\n+ *   1 to enable, 0 to disable\n+ */\n+__rte_experimental\n+void\n+rte_lcore_busyness_enabled_set(int enable);\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice.\n+ *\n+ * Lcore telemetry timestamping function.\n+ *\n+ * @param nb_rx\n+ *   Number of buffers processed by lcore.\n+ */\n+__rte_experimental\n+void\n+__rte_lcore_telemetry_timestamp(uint16_t nb_rx);\n+\n+/** @internal lcore telemetry enabled status */\n+extern int __rte_lcore_telemetry_enabled;\n+\n+/**\n+ * Call lcore telemetry timestamp function.\n+ *\n+ * @param nb_rx\n+ *   Number of buffers processed by lcore.\n+ */\n+#ifdef RTE_LCORE_BUSYNESS\n+#define RTE_LCORE_TELEMETRY_TIMESTAMP(nb_rx)                    \\\n+\tdo {                                                    \\\n+\t\tif (__rte_lcore_telemetry_enabled)              \\\n+\t\t\t__rte_lcore_telemetry_timestamp(nb_rx); \\\n+\t} while (0)\n+#else\n+#define RTE_LCORE_TELEMETRY_TIMESTAMP(nb_rx) \\\n+\twhile (0) {}\n+#endif\n+\n #ifdef __cplusplus\n }\n #endif\ndiff --git a/lib/librte_eal/meson.build b/lib/librte_eal/meson.build\nindex 7d6222e781..9198625c83 100644\n--- a/lib/librte_eal/meson.build\n+++ b/lib/librte_eal/meson.build\n@@ -18,6 +18,9 @@ subdir(arch_subdir)\n deps += ['kvargs']\n if not is_windows\n \tdeps += ['telemetry']\n+else\n+\t# core busyness telemetry depends on telemetry library\n+\tdpdk_conf.set('RTE_LCORE_BUSYNESS', 0)\n endif\n if dpdk_conf.has('RTE_USE_LIBBSD')\n \text_deps += libbsd\ndiff --git a/lib/librte_eal/version.map b/lib/librte_eal/version.map\nindex 354c068f31..3bf60dbafb 100644\n--- a/lib/librte_eal/version.map\n+++ b/lib/librte_eal/version.map\n@@ -403,6 +403,13 @@ EXPERIMENTAL {\n \trte_service_lcore_may_be_active;\n \trte_vect_get_max_simd_bitwidth;\n \trte_vect_set_max_simd_bitwidth;\n+\n+\t__rte_lcore_telemetry_timestamp;\n+\t__rte_lcore_telemetry_enabled;\n+\trte_lcore_busyness;\n+\trte_lcore_busyness_enabled;\n+\trte_lcore_busyness_enabled_set;\n+\n };\n \n INTERNAL {\ndiff --git a/lib/librte_ethdev/rte_ethdev.h b/lib/librte_ethdev/rte_ethdev.h\nindex f5f8919186..a81c3cd27b 100644\n--- a/lib/librte_ethdev/rte_ethdev.h\n+++ b/lib/librte_ethdev/rte_ethdev.h\n@@ -4871,6 +4871,8 @@ rte_eth_rx_burst(uint16_t port_id, uint16_t queue_id,\n #endif\n \n \trte_ethdev_trace_rx_burst(port_id, queue_id, (void **)rx_pkts, nb_rx);\n+\n+\tRTE_LCORE_TELEMETRY_TIMESTAMP(nb_rx);\n \treturn nb_rx;\n }\n \ndiff --git a/lib/librte_eventdev/rte_eventdev.h b/lib/librte_eventdev/rte_eventdev.h\nindex ce1fc2ce0f..820b3ba73d 100644\n--- a/lib/librte_eventdev/rte_eventdev.h\n+++ b/lib/librte_eventdev/rte_eventdev.h\n@@ -1663,13 +1663,19 @@ rte_event_dequeue_burst(uint8_t dev_id, uint8_t port_id, struct rte_event ev[],\n \t * Allow zero cost non burst mode routine invocation if application\n \t * requests nb_events as const one\n \t */\n-\tif (nb_events == 1)\n-\t\treturn (*dev->dequeue)(\n-\t\t\tdev->data->ports[port_id], ev, timeout_ticks);\n-\telse\n-\t\treturn (*dev->dequeue_burst)(\n-\t\t\tdev->data->ports[port_id], ev, nb_events,\n-\t\t\t\ttimeout_ticks);\n+\tif (nb_events == 1) {\n+\t\tconst uint16_t nb_evts =\n+\t\t\t\t(*dev->dequeue)(dev->data->ports[port_id],\n+\t\t\t\t\tev, timeout_ticks);\n+\t\tRTE_LCORE_TELEMETRY_TIMESTAMP(nb_evts);\n+\t\treturn nb_evts;\n+\t} else {\n+\t\tconst uint16_t nb_evts =\n+\t\t\t\t(*dev->dequeue_burst)(dev->data->ports[port_id],\n+\t\t\t\t\tev, nb_events, timeout_ticks);\n+\t\tRTE_LCORE_TELEMETRY_TIMESTAMP(nb_evts);\n+\t\treturn nb_evts;\n+\t}\n }\n \n /**\ndiff --git a/lib/librte_rawdev/rte_rawdev.c b/lib/librte_rawdev/rte_rawdev.c\nindex f29164dd15..c37712a3f0 100644\n--- a/lib/librte_rawdev/rte_rawdev.c\n+++ b/lib/librte_rawdev/rte_rawdev.c\n@@ -240,12 +240,15 @@ rte_rawdev_dequeue_buffers(uint16_t dev_id,\n \t\t\t   rte_rawdev_obj_t context)\n {\n \tstruct rte_rawdev *dev;\n+\tint nb_ops;\n \n \tRTE_RAWDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);\n \tdev = &rte_rawdevs[dev_id];\n \n \tRTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dequeue_bufs, -ENOTSUP);\n-\treturn (*dev->dev_ops->dequeue_bufs)(dev, buffers, count, context);\n+\tnb_ops = (*dev->dev_ops->dequeue_bufs)(dev, buffers, count, context);\n+\tRTE_LCORE_TELEMETRY_TIMESTAMP(nb_ops);\n+\treturn nb_ops;\n }\n \n int\ndiff --git a/lib/librte_regexdev/rte_regexdev.h b/lib/librte_regexdev/rte_regexdev.h\nindex 0001658925..b3ec648ca9 100644\n--- a/lib/librte_regexdev/rte_regexdev.h\n+++ b/lib/librte_regexdev/rte_regexdev.h\n@@ -1524,6 +1524,7 @@ rte_regexdev_dequeue_burst(uint8_t dev_id, uint16_t qp_id,\n \t\t\t   struct rte_regex_ops **ops, uint16_t nb_ops)\n {\n \tstruct rte_regexdev *dev = &rte_regex_devices[dev_id];\n+\tuint16_t deq_ops;\n #ifdef RTE_LIBRTE_REGEXDEV_DEBUG\n \tRTE_REGEXDEV_VALID_DEV_ID_OR_ERR_RET(dev_id, -EINVAL);\n \tRTE_FUNC_PTR_OR_ERR_RET(*dev->dequeue, -ENOTSUP);\n@@ -1532,7 +1533,9 @@ rte_regexdev_dequeue_burst(uint8_t dev_id, uint16_t qp_id,\n \t\treturn -EINVAL;\n \t}\n #endif\n-\treturn (*dev->dequeue)(dev, qp_id, ops, nb_ops);\n+\tdeq_ops = (*dev->dequeue)(dev, qp_id, ops, nb_ops);\n+\tRTE_LCORE_TELEMETRY_TIMESTAMP(deq_ops);\n+\treturn deq_ops;\n }\n \n #ifdef __cplusplus\ndiff --git a/lib/librte_ring/rte_ring_elem.h b/lib/librte_ring/rte_ring_elem.h\nindex 7034d29c07..341bdf8dec 100644\n--- a/lib/librte_ring/rte_ring_elem.h\n+++ b/lib/librte_ring/rte_ring_elem.h\n@@ -475,6 +475,8 @@ __rte_ring_do_dequeue_elem(struct rte_ring *r, void *obj_table,\n end:\n \tif (available != NULL)\n \t\t*available = entries - n;\n+\n+\tRTE_LCORE_TELEMETRY_TIMESTAMP(n);\n \treturn n;\n }\n \n",
    "prefixes": [
        "20.11",
        "v1",
        "1/2"
    ]
}