get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 40815,
    "url": "http://patchwork.dpdk.org/api/patches/40815/?format=api",
    "web_url": "http://patchwork.dpdk.org/project/dpdk/patch/1528451833-3617-1-git-send-email-liang.j.ma@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": "<1528451833-3617-1-git-send-email-liang.j.ma@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1528451833-3617-1-git-send-email-liang.j.ma@intel.com",
    "date": "2018-06-08T09:57:12",
    "name": "[dpdk-dev,v1,1/2] lib/librte_power: traffic pattern aware power control",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "2e0249d1d3c6966bbedb5011e025a3e4ad2ceed4",
    "submitter": {
        "id": 904,
        "url": "http://patchwork.dpdk.org/api/people/904/?format=api",
        "name": "Liang, Ma",
        "email": "liang.j.ma@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/1528451833-3617-1-git-send-email-liang.j.ma@intel.com/mbox/",
    "series": [
        {
            "id": 48,
            "url": "http://patchwork.dpdk.org/api/series/48/?format=api",
            "web_url": "http://patchwork.dpdk.org/project/dpdk/list/?series=48",
            "date": "2018-06-08T09:57:12",
            "name": "[dpdk-dev,v1,1/2] lib/librte_power: traffic pattern aware power control",
            "version": 1,
            "mbox": "http://patchwork.dpdk.org/series/48/mbox/"
        }
    ],
    "comments": "http://patchwork.dpdk.org/api/patches/40815/comments/",
    "check": "fail",
    "checks": "http://patchwork.dpdk.org/api/patches/40815/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@dpdk.org",
        "Delivered-To": "patchwork@dpdk.org",
        "Received": [
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id F38A05B40;\n\tFri,  8 Jun 2018 11:57:39 +0200 (CEST)",
            "from mga01.intel.com (mga01.intel.com [192.55.52.88])\n\tby dpdk.org (Postfix) with ESMTP id 34DC65B2C\n\tfor <dev@dpdk.org>; Fri,  8 Jun 2018 11:57:37 +0200 (CEST)",
            "from fmsmga007.fm.intel.com ([10.253.24.52])\n\tby fmsmga101.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384;\n\t08 Jun 2018 02:57:36 -0700",
            "from irvmail001.ir.intel.com ([163.33.26.43])\n\tby fmsmga007.fm.intel.com with ESMTP; 08 Jun 2018 02:57:34 -0700",
            "from sivswdev01.ir.intel.com (sivswdev01.ir.intel.com\n\t[10.237.217.45])\n\tby irvmail001.ir.intel.com (8.14.3/8.13.6/MailSET/Hub) with ESMTP id\n\tw589vY0J028837; Fri, 8 Jun 2018 10:57:34 +0100",
            "from sivswdev01.ir.intel.com (localhost [127.0.0.1])\n\tby sivswdev01.ir.intel.com with ESMTP id w589vYH7003774;\n\tFri, 8 Jun 2018 10:57:34 +0100",
            "(from lma25@localhost)\n\tby sivswdev01.ir.intel.com with LOCAL id w589vYpR003769;\n\tFri, 8 Jun 2018 10:57:34 +0100"
        ],
        "X-Amp-Result": "SKIPPED(no attachment in message)",
        "X-Amp-File-Uploaded": "False",
        "X-ExtLoop1": "1",
        "X-IronPort-AV": "E=Sophos;i=\"5.49,490,1520924400\"; d=\"scan'208\";a=\"45617098\"",
        "From": "Liang Ma <liang.j.ma@intel.com>",
        "To": "david.hunt@intel.com",
        "Cc": "dev@dpdk.org, radu.nicolau@intel.com, Liang Ma <liang.j.ma@intel.com>",
        "Date": "Fri,  8 Jun 2018 10:57:12 +0100",
        "Message-Id": "<1528451833-3617-1-git-send-email-liang.j.ma@intel.com>",
        "X-Mailer": "git-send-email 1.7.7.4",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain; charset=UTF-8",
        "Content-Transfer-Encoding": "8bit",
        "Subject": "[dpdk-dev] [PATCH v1 1/2] lib/librte_power: traffic pattern aware\n\tpower control",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://dpdk.org/ml/options/dev>,\n\t<mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://dpdk.org/ml/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<https://dpdk.org/ml/listinfo/dev>,\n\t<mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "1. Abstract\n\nFor packet processing workloads such as DPDK polling is continuous.\nThis means CPU cores always show 100% busy independent of how much work\nthose cores are doing. It is critical to accurately determine how busy\na core is hugely important for the following reasons:\n\n   * No indication of overload conditions\n\n   * User do not know how much real load is on a system meaning resulted in\n     wasted energy as no power management is utilized\n\nTried and failed schemes include calculating the cycles required from\nthe load on the core, in other words the business. For example,\nhow many cycles it costs to handle each packet and determining the frequency\ncost per core. Due to the varying nature of traffic, types of frames and cost\nin cycles to process, this mechanism becomes complex quickly where\na simple scheme is required to solve the problems.\n\n2. Proposed solution\n\nFor all polling mechanism, the proposed solution focus on how many times\nempty poll executed instead of calculating how many cycles it cost to handle\neach packet. The less empty poll number means current core is busy with\nprocessing workload, therefore,  the higher frequency is needed. The high\nempty poll number indicate current core has lots spare time, therefore,\nwe can lower the frequency.\n\n2.1 Power state definition:\n\n\tLOW:  the frequency is used for purge mode.\n\n\tMED:  the frequency is used to process modest traffic workload.\n\n\tHIGH: the frequency is used to process busy traffic workload.\n\n2.2 There are two phases to establish the power management system:\n\n\ta.Initialization/Training phase. There is no traffic pass-through,\n\t  the system will test average empty poll numbers  with LOW/MED/HIGH\n\t  power state. Those average empty poll numbers  will be the baseline\n\t  for the normal phase. The system will collect all core's counter\n\t  every 100ms. The Training phase will take 5 seconds.\n\n\tb.Normal phase. When the real traffic pass-though, the system will\n\t  compare run-time empty poll moving average value with base line\n\t  then make decision to move to HIGH power state of MED  power state.\n\t  The system will collect all core's counter every 100ms.\n\n3. Proposed  API\n\n1.  rte_empty_poll_stat_init(void);\nwhich is used to initialize the power management system.\n \n2.  rte_empty_poll_stat_free(void);\nwhich is used to free the resource hold by power management system.\n \n3.  rte_empty_poll_stat_update(unsigned int lcore_id);\nwhich is used to update specific core empty poll counter, not thread safe\n \n4.  rte_poll_stat_update(unsigned int lcore_id, uint8_t nb_pkt);\nwhich is used to update specific core valid poll counter, not thread safe\n \n5.  rte_empty_poll_stat_fetch(unsigned int lcore_id);\nwhich is used to get specific core empty poll counter.\n \n6.  rte_poll_stat_fetch(unsigned int lcore_id);\nwhich is used to get specific core valid poll counter.\n\n7.  rte_empty_poll_set_freq(enum freq_val index, uint32_t limit);\nwhich allow user customize the frequency of power state.\n\n8.  rte_empty_poll_setup_timer(void);\nwhich is used to setup the timer/callback to process all above counter.\n\nSigned-off-by: Liang Ma <liang.j.ma@intel.com>\n---\n lib/librte_power/Makefile         |   3 +-\n lib/librte_power/meson.build      |   5 +-\n lib/librte_power/rte_empty_poll.c | 529 ++++++++++++++++++++++++++++++++++++++\n lib/librte_power/rte_empty_poll.h | 135 ++++++++++\n 4 files changed, 669 insertions(+), 3 deletions(-)\n create mode 100644 lib/librte_power/rte_empty_poll.c\n create mode 100644 lib/librte_power/rte_empty_poll.h",
    "diff": "diff --git a/lib/librte_power/Makefile b/lib/librte_power/Makefile\nindex 6f85e88..dbc175a 100644\n--- a/lib/librte_power/Makefile\n+++ b/lib/librte_power/Makefile\n@@ -16,8 +16,9 @@ LIBABIVER := 1\n # all source are stored in SRCS-y\n SRCS-$(CONFIG_RTE_LIBRTE_POWER) := rte_power.c power_acpi_cpufreq.c\n SRCS-$(CONFIG_RTE_LIBRTE_POWER) += power_kvm_vm.c guest_channel.c\n+SRCS-$(CONFIG_RTE_LIBRTE_POWER) += rte_empty_poll.c\n \n # install this header file\n-SYMLINK-$(CONFIG_RTE_LIBRTE_POWER)-include := rte_power.h\n+SYMLINK-$(CONFIG_RTE_LIBRTE_POWER)-include := rte_power.h  rte_empty_poll.h\n \n include $(RTE_SDK)/mk/rte.lib.mk\ndiff --git a/lib/librte_power/meson.build b/lib/librte_power/meson.build\nindex 253173f..5270fa3 100644\n--- a/lib/librte_power/meson.build\n+++ b/lib/librte_power/meson.build\n@@ -5,5 +5,6 @@ if host_machine.system() != 'linux'\n \tbuild = false\n endif\n sources = files('rte_power.c', 'power_acpi_cpufreq.c',\n-\t\t'power_kvm_vm.c', 'guest_channel.c')\n-headers = files('rte_power.h')\n+\t\t'power_kvm_vm.c', 'guest_channel.c',\n+\t\t'rte_empty_poll.c')\n+headers = files('rte_power.h','rte_empty_poll.h')\ndiff --git a/lib/librte_power/rte_empty_poll.c b/lib/librte_power/rte_empty_poll.c\nnew file mode 100644\nindex 0000000..57bd63b\n--- /dev/null\n+++ b/lib/librte_power/rte_empty_poll.c\n@@ -0,0 +1,529 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2010-2018 Intel Corporation\n+ */\n+\n+#include <string.h>\n+\n+#include <rte_lcore.h>\n+#include <rte_cycles.h>\n+#include <rte_atomic.h>\n+#include <rte_malloc.h>\n+\n+\n+\n+\n+#include \"rte_power.h\"\n+#include \"rte_empty_poll.h\"\n+\n+\n+\n+\n+#define INTERVALS_PER_SECOND 10     /* (100ms) */\n+#define SECONDS_TO_TRAIN_FOR  5\n+#define DEFAULT_MED_TO_HIGH_PERCENT_THRESHOLD 70\n+#define DEFAULT_HIGH_TO_MED_PERCENT_THRESHOLD 30\n+#define DEFAULT_CYCLES_PER_PACKET 800\n+\n+\n+static struct ep_params *ep_params;\n+static uint32_t med_to_high_threshold = DEFAULT_MED_TO_HIGH_PERCENT_THRESHOLD;\n+static uint32_t high_to_med_threshold = DEFAULT_HIGH_TO_MED_PERCENT_THRESHOLD;\n+\n+static uint32_t avail_freqs[RTE_MAX_LCORE][NUM_FREQS];\n+\n+static uint32_t total_avail_freqs[RTE_MAX_LCORE];\n+\n+static uint32_t freq_index[NUM_FREQ];\n+\n+\n+\n+static uint32_t\n+get_freq_index(enum freq_val index)\n+{\n+\treturn freq_index[index];\n+}\n+\n+\n+static int\n+set_power_freq(int lcore_id, enum freq_val freq, bool specific_freq)\n+{\n+\tint err = 0;\n+\tuint32_t power_freq_index;\n+\tif (!specific_freq)\n+\t\tpower_freq_index = get_freq_index(freq);\n+\telse\n+\t\tpower_freq_index = freq;\n+\n+\terr = rte_power_set_freq(lcore_id, power_freq_index);\n+\n+\treturn err;\n+}\n+\n+\n+static inline void __attribute__((always_inline))\n+exit_training_state(struct priority_worker *poll_stats)\n+{\n+\tRTE_SET_USED(poll_stats);\n+}\n+\n+static inline void __attribute__((always_inline))\n+enter_training_state(struct priority_worker *poll_stats)\n+{\n+\tpoll_stats->iter_counter = 0;\n+\tpoll_stats->cur_freq = LOW;\n+\tpoll_stats->queue_state = TRAINING;\n+}\n+\n+static inline void __attribute__((always_inline))\n+enter_normal_state(struct priority_worker *poll_stats)\n+{\n+\t/* Clear the averages arrays and strs */\n+\tmemset(poll_stats->edpi_av, 0, sizeof(poll_stats->edpi_av));\n+\tpoll_stats->ec = 0;\n+\tmemset(poll_stats->ppi_av, 0, sizeof(poll_stats->ppi_av));\n+\tpoll_stats->pc = 0;\n+\n+\tpoll_stats->cur_freq = MED;\n+\tpoll_stats->iter_counter = 0;\n+\tpoll_stats->threshold_ctr = 0;\n+\tpoll_stats->queue_state = MED_NORMAL;\n+\tset_power_freq(poll_stats->lcore_id, MED, false);\n+\n+\t/* Try here */\n+\tpoll_stats->thresh[MED].threshold_percent = med_to_high_threshold;\n+\tpoll_stats->thresh[HGH].threshold_percent = high_to_med_threshold;\n+}\n+\n+static inline void __attribute__((always_inline))\n+enter_busy_state(struct priority_worker *poll_stats)\n+{\n+\tmemset(poll_stats->edpi_av, 0, sizeof(poll_stats->edpi_av));\n+\tpoll_stats->ec = 0;\n+\tmemset(poll_stats->ppi_av, 0, sizeof(poll_stats->ppi_av));\n+\tpoll_stats->pc = 0;\n+\n+\tpoll_stats->cur_freq = HGH;\n+\tpoll_stats->iter_counter = 0;\n+\tpoll_stats->threshold_ctr = 0;\n+\tpoll_stats->queue_state = HGH_BUSY;\n+\tset_power_freq(poll_stats->lcore_id, HGH, false);\n+}\n+\n+static inline void __attribute__((always_inline))\n+enter_purge_state(struct priority_worker *poll_stats)\n+{\n+\tpoll_stats->iter_counter = 0;\n+\tpoll_stats->queue_state = LOW_PURGE;\n+}\n+\n+static inline void __attribute__((always_inline))\n+set_state(struct priority_worker *poll_stats,\n+\t\tenum queue_state new_state)\n+{\n+\tenum queue_state old_state = poll_stats->queue_state;\n+\tif (old_state != new_state) {\n+\n+\t\t/* Call any old state exit functions */\n+\t\tif (old_state == TRAINING)\n+\t\t\texit_training_state(poll_stats);\n+\n+\t\t/* Call any new state entry functions */\n+\t\tif (new_state == TRAINING)\n+\t\t\tenter_training_state(poll_stats);\n+\t\tif (new_state == MED_NORMAL)\n+\t\t\tenter_normal_state(poll_stats);\n+\t\tif (new_state == HGH_BUSY)\n+\t\t\tenter_busy_state(poll_stats);\n+\t\tif (new_state == LOW_PURGE)\n+\t\t\tenter_purge_state(poll_stats);\n+\t}\n+}\n+\n+\n+static void\n+update_training_stats(struct priority_worker *poll_stats,\n+\t\tuint32_t freq,\n+\t\tbool specific_freq,\n+\t\tuint32_t max_train_iter)\n+{\n+\tRTE_SET_USED(specific_freq);\n+\n+\tchar pfi_str[32];\n+\tuint64_t p0_empty_deq;\n+\n+\tsprintf(pfi_str, \"%02d\", freq);\n+\n+\tif (poll_stats->cur_freq == freq &&\n+\t\t\tpoll_stats->thresh[freq].trained == false) {\n+\t\tif (poll_stats->thresh[freq].cur_train_iter == 0) {\n+\n+\t\t\tset_power_freq(poll_stats->lcore_id,\n+\t\t\t\t\tfreq, specific_freq);\n+\n+\t\t\tpoll_stats->empty_dequeues_prev =\n+\t\t\t\tpoll_stats->empty_dequeues;\n+\n+\t\t\tpoll_stats->thresh[freq].cur_train_iter++;\n+\n+\t\t\treturn;\n+\t\t} else if (poll_stats->thresh[freq].cur_train_iter\n+\t\t\t\t<= max_train_iter) {\n+\n+\t\t\tp0_empty_deq = poll_stats->empty_dequeues -\n+\t\t\t\tpoll_stats->empty_dequeues_prev;\n+\n+\t\t\tpoll_stats->empty_dequeues_prev =\n+\t\t\t\tpoll_stats->empty_dequeues;\n+\n+\t\t\tpoll_stats->thresh[freq].base_edpi += p0_empty_deq;\n+\t\t\tpoll_stats->thresh[freq].cur_train_iter++;\n+\n+\t\t} else {\n+\t\t\tif (poll_stats->thresh[freq].trained == false) {\n+\t\t\t\tpoll_stats->thresh[freq].base_edpi =\n+\t\t\t\t\tpoll_stats->thresh[freq].base_edpi /\n+\t\t\t\t\tmax_train_iter;\n+\n+\t\t\t\t/* Add on a factor of 0.05%, this should remove any */\n+\t\t\t\t/* false negatives when the system is 0% busy */\n+\t\t\t\tpoll_stats->thresh[freq].base_edpi +=\n+\t\t\t\t\tpoll_stats->thresh[freq].base_edpi / 2000;\n+\n+\t\t\t\tpoll_stats->thresh[freq].trained = true;\n+\t\t\t\tpoll_stats->cur_freq++;\n+\n+\t\t\t}\n+\t\t}\n+\t}\n+}\n+\n+static inline uint32_t __attribute__((always_inline))\n+update_stats(struct priority_worker *poll_stats)\n+{\n+\tuint64_t tot_edpi = 0, tot_ppi = 0;\n+\tuint32_t j, percent;\n+\n+\tstruct priority_worker *s = poll_stats;\n+\n+\tuint64_t cur_edpi = s->empty_dequeues - s->empty_dequeues_prev;\n+\n+\ts->empty_dequeues_prev = s->empty_dequeues;\n+\n+\tuint64_t ppi = s->num_dequeue_pkts - s->num_dequeue_pkts_prev;\n+\n+\ts->num_dequeue_pkts_prev = s->num_dequeue_pkts;\n+\n+\tif (s->thresh[s->cur_freq].base_edpi < cur_edpi)\n+\t\treturn 1000UL; /* Value to make us fail */\n+\n+\ts->edpi_av[s->ec++ % BINS_AV] = cur_edpi;\n+\ts->ppi_av[s->pc++ % BINS_AV] = ppi;\n+\n+\tfor (j = 0; j < BINS_AV; j++) {\n+\t\ttot_edpi += s->edpi_av[j];\n+\t\ttot_ppi += s->ppi_av[j];\n+\t}\n+\n+\ttot_edpi = tot_edpi / BINS_AV;\n+\n+\tpercent = 100 - (uint32_t)((float)tot_edpi /\n+\t\t\t(float)s->thresh[s->cur_freq].base_edpi * 100);\n+\n+\treturn (uint32_t)percent;\n+}\n+\n+\n+static inline void  __attribute__((always_inline))\n+update_stats_normal(struct priority_worker *poll_stats)\n+{\n+\tuint32_t percent;\n+\n+\tif (poll_stats->thresh[poll_stats->cur_freq].base_edpi == 0)\n+\t\treturn;\n+\n+\tpercent = update_stats(poll_stats);\n+\n+\tif (percent > 100)\n+\t\treturn;\n+\n+\tif (poll_stats->cur_freq == LOW)\n+\t\tRTE_LOG(INFO, POWER, \"Purge Mode is not supported\\n\");\n+\telse if (poll_stats->cur_freq == MED) {\n+\n+\t\tif (percent > poll_stats->thresh[poll_stats->cur_freq].\n+\t\t\t\tthreshold_percent) {\n+\n+\t\t\tif (poll_stats->threshold_ctr < INTERVALS_PER_SECOND)\n+\t\t\t\tpoll_stats->threshold_ctr++;\n+\t\t\telse\n+\t\t\t\tset_state(poll_stats, HGH_BUSY);\n+\n+\t\t} else {\n+\t\t\t/* reset */\n+\t\t\tpoll_stats->threshold_ctr = 0;\n+\t\t}\n+\n+\t} else if (poll_stats->cur_freq == HGH) {\n+\n+\t\tif (percent < poll_stats->thresh[poll_stats->cur_freq].\n+\t\t\t\tthreshold_percent) {\n+\n+\t\t\tif (poll_stats->threshold_ctr < INTERVALS_PER_SECOND)\n+\t\t\t\tpoll_stats->threshold_ctr++;\n+\t\t\telse\n+\t\t\t\tset_state(poll_stats, MED_NORMAL);\n+\t\t} else\n+\t\t\t/* reset */\n+\t\t\tpoll_stats->threshold_ctr = 0;\n+\n+\n+\t}\n+}\n+\n+static int\n+empty_poll_trainning(struct priority_worker *poll_stats,\n+\t\tuint32_t max_train_iter) {\n+\n+\tif (poll_stats->iter_counter < INTERVALS_PER_SECOND) {\n+\t\tpoll_stats->iter_counter++;\n+\t\treturn 0;\n+\t}\n+\n+\n+\tupdate_training_stats(poll_stats,\n+\t\t\tLOW,\n+\t\t\tfalse,\n+\t\t\tmax_train_iter);\n+\n+\tupdate_training_stats(poll_stats,\n+\t\t\tMED,\n+\t\t\tfalse,\n+\t\t\tmax_train_iter);\n+\n+\tupdate_training_stats(poll_stats,\n+\t\t\tHGH,\n+\t\t\tfalse,\n+\t\t\tmax_train_iter);\n+\n+\n+\tif (poll_stats->thresh[LOW].trained == true\n+\t\t\t&& poll_stats->thresh[MED].trained == true\n+\t\t\t&& poll_stats->thresh[HGH].trained == true) {\n+\n+\t\tset_state(poll_stats, MED_NORMAL);\n+\n+\t\tRTE_LOG(INFO, POWER, \"Training is Complete for %d\\n\",\n+\t\t\t\tpoll_stats->lcore_id);\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static void\n+empty_poll_detection(struct rte_timer *tim,\n+\t\tvoid *arg)\n+{\n+\n+\tuint32_t i;\n+\n+\tstruct priority_worker *poll_stats;\n+\n+\tRTE_SET_USED(tim);\n+\n+\tRTE_SET_USED(arg);\n+\n+\tfor (i = 0; i < NUM_NODES; i++) {\n+\n+\t\tpoll_stats = &(ep_params->wrk_data.wrk_stats[i]);\n+\n+\t\tif (rte_lcore_is_enabled(poll_stats->lcore_id) == 0)\n+\t\t\tcontinue;\n+\n+\t\tswitch (poll_stats->queue_state) {\n+\t\tcase(TRAINING):\n+\t\t\tempty_poll_trainning(poll_stats,\n+\t\t\t\t\tep_params->max_train_iter);\n+\t\t\tbreak;\n+\n+\t\tcase(HGH_BUSY):\n+\t\tcase(MED_NORMAL):\n+\t\t\tupdate_stats_normal(poll_stats);\n+\n+\t\t\tbreak;\n+\n+\t\tcase(LOW_PURGE):\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tbreak;\n+\n+\t\t}\n+\n+\t}\n+\n+}\n+\n+int\n+rte_empty_poll_stat_init(void)\n+{\n+\tuint32_t i;\n+\t/* Allocate the ep_params structure */\n+\tep_params = rte_zmalloc_socket(NULL,\n+\t\t\tsizeof(struct ep_params),\n+\t\t\t0,\n+\t\t\trte_socket_id());\n+\n+\tif (!ep_params)\n+\t\trte_panic(\"Cannot allocate heap memory for ep_params \"\n+\t\t\t\t\"for socket %d\\n\", rte_socket_id());\n+\n+\tfreq_index[LOW] = 14;\n+\tfreq_index[MED] = 9;\n+\tfreq_index[HGH] = 1;\n+\n+\tRTE_LOG(INFO, POWER, \"Initialize the Empty Poll\\n\");\n+\n+\t/* 5 seconds worth of training */\n+\tep_params->max_train_iter = INTERVALS_PER_SECOND * SECONDS_TO_TRAIN_FOR;\n+\n+\tstruct stats_data *w = &ep_params->wrk_data;\n+\n+\t/* initialize all wrk_stats state */\n+\tfor (i = 0; i < NUM_NODES; i++) {\n+\n+\t\tif (rte_lcore_is_enabled(i) == 0)\n+\t\t\tcontinue;\n+\n+\t\tset_state(&w->wrk_stats[i], TRAINING);\n+\t\t/*init the freqs table */\n+\t\ttotal_avail_freqs[i] = rte_power_freqs(i,\n+\t\t\t\tavail_freqs[i],\n+\t\t\t\tNUM_FREQS);\n+\n+\t\tif (get_freq_index(LOW) > total_avail_freqs[i])\n+\t\t\treturn -1;\n+\n+\t}\n+\n+\n+\treturn 0;\n+}\n+\n+void\n+rte_empty_poll_stat_free(void)\n+{\n+\n+\tRTE_LOG(INFO, POWER, \"Close the Empty Poll\\n\");\n+\n+\tif (ep_params != NULL)\n+\t\trte_free(ep_params);\n+}\n+\n+int\n+rte_empty_poll_stat_update(unsigned int lcore_id)\n+{\n+\tstruct priority_worker *poll_stats;\n+\n+\tif (lcore_id >= NUM_NODES)\n+\t\treturn -1;\n+\n+\tpoll_stats = &(ep_params->wrk_data.wrk_stats[lcore_id]);\n+\n+\tif (poll_stats->lcore_id == 0)\n+\t\tpoll_stats->lcore_id = lcore_id;\n+\n+\tpoll_stats->empty_dequeues++;\n+\n+\treturn 0;\n+}\n+\n+int\n+rte_poll_stat_update(unsigned int lcore_id, uint8_t nb_pkt)\n+{\n+\n+\tstruct priority_worker *poll_stats;\n+\n+\tif (lcore_id >= NUM_NODES)\n+\t\treturn -1;\n+\n+\tpoll_stats = &(ep_params->wrk_data.wrk_stats[lcore_id]);\n+\n+\tif (poll_stats->lcore_id == 0)\n+\t\tpoll_stats->lcore_id = lcore_id;\n+\n+\tpoll_stats->num_dequeue_pkts += nb_pkt;\n+\n+\treturn 0;\n+}\n+\n+\n+uint64_t\n+rte_empty_poll_stat_fetch(unsigned int lcore_id)\n+{\n+\tstruct priority_worker *poll_stats;\n+\n+\tif (lcore_id >= NUM_NODES)\n+\t\treturn -1;\n+\n+\tpoll_stats = &(ep_params->wrk_data.wrk_stats[lcore_id]);\n+\n+\tif (poll_stats->lcore_id == 0)\n+\t\tpoll_stats->lcore_id = lcore_id;\n+\n+\treturn poll_stats->empty_dequeues;\n+}\n+\n+uint64_t\n+rte_poll_stat_fetch(unsigned int lcore_id)\n+{\n+\tstruct priority_worker *poll_stats;\n+\n+\tif (lcore_id >= NUM_NODES)\n+\t\treturn -1;\n+\n+\tpoll_stats = &(ep_params->wrk_data.wrk_stats[lcore_id]);\n+\n+\tif (poll_stats->lcore_id == 0)\n+\t\tpoll_stats->lcore_id = lcore_id;\n+\n+\treturn poll_stats->num_dequeue_pkts;\n+}\n+\n+void\n+rte_empty_poll_set_freq(enum freq_val index, uint32_t limit)\n+{\n+\tswitch (index) {\n+\n+\tcase LOW:\n+\t\tfreq_index[LOW] = limit;\n+\t\tbreak;\n+\n+\tcase MED:\n+\t\tfreq_index[MED] = limit;\n+\t\tbreak;\n+\n+\tcase HGH:\n+\t\tfreq_index[HGH] = limit;\n+\t\tbreak;\n+\tdefault:\n+\t\tbreak;\n+\t}\n+}\n+\n+void\n+rte_empty_poll_setup_timer(void)\n+{\n+\tint lcore_id = rte_lcore_id();\n+\tuint64_t hz = rte_get_timer_hz();\n+\n+\tstruct  ep_params *ep_ptr = ep_params;\n+\n+\tep_ptr->interval_ticks = hz / INTERVALS_PER_SECOND;\n+\n+\trte_timer_reset_sync(&ep_ptr->timer0,\n+\t\t\tep_ptr->interval_ticks,\n+\t\t\tPERIODICAL,\n+\t\t\tlcore_id,\n+\t\t\tempty_poll_detection,\n+\t\t\t(void *)ep_ptr);\n+\n+}\ndiff --git a/lib/librte_power/rte_empty_poll.h b/lib/librte_power/rte_empty_poll.h\nnew file mode 100644\nindex 0000000..7e036ee\n--- /dev/null\n+++ b/lib/librte_power/rte_empty_poll.h\n@@ -0,0 +1,135 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2010-2018 Intel Corporation\n+ */\n+\n+#ifndef _RTE_EMPTY_POLL_H\n+#define _RTE_EMPTY_POLL_H\n+\n+/**\n+ * @file\n+ * RTE Power Management\n+ */\n+#include <stdint.h>\n+#include <stdbool.h>\n+#include <sys/queue.h>\n+\n+#include <rte_common.h>\n+#include <rte_byteorder.h>\n+#include <rte_log.h>\n+#include <rte_string_fns.h>\n+#include <rte_power.h>\n+#include <rte_timer.h>\n+\n+#ifdef __cplusplus\n+extern \"C\" {\n+#endif\n+\n+#define NUM_FREQS 20\n+\n+#define BINS_AV 4 /* has to be ^2 */\n+\n+#define DROP (NUM_DIRECTIONS * NUM_DEVICES)\n+\n+#define NUM_PRIORITIES          2\n+\n+#define NUM_NODES         31 /*any reseanable prime number should work*/\n+\n+\n+enum freq_val {\n+\tLOW,\n+\tMED,\n+\tHGH,\n+\tNUM_FREQ = NUM_FREQS\n+};\n+\n+\n+enum queue_state {\n+\tTRAINING, /* NO TRAFFIC */\n+\tMED_NORMAL,   /* MED */\n+\tHGH_BUSY,     /* HIGH */\n+\tLOW_PURGE,    /* LOW */\n+};\n+\n+/* queue stats */\n+struct freq_threshold {\n+\n+\tuint64_t base_edpi;\n+\tbool trained;\n+\tuint32_t threshold_percent;\n+\tuint32_t cur_train_iter;\n+};\n+\n+\n+struct priority_worker {\n+\n+\t/* Current dequeue and throughput counts */\n+\t/* These 2 are written to by the worker threads */\n+\t/* So keep them on their own cache line */\n+\tuint64_t empty_dequeues;\n+\tuint64_t num_dequeue_pkts;\n+\n+\tenum queue_state queue_state;\n+\n+\tuint64_t empty_dequeues_prev;\n+\tuint64_t num_dequeue_pkts_prev;\n+\n+\t/* Used for training only */\n+\tstruct freq_threshold thresh[NUM_FREQ];\n+\tenum freq_val cur_freq;\n+\n+\t/* bucket arrays to calculate the averages */\n+\tuint64_t edpi_av[BINS_AV];\n+\tuint32_t  ec;\n+\tuint64_t ppi_av[BINS_AV];\n+\tuint32_t  pc;\n+\n+\tuint32_t lcore_id;\n+\tuint32_t iter_counter;\n+\tuint32_t threshold_ctr;\n+\tuint32_t display_ctr;\n+\tuint8_t  dev_id;\n+\n+} __rte_cache_aligned;\n+\n+\n+struct stats_data {\n+\n+\tstruct priority_worker wrk_stats[NUM_NODES];\n+\n+\t/* flag to stop rx threads processing packets until training over */\n+\tbool start_rx;\n+\n+};\n+\n+struct ep_params {\n+\n+\t/* timer related stuff */\n+\tuint64_t interval_ticks;\n+\tuint32_t max_train_iter;\n+\tstruct rte_timer timer0;\n+\n+\tstruct stats_data wrk_data;\n+};\n+\n+\n+int rte_empty_poll_stat_init(void);\n+\n+void rte_empty_poll_stat_free(void);\n+\n+int rte_empty_poll_stat_update(unsigned int lcore_id);\n+\n+int rte_poll_stat_update(unsigned int lcore_id, uint8_t nb_pkt);\n+\n+uint64_t rte_empty_poll_stat_fetch(unsigned int lcore_id);\n+\n+uint64_t rte_poll_stat_fetch(unsigned int lcore_id);\n+\n+void rte_empty_poll_set_freq(enum freq_val index, uint32_t limit);\n+\n+void rte_empty_poll_setup_timer(void);\n+\n+#ifdef __cplusplus\n+}\n+#endif\n+\n+#endif\n",
    "prefixes": [
        "dpdk-dev",
        "v1",
        "1/2"
    ]
}