diff options
author | Daniele Di Proietto <diproiettod@vmware.com> | 2016-11-15 15:40:49 -0800 |
---|---|---|
committer | Daniele Di Proietto <diproiettod@vmware.com> | 2017-01-15 19:25:11 -0800 |
commit | b9584f2122f406ce6c732978ad5244c0eee17ff2 (patch) | |
tree | ed0ab0fd4a5a1e772654a862fefd3d473986143e /lib | |
parent | 2788a1b13822291a7f0eeda4055eafe85410feb1 (diff) | |
download | openvswitch-b9584f2122f406ce6c732978ad5244c0eee17ff2.tar.gz |
dpif-netdev: Create pmd threads for every numa node.
A lot of the complexity in the code that handles pmd threads and ports
in dpif-netdev is due to the fact that we postpone the creation of pmd
threads on a numa node until we have a port that needs to be polled on
that particular node.
Since the previous commit, a pmd thread with no ports will not consume
any CPU, so it seems easier to create all the threads at once.
This will also make future commits easier.
Signed-off-by: Daniele Di Proietto <diproiettod@vmware.com>
Acked-by: Ilya Maximets <i.maximets@samsung.com>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/dpif-netdev.c | 208 |
1 files changed, 68 insertions, 140 deletions
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index 9dff13b48..6cc6e141c 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -575,8 +575,8 @@ static struct dp_netdev_pmd_thread *dp_netdev_get_pmd(struct dp_netdev *dp, static struct dp_netdev_pmd_thread * dp_netdev_pmd_get_next(struct dp_netdev *dp, struct cmap_position *pos); static void dp_netdev_destroy_all_pmds(struct dp_netdev *dp); -static void dp_netdev_del_pmds_on_numa(struct dp_netdev *dp, int numa_id); -static void dp_netdev_set_pmds_on_numa(struct dp_netdev *dp, int numa_id) +static void dp_netdev_stop_pmds(struct dp_netdev *dp); +static void dp_netdev_start_pmds(struct dp_netdev *dp) OVS_REQUIRES(dp->port_mutex); static void dp_netdev_pmd_clear_ports(struct dp_netdev_pmd_thread *pmd); static void dp_netdev_del_port_from_all_pmds(struct dp_netdev *dp, @@ -1092,19 +1092,20 @@ dp_netdev_free(struct dp_netdev *dp) shash_find_and_delete(&dp_netdevs, dp->name); - dp_netdev_destroy_all_pmds(dp); - ovs_mutex_destroy(&dp->non_pmd_mutex); - ovsthread_key_delete(dp->per_pmd_key); - - conntrack_destroy(&dp->conntrack); - ovs_mutex_lock(&dp->port_mutex); HMAP_FOR_EACH_SAFE (port, next, node, &dp->ports) { do_del_port(dp, port); } ovs_mutex_unlock(&dp->port_mutex); + dp_netdev_destroy_all_pmds(dp); cmap_destroy(&dp->poll_threads); + ovs_mutex_destroy(&dp->non_pmd_mutex); + ovsthread_key_delete(dp->per_pmd_key); + + conntrack_destroy(&dp->conntrack); + + seq_destroy(dp->reconfigure_seq); seq_destroy(dp->port_seq); @@ -1348,10 +1349,7 @@ do_add_port(struct dp_netdev *dp, const char *devname, const char *type, } if (netdev_is_pmd(port->netdev)) { - int numa_id = netdev_get_numa_id(port->netdev); - - ovs_assert(ovs_numa_numa_id_is_valid(numa_id)); - dp_netdev_set_pmds_on_numa(dp, numa_id); + dp_netdev_start_pmds(dp); } dp_netdev_add_port_to_pmds(dp, port); @@ -1493,45 +1491,16 @@ get_n_pmd_threads(struct dp_netdev *dp) return cmap_count(&dp->poll_threads) - 1; } -static int -get_n_pmd_threads_on_numa(struct dp_netdev *dp, int numa_id) -{ - struct dp_netdev_pmd_thread *pmd; - int n_pmds = 0; - - CMAP_FOR_EACH (pmd, node, &dp->poll_threads) { - if (pmd->numa_id == numa_id) { - n_pmds++; - } - } - - return n_pmds; -} - -/* Returns 'true' if there is a port with pmd netdev and the netdev is on - * numa node 'numa_id' or its rx queue assigned to core on that numa node . */ +/* Returns 'true' if there is a port with pmd netdev. */ static bool -has_pmd_rxq_for_numa(struct dp_netdev *dp, int numa_id) +has_pmd_port(struct dp_netdev *dp) OVS_REQUIRES(dp->port_mutex) { struct dp_netdev_port *port; HMAP_FOR_EACH (port, node, &dp->ports) { if (netdev_is_pmd(port->netdev)) { - int i; - - if (netdev_get_numa_id(port->netdev) == numa_id) { - return true; - } - - for (i = 0; i < port->n_rxq; i++) { - unsigned core_id = port->rxqs[i].core_id; - - if (core_id != OVS_CORE_UNSPEC - && ovs_numa_get_numa_id(core_id) == numa_id) { - return true; - } - } + return true; } } @@ -1549,14 +1518,9 @@ do_del_port(struct dp_netdev *dp, struct dp_netdev_port *port) dp_netdev_del_port_from_all_pmds(dp, port); if (netdev_is_pmd(port->netdev)) { - int numa_id = netdev_get_numa_id(port->netdev); - - /* PMD threads can not be on invalid numa node. */ - ovs_assert(ovs_numa_numa_id_is_valid(numa_id)); - /* If there is no netdev on the numa node, deletes the pmd threads - * for that numa. */ - if (!has_pmd_rxq_for_numa(dp, numa_id)) { - dp_netdev_del_pmds_on_numa(dp, numa_id); + /* If there is no pmd netdev, delete the pmd threads */ + if (!has_pmd_port(dp)) { + dp_netdev_stop_pmds(dp); } } @@ -3423,18 +3387,22 @@ dp_netdev_del_pmd(struct dp_netdev *dp, struct dp_netdev_pmd_thread *pmd) dp_netdev_pmd_unref(pmd); } -/* Destroys all pmd threads. */ +/* Destroys all pmd threads, but not the non pmd thread. */ static void -dp_netdev_destroy_all_pmds(struct dp_netdev *dp) +dp_netdev_stop_pmds(struct dp_netdev *dp) { struct dp_netdev_pmd_thread *pmd; struct dp_netdev_pmd_thread **pmd_list; size_t k = 0, n_pmds; - n_pmds = cmap_count(&dp->poll_threads); + n_pmds = get_n_pmd_threads(dp); pmd_list = xcalloc(n_pmds, sizeof *pmd_list); CMAP_FOR_EACH (pmd, node, &dp->poll_threads) { + /* We don't need to destroy the non pmd thread */ + if (pmd->core_id == NON_PMD_CORE_ID) { + continue; + } /* We cannot call dp_netdev_del_pmd(), since it alters * 'dp->poll_threads' (while we're iterating it) and it * might quiesce. */ @@ -3448,51 +3416,30 @@ dp_netdev_destroy_all_pmds(struct dp_netdev *dp) free(pmd_list); } -/* Deletes all pmd threads on numa node 'numa_id' and - * fixes static_tx_qids of other threads to keep them sequential. */ +/* Destroys all pmd threads, including the non pmd thread. */ static void -dp_netdev_del_pmds_on_numa(struct dp_netdev *dp, int numa_id) +dp_netdev_destroy_all_pmds(struct dp_netdev *dp) { struct dp_netdev_pmd_thread *pmd; - int n_pmds_on_numa, n_pmds; - int *free_idx, k = 0; struct dp_netdev_pmd_thread **pmd_list; + size_t k = 0, n_pmds; - n_pmds_on_numa = get_n_pmd_threads_on_numa(dp, numa_id); - free_idx = xcalloc(n_pmds_on_numa, sizeof *free_idx); - pmd_list = xcalloc(n_pmds_on_numa, sizeof *pmd_list); + n_pmds = cmap_count(&dp->poll_threads); + pmd_list = xcalloc(n_pmds, sizeof *pmd_list); CMAP_FOR_EACH (pmd, node, &dp->poll_threads) { /* We cannot call dp_netdev_del_pmd(), since it alters * 'dp->poll_threads' (while we're iterating it) and it * might quiesce. */ - if (pmd->numa_id == numa_id && pmd->core_id != NON_PMD_CORE_ID) { - atomic_read_relaxed(&pmd->static_tx_qid, &free_idx[k]); - pmd_list[k] = pmd; - ovs_assert(k < n_pmds_on_numa); - k++; - } + ovs_assert(k < n_pmds); + pmd_list[k++] = pmd; } - for (int i = 0; i < k; i++) { + for (size_t i = 0; i < k; i++) { dp_netdev_del_pmd(dp, pmd_list[i]); } - n_pmds = get_n_pmd_threads(dp); - CMAP_FOR_EACH (pmd, node, &dp->poll_threads) { - int old_tx_qid; - - atomic_read_relaxed(&pmd->static_tx_qid, &old_tx_qid); - - if (old_tx_qid >= n_pmds && pmd->core_id != NON_PMD_CORE_ID) { - int new_tx_qid = free_idx[--k]; - - atomic_store_relaxed(&pmd->static_tx_qid, new_tx_qid); - } - } - free(pmd_list); - free(free_idx); } /* Deletes all rx queues from pmd->poll_list and all the ports from @@ -3743,52 +3690,55 @@ dp_netdev_add_port_to_pmds(struct dp_netdev *dp, struct dp_netdev_port *port) hmapx_destroy(&to_reload); } -/* Starts pmd threads for the numa node 'numa_id', if not already started. - * The function takes care of filling the threads tx port cache. */ static void -dp_netdev_set_pmds_on_numa(struct dp_netdev *dp, int numa_id) - OVS_REQUIRES(dp->port_mutex) +dp_netdev_start_pmds_on_numa(struct dp_netdev *dp, int numa_id) { - int n_pmds; + int can_have, n_unpinned, i; - if (!ovs_numa_numa_id_is_valid(numa_id)) { - VLOG_WARN("Cannot create pmd threads due to numa id (%d) invalid", - numa_id); + n_unpinned = ovs_numa_get_n_unpinned_cores_on_numa(numa_id); + if (!n_unpinned) { + VLOG_WARN("Cannot create pmd threads due to out of unpinned " + "cores on numa node %d", numa_id); return; } - n_pmds = get_n_pmd_threads_on_numa(dp, numa_id); + /* If cpu mask is specified, uses all unpinned cores, otherwise + * tries creating NR_PMD_THREADS pmd threads. */ + can_have = dp->pmd_cmask ? n_unpinned : MIN(n_unpinned, NR_PMD_THREADS); + for (i = 0; i < can_have; i++) { + unsigned core_id = ovs_numa_get_unpinned_core_on_numa(numa_id); + struct dp_netdev_pmd_thread *pmd = xzalloc(sizeof *pmd); + struct dp_netdev_port *port; - /* If there are already pmd threads created for the numa node - * in which 'netdev' is on, do nothing. Else, creates the - * pmd threads for the numa node. */ - if (!n_pmds) { - int can_have, n_unpinned, i; + dp_netdev_configure_pmd(pmd, dp, core_id, numa_id); - n_unpinned = ovs_numa_get_n_unpinned_cores_on_numa(numa_id); - if (!n_unpinned) { - VLOG_WARN("Cannot create pmd threads due to out of unpinned " - "cores on numa node %d", numa_id); - return; + HMAP_FOR_EACH (port, node, &dp->ports) { + dp_netdev_add_port_tx_to_pmd(pmd, port); } - /* If cpu mask is specified, uses all unpinned cores, otherwise - * tries creating NR_PMD_THREADS pmd threads. */ - can_have = dp->pmd_cmask ? n_unpinned : MIN(n_unpinned, NR_PMD_THREADS); - for (i = 0; i < can_have; i++) { - unsigned core_id = ovs_numa_get_unpinned_core_on_numa(numa_id); - struct dp_netdev_pmd_thread *pmd = xzalloc(sizeof *pmd); - struct dp_netdev_port *port; + pmd->thread = ovs_thread_create("pmd", pmd_thread_main, pmd); + } + VLOG_INFO("Created %d pmd threads on numa node %d", can_have, numa_id); +} + +/* Starts pmd threads, if not already started. The function takes care of + * filling the threads tx port cache. */ +static void +dp_netdev_start_pmds(struct dp_netdev *dp) + OVS_REQUIRES(dp->port_mutex) +{ + int n_pmds; - dp_netdev_configure_pmd(pmd, dp, core_id, numa_id); + n_pmds = get_n_pmd_threads(dp); - HMAP_FOR_EACH (port, node, &dp->ports) { - dp_netdev_add_port_tx_to_pmd(pmd, port); - } + /* If there are already pmd threads created for the datapath, do nothing. + * Else, creates the pmd threads. */ + if (!n_pmds) { + int n_numas = ovs_numa_get_n_numas(); - pmd->thread = ovs_thread_create("pmd", pmd_thread_main, pmd); + for (int numa_id = 0; numa_id < n_numas; numa_id++) { + dp_netdev_start_pmds_on_numa(dp, numa_id); } - VLOG_INFO("Created %d pmd threads on numa node %d", can_have, numa_id); } } @@ -3804,31 +3754,9 @@ dp_netdev_reset_pmd_threads(struct dp_netdev *dp) struct dp_netdev_port *port; struct hmapx_node *node; + dp_netdev_start_pmds(dp); + /* Distribute only pinned rx queues first to mark threads as isolated */ HMAP_FOR_EACH (port, node, &dp->ports) { - if (netdev_is_pmd(port->netdev)) { - struct hmapx numas = HMAPX_INITIALIZER(&numas); - struct hmapx_node *numa_node; - uintptr_t numa_id; - int i; - - numa_id = netdev_get_numa_id(port->netdev); - hmapx_add(&numas, (void *) numa_id); - for (i = 0; i < port->n_rxq; i++) { - unsigned core_id = port->rxqs[i].core_id; - - if (core_id != OVS_CORE_UNSPEC) { - numa_id = ovs_numa_get_numa_id(core_id); - hmapx_add(&numas, (void *) numa_id); - } - } - - HMAPX_FOR_EACH (numa_node, &numas) { - dp_netdev_set_pmds_on_numa(dp, (uintptr_t) numa_node->data); - } - - hmapx_destroy(&numas); - } - /* Distribute only pinned rx queues first to mark threads as isolated */ dp_netdev_add_port_rx_to_pmds(dp, port, &to_reload, true); } |