Extend 'pmd-sleep-max' so that individual PMD thread cores may have a specified max sleep request value.
Any PMD thread core without a value will use the datapath default (no sleep request) or datapath global value set by the user. To set PMD thread cores 8 and 9 to never request a load based sleep and all other PMD thread cores to be able to request a max sleep of 50 usecs: $ ovs-vsctl set open_vswitch . other_config:pmd-sleep-max=50,8:0,9:0 To set PMD thread cores 10 and 11 to request a max sleep of 100 usecs and all other PMD thread cores to never request a sleep: $ ovs-vsctl set open_vswitch . other_config:pmd-sleep-max=10:100,11:100 'pmd-sleep-show' can be used to dump the global and individual PMD thread core max sleep request values. Signed-off-by: Kevin Traynor <ktray...@redhat.com> --- Documentation/topics/dpdk/pmd.rst | 23 +++ lib/dpif-netdev-private-thread.h | 3 + lib/dpif-netdev.c | 225 ++++++++++++++++++++++++++++-- tests/pmd.at | 32 ++--- 4 files changed, 252 insertions(+), 31 deletions(-) diff --git a/Documentation/topics/dpdk/pmd.rst b/Documentation/topics/dpdk/pmd.rst index 40e6b7843..eafcbc504 100644 --- a/Documentation/topics/dpdk/pmd.rst +++ b/Documentation/topics/dpdk/pmd.rst @@ -375,4 +375,27 @@ system configuration (e.g. enabling processor C-states) and workloads. rate. +Max sleep request values can be set for individual PMDs using key:value pairs. +Any PMD that has been assigned a specified value will use that. Any PMD that +does not have a specified value will use the current global default. + +Specified values for individual PMDs can be added or removed at any time. + +For example, to set PMD thread cores 8 and 9 to never request a load based +sleep and all others PMD cores to be able to request a max sleep of 50 usecs:: + + $ ovs-vsctl set open_vswitch . other_config:pmd-sleep-max=50,8:0,9:0 + +The max sleep request for each PMD can be checked in the logs or with:: + + $ ovs-appctl dpif-netdev/pmd-sleep-show + PMD max sleep request is 50 usecs by default. + PMD load based sleeps are enabled by default. + PMD thread core 8 NUMA 0: Max sleep request set to 0 usecs. + PMD thread core 9 NUMA 1: Max sleep request set to 0 usecs. + PMD thread core 10 NUMA 0: Max sleep request set to 50 usecs. + PMD thread core 11 NUMA 1: Max sleep request set to 50 usecs. + PMD thread core 12 NUMA 0: Max sleep request set to 50 usecs. + PMD thread core 13 NUMA 1: Max sleep request set to 50 usecs. + .. _ovs-vswitchd(8): http://openvswitch.org/support/dist-docs/ovs-vswitchd.8.html diff --git a/lib/dpif-netdev-private-thread.h b/lib/dpif-netdev-private-thread.h index 1ec3cd794..5c72ce5d9 100644 --- a/lib/dpif-netdev-private-thread.h +++ b/lib/dpif-netdev-private-thread.h @@ -181,4 +181,7 @@ struct dp_netdev_pmd_thread { bool isolated; + /* Max sleep request. UINT64_MAX indicates dp default should be used.*/ + atomic_uint64_t max_sleep; + /* Queue id used by this pmd thread to send packets on all netdevs if * XPS disabled for this netdev. All static_tx_qid's are unique and less diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index dadf17b70..ee0137ef1 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -180,4 +180,9 @@ static struct odp_support dp_netdev_support = { #define PMD_SLEEP_INC_US 1 +struct pmd_sleep { + unsigned core_id; + uint64_t max_sleep; +}; + struct dpcls { struct cmap_node node; /* Within dp_netdev_pmd_thread.classifiers */ @@ -290,4 +295,6 @@ struct dp_netdev { /* Max load based sleep request. */ atomic_uint64_t pmd_max_sleep; + /* Max load based sleep request user string. */ + char *max_sleep_list; /* Enable the SMC cache from ovsdb config */ atomic_bool smc_enable_db; @@ -890,9 +897,15 @@ pmd_max_sleep_show(struct ds *reply, struct dp_netdev_pmd_thread *pmd, { if (pmd->core_id != NON_PMD_CORE_ID) { + uint64_t pmd_max_sleep; + + atomic_read_relaxed(&pmd->max_sleep, &pmd_max_sleep); ds_put_format(reply, "PMD thread core %3u NUMA %2d: " "Max sleep request set to", pmd->core_id, pmd->numa_id); - ds_put_format(reply, " %4"PRIu64" usecs.", default_max_sleep); + ds_put_format(reply, " %4"PRIu64" usecs.", + pmd_max_sleep == UINT64_MAX + ? default_max_sleep + : pmd_max_sleep); ds_put_cstr(reply, "\n"); } @@ -1528,7 +1541,8 @@ dpif_netdev_pmd_info(struct unixctl_conn *conn, int argc, const char *argv[], atomic_read_relaxed(&dp->pmd_max_sleep, &default_max_sleep); ds_put_format(&reply, "PMD max sleep request is %"PRIu64" " - "usecs.", default_max_sleep); + "usecs by default.", default_max_sleep); ds_put_cstr(&reply, "\n"); - ds_put_format(&reply, "PMD load based sleeps are %s.", + ds_put_format(&reply, "PMD load based sleeps are %s " + "by default.", default_max_sleep ? "enabled" : "disabled"); ds_put_cstr(&reply, "\n"); @@ -1924,4 +1938,6 @@ create_dp_netdev(const char *name, const struct dpif_class *class, } + dp->max_sleep_list = NULL; + dp->last_tnl_conf_seq = seq_read(tnl_conf_seq); *dpp = dp; @@ -2033,4 +2049,5 @@ dp_netdev_free(struct dp_netdev *dp) dp_netdev_meter_destroy(dp); + free(dp->max_sleep_list); free(dp->pmd_cmask); free(CONST_CAST(char *, dp->name)); @@ -4847,4 +4864,8 @@ set_pmd_auto_lb(struct dp_netdev *dp, bool state, bool always_log) } +static void +set_all_pmd_max_sleeps(struct dp_netdev *dp, const struct smap *config, + bool always_log); + /* Applies datapath configuration from the database. Some of the changes are * actually applied in dpif_netdev_run(). */ @@ -4864,5 +4885,4 @@ dpif_netdev_set_config(struct dpif *dpif, const struct smap *other_config) uint8_t cur_rebalance_load; uint32_t rebalance_load, rebalance_improve; - uint64_t pmd_max_sleep, cur_pmd_max_sleep; bool log_autolb = false; enum sched_assignment_type pmd_rxq_assign_type; @@ -5015,15 +5035,7 @@ dpif_netdev_set_config(struct dpif *dpif, const struct smap *other_config) set_pmd_auto_lb(dp, autolb_state, log_autolb); - pmd_max_sleep = smap_get_ullong(other_config, "pmd-sleep-max", 0); - pmd_max_sleep = MIN(PMD_RCU_QUIESCE_INTERVAL, pmd_max_sleep); - atomic_read_relaxed(&dp->pmd_max_sleep, &cur_pmd_max_sleep); - if (first_set_config || pmd_max_sleep != cur_pmd_max_sleep) { - atomic_store_relaxed(&dp->pmd_max_sleep, pmd_max_sleep); - VLOG_INFO("PMD max sleep request is %"PRIu64" usecs.", pmd_max_sleep); - VLOG_INFO("PMD load based sleeps are %s.", - pmd_max_sleep ? "enabled" : "disabled" ); - } + set_all_pmd_max_sleeps(dp, other_config, first_set_config); - first_set_config = false; + first_set_config = false; return 0; } @@ -5065,4 +5077,182 @@ parse_affinity_list(const char *affinity_list, unsigned *core_ids, int n_rxq) } +static int +parse_pmd_sleep_list(const char *max_sleep_list, + struct pmd_sleep **pmd_sleeps) +{ + char *list, *copy, *key, *value; + int num_vals = 0; + + if (!max_sleep_list) { + return num_vals; + } + + list = copy = xstrdup(max_sleep_list); + + while (ofputil_parse_key_value(&list, &key, &value)) { + char *error = NULL; + unsigned core; + uint64_t temp, pmd_max_sleep; + int i; + + error = str_to_u64(key, &temp); + if (error) { + free(error); + continue; + } + + error = str_to_u64(value, &pmd_max_sleep); + if (error) { + /* No value specified. key is dp default. */ + core = UINT_MAX; + pmd_max_sleep = temp; + free(error); + } else { + /* Value specified. key is pmd core id.*/ + if (temp >= UINT_MAX) { + continue; + } + core = (unsigned) temp; + } + + /* Detect duplicate max sleep values for default or a specific core. */ + for (i = 0; i < num_vals; i++) { + if ((*pmd_sleeps)[i].core_id == core) { + break; + } + } + if (i == num_vals) { + /* Not duplicate, add a new entry. */ + *pmd_sleeps = xrealloc(*pmd_sleeps, + (num_vals + 1) * sizeof **pmd_sleeps); + num_vals++; + } + + pmd_max_sleep = MIN(PMD_RCU_QUIESCE_INTERVAL, pmd_max_sleep); + + (*pmd_sleeps)[i].core_id = core; + (*pmd_sleeps)[i].max_sleep = pmd_max_sleep; + } + + free(copy); + return num_vals; +} + +static void log_pmd_sleep(unsigned core_id, int numa_id, + uint64_t pmd_max_sleep, uint64_t default_max_sleep) +{ + VLOG_INFO("PMD thread core %3u NUMA %2d: Max sleep request set to " + "%4"PRIu64" usecs.", core_id, numa_id, + pmd_max_sleep == UINT64_MAX + ? default_max_sleep + : pmd_max_sleep); +} + +static void +set_pmd_max_sleep(struct dp_netdev *dp, struct dp_netdev_pmd_thread *pmd) +{ + struct pmd_sleep *pmd_sleeps = NULL; + uint64_t max_sleep = UINT64_MAX; + int num_vals; + + num_vals = parse_pmd_sleep_list(dp->max_sleep_list, &pmd_sleeps); + + /* Check if the user has set a specific value for this pmd. */ + for (int i = 0; i < num_vals; i++) { + if (pmd_sleeps[i].core_id == pmd->core_id) { + max_sleep = pmd_sleeps[i].max_sleep; + break; + } + } + atomic_init(&pmd->max_sleep, max_sleep); + log_pmd_sleep(pmd->core_id, pmd->numa_id, max_sleep, dp->pmd_max_sleep); + free(pmd_sleeps); +} + +static void +set_all_pmd_max_sleeps(struct dp_netdev *dp, const struct smap *config, + bool always_log) +{ + const char *max_sleep_list = smap_get(config, "pmd-sleep-max"); + struct pmd_sleep *pmd_sleeps = NULL; + struct dp_netdev_pmd_thread **pmd_list = NULL; + struct dp_netdev_pmd_thread *pmd; + int num_vals = 0; + uint64_t default_max_sleep = 0; + uint64_t cur_default_max_sleep; + size_t n; + + if (nullable_string_is_equal(max_sleep_list, dp->max_sleep_list) + && !always_log) { + return; + } + + /* Free existing string and copy new one. */ + free(dp->max_sleep_list); + dp->max_sleep_list = nullable_xstrdup(max_sleep_list); + + num_vals = parse_pmd_sleep_list(max_sleep_list, &pmd_sleeps); + + /* Check if the user has set a dp default. */ + for (int i = 0; i < num_vals; i++) { + if (pmd_sleeps[i].core_id == UINT_MAX) { + default_max_sleep = pmd_sleeps[i].max_sleep; + break; + } + } + atomic_read_relaxed(&dp->pmd_max_sleep, &cur_default_max_sleep); + if (default_max_sleep != cur_default_max_sleep) { + atomic_store_relaxed(&dp->pmd_max_sleep, default_max_sleep); + always_log = true; + } + + CMAP_FOR_EACH (pmd, node, &dp->poll_threads) { + uint64_t new_max_sleep, cur_pmd_max_sleep; + + if (pmd->core_id == NON_PMD_CORE_ID) { + continue; + } + + /* Default to dp value. */ + new_max_sleep = UINT64_MAX; + + /* Check for pmd specific value. */ + for (int i = 0; i < num_vals; i++) { + if (pmd->core_id == pmd_sleeps[i].core_id) { + new_max_sleep = pmd_sleeps[i].max_sleep; + break; + } + } + atomic_read_relaxed(&pmd->max_sleep, &cur_pmd_max_sleep); + if (new_max_sleep != cur_pmd_max_sleep) { + atomic_store_relaxed(&pmd->max_sleep, new_max_sleep); + always_log = true; + } + } + + if (always_log) { + VLOG_INFO("PMD max sleep request is %"PRIu64" " + "usecs by default.", default_max_sleep); + VLOG_INFO("PMD load based sleeps are %s by default.", + default_max_sleep ? "enabled" : "disabled" ); + + sorted_poll_thread_list(dp, &pmd_list, &n); + + for (size_t i = 0; i < n; i++) { + uint64_t cur_pmd_max_sleep; + + pmd = pmd_list[i]; + if (pmd->core_id == NON_PMD_CORE_ID) { + continue; + } + atomic_read_relaxed(&pmd->max_sleep, &cur_pmd_max_sleep); + log_pmd_sleep(pmd->core_id, pmd->numa_id, cur_pmd_max_sleep, + default_max_sleep); + } + free(pmd_list); + } + free(pmd_sleeps); +} + /* Parses 'affinity_list' and applies configuration if it is valid. */ static int @@ -7054,5 +7244,8 @@ reload: atomic_read_relaxed(&pmd->dp->smc_enable_db, &pmd->ctx.smc_enable_db); - atomic_read_relaxed(&pmd->dp->pmd_max_sleep, &max_sleep); + atomic_read_relaxed(&pmd->max_sleep, &max_sleep); + if (max_sleep == UINT64_MAX) { + atomic_read_relaxed(&pmd->dp->pmd_max_sleep, &max_sleep); + } for (i = 0; i < poll_cnt; i++) { @@ -7616,4 +7809,6 @@ dp_netdev_configure_pmd(struct dp_netdev_pmd_thread *pmd, struct dp_netdev *dp, cmap_init(&pmd->tx_bonds); + set_pmd_max_sleep(dp, pmd); + /* Initialize DPIF function pointer to the default configured version. */ atomic_init(&pmd->netdev_input_func, dp_netdev_impl_get_default()); diff --git a/tests/pmd.at b/tests/pmd.at index a158d0753..e83206a9a 100644 --- a/tests/pmd.at +++ b/tests/pmd.at @@ -66,6 +66,6 @@ dnl Checks correct pmd load based sleep is set for the datapath. dnl Checking starts from line number 'line' in ovs-vswithd.log . m4_define([CHECK_DP_SLEEP_MAX], [ - SLEEP_TIME="PMD max sleep request is $1 usecs." - SLEEP_STATE="PMD load based sleeps are $2." + SLEEP_TIME="PMD max sleep request is $1 usecs by default." + SLEEP_STATE="PMD load based sleeps are $2 by default." line_st=$4 if [[ -z "$line_st" ]] @@ -1279,6 +1279,6 @@ CHECK_DP_SLEEP_MAX([0], [disabled], []) AT_CHECK([ovs-appctl dpif-netdev/pmd-sleep-show], [0], [dnl -PMD max sleep request is 0 usecs. -PMD load based sleeps are disabled. +PMD max sleep request is 0 usecs by default. +PMD load based sleeps are disabled by default. ]) @@ -1288,6 +1288,6 @@ AT_CHECK([ovs-vsctl set open_vswitch . other_config:pmd-sleep-max="1"]) CHECK_DP_SLEEP_MAX([1], [enabled], [+$LINENUM]) AT_CHECK([ovs-appctl dpif-netdev/pmd-sleep-show], [0], [dnl -PMD max sleep request is 1 usecs. -PMD load based sleeps are enabled. +PMD max sleep request is 1 usecs by default. +PMD load based sleeps are enabled by default. ]) @@ -1297,6 +1297,6 @@ AT_CHECK([ovs-vsctl set open_vswitch . other_config:pmd-sleep-max="10000"]) CHECK_DP_SLEEP_MAX([10000], [enabled], [+$LINENUM]) AT_CHECK([ovs-appctl dpif-netdev/pmd-sleep-show], [0], [dnl -PMD max sleep request is 10000 usecs. -PMD load based sleeps are enabled. +PMD max sleep request is 10000 usecs by default. +PMD load based sleeps are enabled by default. ]) @@ -1306,6 +1306,6 @@ AT_CHECK([ovs-vsctl set open_vswitch . other_config:pmd-sleep-max="0"]) CHECK_DP_SLEEP_MAX([0], [disabled], [+$LINENUM]) AT_CHECK([ovs-appctl dpif-netdev/pmd-sleep-show], [0], [dnl -PMD max sleep request is 0 usecs. -PMD load based sleeps are disabled. +PMD max sleep request is 0 usecs by default. +PMD load based sleeps are disabled by default. ]) @@ -1315,6 +1315,6 @@ AT_CHECK([ovs-vsctl set open_vswitch . other_config:pmd-sleep-max="10001"]) CHECK_DP_SLEEP_MAX([10000], [enabled], [+$LINENUM]) AT_CHECK([ovs-appctl dpif-netdev/pmd-sleep-show], [0], [dnl -PMD max sleep request is 10000 usecs. -PMD load based sleeps are enabled. +PMD max sleep request is 10000 usecs by default. +PMD load based sleeps are enabled by default. ]) @@ -1324,6 +1324,6 @@ AT_CHECK([ovs-vsctl set open_vswitch . other_config:pmd-sleep-max="490"]) CHECK_DP_SLEEP_MAX([490], [enabled], [+$LINENUM]) AT_CHECK([ovs-appctl dpif-netdev/pmd-sleep-show], [0], [dnl -PMD max sleep request is 490 usecs. -PMD load based sleeps are enabled. +PMD max sleep request is 490 usecs by default. +PMD load based sleeps are enabled by default. ]) @@ -1333,6 +1333,6 @@ AT_CHECK([ovs-vsctl set open_vswitch . other_config:pmd-sleep-max="499"]) CHECK_DP_SLEEP_MAX([499], [enabled], [+$LINENUM]) AT_CHECK([ovs-appctl dpif-netdev/pmd-sleep-show], [0], [dnl -PMD max sleep request is 499 usecs. -PMD load based sleeps are enabled. +PMD max sleep request is 499 usecs by default. +PMD load based sleeps are enabled by default. ]) -- 2.40.1 _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev