On Fri, Jun 17, 2022 at 12:10 PM Mike Pattrick <m...@redhat.com> wrote: > > On Mon, Jun 6, 2022 at 3:00 PM Michael Santana <msant...@redhat.com> wrote: > > > > Additional threads are required to service upcalls when we have CPU > > isolation (in per-cpu dispatch mode). The reason additional threads > > are required is because it creates a more fair distribution. With more > > threads we decrease the load of each thread as more threads would > > decrease the number of cores each threads is assigned. Adding as many > > threads are there are cores could have a performance hit when the number > > of active cores (which all threads have to share) is very low. For this > > reason we avoid creating as many threads as there are cores and instead > > meet somewhere in the middle. > > > > 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) > > Why are primes superior to just any odd number in between active and > total_cores? They aren't. Both strategies are valid and sufficient. The primes do provide a more or less even distribution. We dont want too many threads and not enough additional threads
I had proposed the following but it again it is not better or worse than the prime approach. It mainly just scales linearly handlers_n = min(active_cores/4, (total_cores-active_cores)/4) > > I may just be missing something; but if there were 8 active cores and > 12 total cores, why would 11 handlers be better than 9? > > Cheers, > M > > > > > Where next_prime is a function that returns the next numeric prime > > number that is strictly greater than active_cores > > > > Assume default behavior when total_cores <= 2, that is do not create > > additional threads when we have less than 2 total cores on the system > > > > Fixes: b1e517bd2f81 ("dpif-netlink: Introduce per-cpu upcall dispatch.") > > Signed-off-by: Michael Santana <msant...@redhat.com> > > --- > > lib/dpif-netlink.c | 86 ++++++++++++++++++++++++++++++++++++++++++++-- > > lib/ovs-thread.c | 16 +++++++++ > > lib/ovs-thread.h | 1 + > > 3 files changed, 101 insertions(+), 2 deletions(-) > > > > diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c > > index 06e1e8ca0..e948a829b 100644 > > --- a/lib/dpif-netlink.c > > +++ b/lib/dpif-netlink.c > > @@ -31,6 +31,7 @@ > > #include <sys/epoll.h> > > #include <sys/stat.h> > > #include <unistd.h> > > +#include <math.h> > > > > #include "bitmap.h" > > #include "dpif-netlink-rtnl.h" > > @@ -2506,6 +2507,87 @@ dpif_netlink_handler_uninit(struct dpif_handler > > *handler) > > } > > #endif > > > > +/* > > + * Returns 1 if num is a prime number, > > + * Otherwise return 0 > > + */ > > +static uint32_t > > +is_prime(uint32_t num) > > +{ > > + 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 UINT32_MAX. > > + * > > + * Returns 0 if no prime has been found between num and UINT32_MAX > > + */ > > +static uint32_t > > +next_prime(uint32_t num) > > +{ > > + if (num < 2) { > > + return 2; > > + } > > + if (num == 2) { > > + return 3; > > + } > > + if (num % 2 == 0) { > > + num++; > > + } > > + > > + uint32_t i; > > + for (i = num; i < UINT32_MAX; i += 2) { > > + if (is_prime(i)) { > > + return i; > > + } > > + } > > + > > + return 0; > > +} > > + > > +/* > > + * 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 && total_cores > 2) { > > + next_prime_num = next_prime(n_handlers + 1); > > + 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) > > @@ -2515,7 +2597,7 @@ dpif_netlink_refresh_handlers_cpu_dispatch(struct > > dpif_netlink *dpif) > > uint32_t n_handlers; > > uint32_t *upcall_pids; > > > > - n_handlers = count_cpu_cores(); > > + n_handlers = dpif_netlink_calculate_handlers_num(); > > if (dpif->n_handlers != n_handlers) { > > VLOG_DBG("Dispatch mode(per-cpu): initializing %d handlers", > > n_handlers); > > @@ -2755,7 +2837,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..2172b3d3f 100644 > > --- a/lib/ovs-thread.c > > +++ b/lib/ovs-thread.c > > @@ -663,6 +663,22 @@ 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 '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..aac5e19c9 100644 > > --- a/lib/ovs-thread.h > > +++ b/lib/ovs-thread.h > > @@ -522,6 +522,7 @@ bool may_fork(void); > > /* Useful functions related to threading. */ > > > > int count_cpu_cores(void); > > +int count_total_cores(void); > > bool thread_is_pmd(void); > > > > #endif /* ovs-thread.h */ > > -- > > 2.33.1 > > > > _______________________________________________ > > dev mailing list > > d...@openvswitch.org > > https://mail.openvswitch.org/mailman/listinfo/ovs-dev > > > _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev