Michael Santana <[email protected]> writes:
> Additional threads are required to service upcalls when we have CPU
> isolation (in per-cpu dispatch mode). The formula used to calculate
> the number of handler threads to create is as follows
>
> handlers_n = min(next_prime(active_cores+1), total_cores)
>
> Where next_prime is a function that returns the next numeric prime
> number that is strictly greater than active_cores
>
> Fixes: b1e517bd2f81 ("dpif-netlink: Introduce per-cpu upcall dispatch.")
> Signed-off-by: Michael Santana <[email protected]>
> ---
> lib/dpif-netlink.c | 32 ++++++++++++++++++++-
> lib/ovs-thread.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++
> lib/ovs-thread.h | 3 ++
> 3 files changed, 103 insertions(+), 1 deletion(-)
>
> diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c
> index 06e1e8ca0..53de16e12 100644
> --- a/lib/dpif-netlink.c
> +++ b/lib/dpif-netlink.c
> @@ -2506,6 +2506,36 @@ dpif_netlink_handler_uninit(struct dpif_handler
> *handler)
> }
> #endif
>
> +/*
> + * Calcuales and returns the number of handler threads needed based
> + * the following formula:
> + *
> + * handlers_n = min(next_prime(active_cores+1), total_cores)
> + *
> + * Where next_prime is a function that returns the next numeric prime
> + * number that is strictly greater than active_cores
> + */
> +static uint32_t
> +dpif_netlink_calculate_handlers_num(void)
> +{
> + uint32_t next_prime_num;
> + uint32_t n_handlers = count_cpu_cores();
> + uint32_t total_cores = count_total_cores();
> +
> + /*
> + * If we have isolated cores, add additional handler threads to
> + * service inactive cores in the unlikely event that traffic goes
> + * through inactive cores
> + */
> + if (n_handlers < total_cores) {
> + next_prime_num = next_prime(n_handlers +1, 10000000);
> + n_handlers = next_prime_num >= total_cores ?
> + total_cores : next_prime_num;
> + }
> +
> + return n_handlers;
> +}
> +
> static int
> dpif_netlink_refresh_handlers_cpu_dispatch(struct dpif_netlink *dpif)
> OVS_REQ_WRLOCK(dpif->upcall_lock)
> @@ -2755,7 +2785,7 @@ dpif_netlink_number_handlers_required(struct dpif
> *dpif_, uint32_t *n_handlers)
> struct dpif_netlink *dpif = dpif_netlink_cast(dpif_);
>
> if (dpif_netlink_upcall_per_cpu(dpif)) {
> - *n_handlers = count_cpu_cores();
> + *n_handlers = dpif_netlink_calculate_handlers_num();
> return true;
> }
>
> diff --git a/lib/ovs-thread.c b/lib/ovs-thread.c
> index 805cba622..fc3080d7c 100644
> --- a/lib/ovs-thread.c
> +++ b/lib/ovs-thread.c
> @@ -18,6 +18,7 @@
> #include "ovs-thread.h"
> #include <errno.h>
> #include <poll.h>
> +#include <math.h>
> #ifndef _WIN32
> #include <signal.h>
> #endif
> @@ -663,6 +664,74 @@ count_cpu_cores(void)
> return n_cores > 0 ? n_cores : 0;
> }
>
> +/* Returns the total number of cores on the system, or 0 if the
> + * number cannot be determined. */
> +int
> +count_total_cores(void) {
> + long int n_cores;
> +
> +#ifndef _WIN32
> + n_cores = sysconf(_SC_NPROCESSORS_CONF);
> +#else
> + n_cores = 0;
> + errno = ENOTSUP;
> +#endif
> +
> + return n_cores > 0 ? n_cores : 0;
> +}
> +
> +/*
> + * Returns 1 if num is a prime number,
> + * Otherwise return 0
> + */
Should this really be in ovs-thread? Does it need to be in the
"exposed" API? For example, we could just leave it out of the header
and make it static. WDYT?
> +uint32_t
> +is_prime(uint32_t num)
> +{
1 and 0 aren't prime numbers, but this will return '1' anyway. In this
particular patch usage it isn't important. In the future, maybe it
will be. I guess this should be something like:
> + if ((num % 2) == 0) {
+ if ((num < 2) || ((num % 2) == 0)) {
> + return num == 2;
> + }
> +
> + uint32_t i;
> + uint32_t limit = sqrt((float) num);
> + for (i = 3; i <= limit; i += 2) {
> + if (num % i == 0) {
> + return 0;
> + }
> + }
> +
> + return 1;
> +}
> +
> +/*
> + * Returns num if num is a prime number. Otherwise returns the next
> + * prime greater than num. Search is limited by the limit variable.
> + *
> + * Returns 0 if num >= limit, or if no prime has been found between
> + * num and limit
> + */
> +uint32_t
> +next_prime(uint32_t num, uint32_t limit)
> +{
> + if (num < 2) {
> + return 2;
> + }
> + if (num == 2) {
> + return 3;
> + }
> + if (num % 2 == 0) {
> + num++;
> + }
> +
> + uint32_t i;
> + for (i = num; i < limit; i += 2) {
> + if (is_prime(i)) {
> + return i;
> + }
> + }
> +
> + return 0;
> +}
> +
> /* Returns 'true' if current thread is PMD thread. */
> bool
> thread_is_pmd(void)
> diff --git a/lib/ovs-thread.h b/lib/ovs-thread.h
> index 3b444ccdc..6c1ebd098 100644
> --- a/lib/ovs-thread.h
> +++ b/lib/ovs-thread.h
> @@ -522,6 +522,9 @@ bool may_fork(void);
> /* Useful functions related to threading. */
>
> int count_cpu_cores(void);
> +int count_total_cores(void);
> +uint32_t is_prime(uint32_t num);
> +uint32_t next_prime(uint32_t num, uint32_t limit);
Maybe this should be in a different location - I suggest the 'util'
files (util.{c,h}).
> bool thread_is_pmd(void);
>
> #endif /* ovs-thread.h */
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev