get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 45587,
    "url": "http://patches.dpdk.org/api/patches/45587/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/1538146714-30973-1-git-send-email-liang.j.ma@intel.com/",
    "project": {
        "id": 1,
        "url": "http://patches.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": "<1538146714-30973-1-git-send-email-liang.j.ma@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1538146714-30973-1-git-send-email-liang.j.ma@intel.com",
    "date": "2018-09-28T14:58:31",
    "name": "[v9,1/4] lib/librte_power: traffic pattern aware power control",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "7a4eb6c5efbc18b7bb3a48d79241e5525fe100b0",
    "submitter": {
        "id": 904,
        "url": "http://patches.dpdk.org/api/people/904/?format=api",
        "name": "Liang, Ma",
        "email": "liang.j.ma@intel.com"
    },
    "delegate": {
        "id": 1,
        "url": "http://patches.dpdk.org/api/users/1/?format=api",
        "username": "tmonjalo",
        "first_name": "Thomas",
        "last_name": "Monjalon",
        "email": "thomas@monjalon.net"
    },
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/1538146714-30973-1-git-send-email-liang.j.ma@intel.com/mbox/",
    "series": [
        {
            "id": 1575,
            "url": "http://patches.dpdk.org/api/series/1575/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=1575",
            "date": "2018-09-28T14:58:32",
            "name": "[v9,1/4] lib/librte_power: traffic pattern aware power control",
            "version": 9,
            "mbox": "http://patches.dpdk.org/series/1575/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/45587/comments/",
    "check": "success",
    "checks": "http://patches.dpdk.org/api/patches/45587/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 1D89F1B4EA;\n\tFri, 28 Sep 2018 16:58:57 +0200 (CEST)",
            "from mga04.intel.com (mga04.intel.com [192.55.52.120])\n\tby dpdk.org (Postfix) with ESMTP id 706C41B4CB\n\tfor <dev@dpdk.org>; Fri, 28 Sep 2018 16:58:55 +0200 (CEST)",
            "from orsmga006.jf.intel.com ([10.7.209.51])\n\tby fmsmga104.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384;\n\t28 Sep 2018 07:58:54 -0700",
            "from irvmail001.ir.intel.com ([163.33.26.43])\n\tby orsmga006.jf.intel.com with ESMTP; 28 Sep 2018 07:58:38 -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\tw8SEwbL6016655; Fri, 28 Sep 2018 15:58:37 +0100",
            "from sivswdev01.ir.intel.com (localhost [127.0.0.1])\n\tby sivswdev01.ir.intel.com with ESMTP id w8SEwbdn031154;\n\tFri, 28 Sep 2018 15:58:37 +0100",
            "(from lma25@localhost)\n\tby sivswdev01.ir.intel.com with LOCAL id w8SEwbJm031150;\n\tFri, 28 Sep 2018 15:58:37 +0100"
        ],
        "X-Amp-Result": "SKIPPED(no attachment in message)",
        "X-Amp-File-Uploaded": "False",
        "X-ExtLoop1": "1",
        "X-IronPort-AV": "E=Sophos;i=\"5.54,315,1534834800\"; d=\"scan'208\";a=\"78259835\"",
        "From": "Liang Ma <liang.j.ma@intel.com>",
        "To": "david.hunt@intel.com",
        "Cc": "dev@dpdk.org, lei.a.yao@intel.com, ktraynor@redhat.com,\n\tmarko.kovacevic@intel.com, Liang Ma <liang.j.ma@intel.com>",
        "Date": "Fri, 28 Sep 2018 15:58:31 +0100",
        "Message-Id": "<1538146714-30973-1-git-send-email-liang.j.ma@intel.com>",
        "X-Mailer": "git-send-email 1.7.7.4",
        "In-Reply-To": "<1537191016-26330-1-git-send-email-liang.j.ma@intel.com>",
        "References": "<1537191016-26330-1-git-send-email-liang.j.ma@intel.com>",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain; charset=UTF-8",
        "Content-Transfer-Encoding": "8bit",
        "Subject": "[dpdk-dev] [PATCH v9 1/4] 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://mails.dpdk.org/options/dev>,\n\t<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\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 does not know how much real load is on a system, resulting\n     in wasted energy as no power management is utilized.\n\nCompared to the original l3fwd-power design, instead of going to sleep\nafter detecting an empty poll, the new mechanism just lowers the core\nfrequency. As a result, the application does not stop polling the device,\nwhich leads to improved handling of bursts of traffic.\n\nWhen the system become busy, the empty poll mechanism can also increase the\ncore frequency (including turbo) to do best effort for intensive traffic.\nThis gives us more flexible and balanced traffic awareness over the\nstandard l3fwd-power application.\n\n2. Proposed solution\n\nThe proposed solution focuses on how many times empty polls are executed.\nThe less the number of empty polls, means current core is busy with\nprocessing workload, therefore, the higher frequency is needed. The high\nempty poll number indicates the current core not doing any real work\ntherefore, we can lower the frequency to safe power.\n\nIn the current implementation, each core has 1 empty-poll counter which\nassume 1 core is dedicated to 1 queue. This will need to be expanded in the\nfuture to support multiple queues per core.\n\n2.1 Power state definition:\n\n\tLOW:  Not currently used, reserved for future use.\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. The training phase is necessary\n\t  in order to figure out the system polling baseline numbers from\n\t  idle to busy. The highest poll count will be during idle, where\n\t  all polls are empty. These poll counts will be different between\n\t  systems due to the many possible processor micro-arch, cache\n\t  and device configurations, hence the training phase.\n  \t  In the training phase, traffic is blocked so the training\n  \t  algorithm can average the empty-poll numbers for the LOW, MED and\n \t  HIGH  power states in order to create a baseline.\n  \t  The core's counter are collected every 10ms, and the Training\n \t  phase will take 2 seconds.\n \t  Training is disabled as default configuration. The default\n \t  parameter is applied. Sample App still can trigger training\n \t  if that's needed. Once the training phase has been executed once on\n \t  a system, the application can then be started with the relevant\n \t  thresholds provided on the command line, allowing the application\n \t  to start passing start traffic immediately\n\n\tb.Normal phase. Traffic starts immediately based on the default\n\t  thresholds, or based on the user supplied thresholds via the\n\t  command line parameters. The run-time poll counts are compared with\n\t  the baseline and the decision will be taken to move to MED power\n  \t  state or HIGH power state. The counters are calculated every 10ms.\n\n3. Proposed  API\n\n1.  rte_power_empty_poll_stat_init(struct ep_params **eptr,\n\t\tuint8_t *freq_tlb, struct ep_policy *policy);\nwhich is used to initialize the power management system.\n \n2.  rte_power_empty_poll_stat_free(void);\nwhich is used to free the resource hold by power management system.\n \n3.  rte_power_empty_poll_stat_update(unsigned int lcore_id);\nwhich is used to update specific core empty poll counter, not thread safe\n \n4.  rte_power_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_power_empty_poll_stat_fetch(unsigned int lcore_id);\nwhich is used to get specific core empty poll counter.\n \n6.  rte_power_poll_stat_fetch(unsigned int lcore_id);\nwhich is used to get specific core valid poll counter.\n\n7.  rte_empty_poll_detection(struct rte_timer *tim, void *arg);\nwhich is used to detect empty poll state changes then take action.\n\nChangeLog:\nv2: fix some coding style issues.\nv3: rename the filename, API name.\nv4: no change.\nv5: no change.\nv6: re-work the code layout, update API.\nv7: fix minor typo and lift node num limit.\nv8: disable training as default option.\nv9: minor git log update.\n\nSigned-off-by: Liang Ma <liang.j.ma@intel.com>\n\nReviewed-by: Lei Yao <lei.a.yao@intel.com>\n---\n lib/librte_power/Makefile               |   6 +-\n lib/librte_power/meson.build            |   5 +-\n lib/librte_power/rte_power_empty_poll.c | 539 ++++++++++++++++++++++++++++++++\n lib/librte_power/rte_power_empty_poll.h | 219 +++++++++++++\n lib/librte_power/rte_power_version.map  |  13 +\n 5 files changed, 778 insertions(+), 4 deletions(-)\n create mode 100644 lib/librte_power/rte_power_empty_poll.c\n create mode 100644 lib/librte_power/rte_power_empty_poll.h",
    "diff": "diff --git a/lib/librte_power/Makefile b/lib/librte_power/Makefile\nindex 6f85e88..a8f1301 100644\n--- a/lib/librte_power/Makefile\n+++ b/lib/librte_power/Makefile\n@@ -6,8 +6,9 @@ include $(RTE_SDK)/mk/rte.vars.mk\n # library name\n LIB = librte_power.a\n \n+CFLAGS += -DALLOW_EXPERIMENTAL_API\n CFLAGS += $(WERROR_FLAGS) -I$(SRCDIR) -O3 -fno-strict-aliasing\n-LDLIBS += -lrte_eal\n+LDLIBS += -lrte_eal -lrte_timer\n \n EXPORT_MAP := rte_power_version.map\n \n@@ -16,8 +17,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_power_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_power_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..63957eb 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_power_empty_poll.c')\n+headers = files('rte_power.h','rte_power_empty_poll.h')\ndiff --git a/lib/librte_power/rte_power_empty_poll.c b/lib/librte_power/rte_power_empty_poll.c\nnew file mode 100644\nindex 0000000..587ce78\n--- /dev/null\n+++ b/lib/librte_power/rte_power_empty_poll.c\n@@ -0,0 +1,539 @@\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+#include \"rte_power.h\"\n+#include \"rte_power_empty_poll.h\"\n+\n+#define INTERVALS_PER_SECOND 100     /* (10ms) */\n+#define SECONDS_TO_TRAIN_FOR 2\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+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+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+\tRTE_LOG(INFO, POWER, \"set the poewr freq to MED\\n\");\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+static inline void __attribute__((always_inline))\n+set_policy(struct priority_worker *poll_stats,\n+\t\tstruct ep_policy *policy)\n+{\n+\tset_state(poll_stats, policy->state);\n+\n+\tif (policy->state == TRAINING)\n+\t\treturn;\n+\n+\tpoll_stats->thresh[MED_NORMAL].base_edpi = policy->med_base_edpi;\n+\tpoll_stats->thresh[HGH_BUSY].base_edpi = policy->hgh_base_edpi;\n+\n+\tpoll_stats->thresh[MED_NORMAL].trained = true;\n+\tpoll_stats->thresh[HGH_BUSY].trained = true;\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%*/\n+\t\t\t\t/* 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\tRTE_LOG(DEBUG, POWER, \"cur_edpi is too large \"\n+\t\t\t\t\"cur edpi %ld \"\n+\t\t\t\t\"base epdi %ld\\n\",\n+\t\t\t\tcur_edpi,\n+\t\t\t\ts->thresh[s->cur_freq].base_edpi);\n+\t\t/* Value to make us fail need debug log*/\n+\t\treturn 1000UL;\n+\t}\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+\n+\t\tRTE_LOG(DEBUG, POWER, \"cure freq is %d, edpi is %lu\\n\",\n+\t\t\t\tpoll_stats->cur_freq,\n+\t\t\t\tpoll_stats->thresh[poll_stats->cur_freq].base_edpi);\n+\t\treturn;\n+\t}\n+\n+\tpercent = update_stats(poll_stats);\n+\n+\tif (percent > 100) {\n+\t\tRTE_LOG(DEBUG, POWER, \"Big than 100 abnormal\\n\");\n+\t\treturn;\n+\t}\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 >\n+\t\t\tpoll_stats->thresh[MED].threshold_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+\t\t\t\tRTE_LOG(INFO, POWER, \"MOVE to HGH\\n\");\n+\t\t\t}\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 <\n+\t\t\t\tpoll_stats->thresh[HGH].threshold_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\t\tRTE_LOG(INFO, POWER, \"MOVE to MED\\n\");\n+\t\t\t}\n+\t\t} else {\n+\t\t\t/* reset */\n+\t\t\tpoll_stats->threshold_ctr = 0;\n+\t\t}\n+\n+\t}\n+}\n+\n+static int\n+empty_poll_training(struct priority_worker *poll_stats,\n+\t\tuint32_t max_train_iter)\n+{\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, \"Low threshold is %lu\\n\",\n+\t\t\t\tpoll_stats->thresh[LOW].base_edpi);\n+\n+\t\tRTE_LOG(INFO, POWER, \"MED threshold is %lu\\n\",\n+\t\t\t\tpoll_stats->thresh[MED].base_edpi);\n+\n+\n+\t\tRTE_LOG(INFO, POWER, \"HIGH threshold is %lu\\n\",\n+\t\t\t\tpoll_stats->thresh[HGH].base_edpi);\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+void\n+rte_empty_poll_detection(struct rte_timer *tim, void *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_training(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+\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 __rte_experimental\n+rte_power_empty_poll_stat_init(struct ep_params **eptr, uint8_t *freq_tlb,\n+\t\tstruct ep_policy *policy)\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+\tif (freq_tlb == NULL) {\n+\t\tfreq_index[LOW] = 14;\n+\t\tfreq_index[MED] = 9;\n+\t\tfreq_index[HGH] = 1;\n+\t} else {\n+\t\tfreq_index[LOW] = freq_tlb[LOW];\n+\t\tfreq_index[MED] = freq_tlb[MED];\n+\t\tfreq_index[HGH] = freq_tlb[HGH];\n+\t}\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*eptr = ep_params;\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+\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\tRTE_LOG(INFO, POWER, \"total avail freq is %d , lcoreid %d\\n\",\n+\t\t\t\ttotal_avail_freqs[i],\n+\t\t\t\ti);\n+\n+\t\tif (get_freq_index(LOW) > total_avail_freqs[i])\n+\t\t\treturn -1;\n+\n+\t\tif (rte_get_master_lcore() != i) {\n+\t\t\tw->wrk_stats[i].lcore_id = i;\n+\t\t\tset_policy(&w->wrk_stats[i], policy);\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+void __rte_experimental\n+rte_power_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 __rte_experimental\n+rte_power_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 __rte_experimental\n+rte_power_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 __rte_experimental\n+rte_power_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 __rte_experimental\n+rte_power_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+}\ndiff --git a/lib/librte_power/rte_power_empty_poll.h b/lib/librte_power/rte_power_empty_poll.h\nnew file mode 100644\nindex 0000000..ae27f7d\n--- /dev/null\n+++ b/lib/librte_power/rte_power_empty_poll.h\n@@ -0,0 +1,219 @@\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+\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         256  /* Max core number*/\n+\n+/* Processor Power State */\n+enum freq_val {\n+\tLOW,\n+\tMED,\n+\tHGH,\n+\tNUM_FREQ = NUM_FREQS\n+};\n+\n+\n+/* Queue Polling State */\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+/* Each Worder Thread Empty Poll Stats */\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+/* Empty Poll Parameters */\n+struct ep_params {\n+\n+\t/* Timer related stuff */\n+\tuint64_t interval_ticks;\n+\tuint32_t max_train_iter;\n+\n+\tstruct rte_timer timer0;\n+\tstruct stats_data wrk_data;\n+};\n+\n+\n+/* Sample App Init information */\n+struct ep_policy {\n+\n+\tuint64_t med_base_edpi;\n+\tuint64_t hgh_base_edpi;\n+\n+\tenum queue_state state;\n+};\n+\n+\n+\n+/**\n+ * Initialize the power management system.\n+ *\n+ * @param eptr\n+ *   the structure of empty poll configuration\n+ * @freq_tlb\n+ *   the power state/frequency  mapping table\n+ * @policy\n+ *   the initialization policy from sample app\n+ *\n+ * @return\n+ *  - 0 on success.\n+ *  - Negative on error.\n+ */\n+int __rte_experimental\n+rte_power_empty_poll_stat_init(struct ep_params **eptr, uint8_t *freq_tlb,\n+\t\tstruct ep_policy *policy);\n+\n+/**\n+ * Free the resource hold by power management system.\n+ */\n+void __rte_experimental\n+rte_power_empty_poll_stat_free(void);\n+\n+/**\n+ * Update specific core empty poll counter\n+ * It's not thread safe.\n+ *\n+ * @param lcore_id\n+ *  lcore id\n+ *\n+ * @return\n+ *  - 0 on success.\n+ *  - Negative on error.\n+ */\n+int __rte_experimental\n+rte_power_empty_poll_stat_update(unsigned int lcore_id);\n+\n+/**\n+ * Update specific core valid poll counter, not thread safe.\n+ *\n+ * @param lcore_id\n+ *  lcore id.\n+ * @param nb_pkt\n+ *  The packet number of one valid poll.\n+ *\n+ * @return\n+ *  - 0 on success.\n+ *  - Negative on error.\n+ */\n+int __rte_experimental\n+rte_power_poll_stat_update(unsigned int lcore_id, uint8_t nb_pkt);\n+\n+/**\n+ * Fetch specific core empty poll counter.\n+ *\n+ * @param lcore_id\n+ *  lcore id\n+ *\n+ * @return\n+ *  Current lcore empty poll counter value.\n+ */\n+uint64_t __rte_experimental\n+rte_power_empty_poll_stat_fetch(unsigned int lcore_id);\n+\n+/**\n+ * Fetch specific core valid poll counter.\n+ *\n+ * @param lcore_id\n+ *  lcore id\n+ *\n+ * @return\n+ *  Current lcore valid poll counter value.\n+ */\n+uint64_t __rte_experimental\n+rte_power_poll_stat_fetch(unsigned int lcore_id);\n+\n+/**\n+ * Empty poll  state change detection function\n+ *\n+ * @param  tim\n+ *  The timer structure\n+ * @param  arg\n+ *  The customized parameter\n+ */\n+void  __rte_experimental\n+rte_empty_poll_detection(struct rte_timer *tim, void *arg);\n+\n+#ifdef __cplusplus\n+}\n+#endif\n+\n+#endif\ndiff --git a/lib/librte_power/rte_power_version.map b/lib/librte_power/rte_power_version.map\nindex dd587df..11ffdfb 100644\n--- a/lib/librte_power/rte_power_version.map\n+++ b/lib/librte_power/rte_power_version.map\n@@ -33,3 +33,16 @@ DPDK_18.08 {\n \trte_power_get_capabilities;\n \n } DPDK_17.11;\n+\n+EXPERIMENTAL {\n+        global:\n+\n+        rte_power_empty_poll_stat_init;\n+        rte_power_empty_poll_stat_free;\n+        rte_power_empty_poll_stat_update;\n+        rte_power_empty_poll_stat_fetch;\n+        rte_power_poll_stat_fetch;\n+        rte_power_poll_stat_update;\n+        rte_empty_poll_detection;\n+\n+};\n",
    "prefixes": [
        "v9",
        "1/4"
    ]
}