From b2b50a7784ae6b3feffa49a5010d5b82ead32ab9 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Sun, 3 Feb 2019 11:14:25 +0100 Subject: [PATCH] MINOR: listener: pre-compute some thread counts per bind_conf In order to quickly pick a thread ID when accepting a connection, we'll need to know certain pre-computed values derived from the thread mask, which are counts of bits per position multiples of 1, 2, 4, 8, 16 and 32. In practice it is sufficient to compute only the 4 first ones and store them in the bind_conf. We update the count every time the bind_thread value is adjusted. The fields in the bind_conf struct have been moved around a little bit to make it easier to group all thread bit values into the same cache line. The function used to return a thread number is bind_map_thread_id(), and it maps a number between 0 and 31/63 to a thread ID between 0 and 31/63, starting from the left. --- include/proto/listener.h | 3 +++ include/types/listener.h | 18 ++++++++++-------- src/cfgparse.c | 2 ++ src/listener.c | 28 ++++++++++++++++++++++++++++ 4 files changed, 43 insertions(+), 8 deletions(-) diff --git a/include/proto/listener.h b/include/proto/listener.h index fdace2b5f..3a6762ccb 100644 --- a/include/proto/listener.h +++ b/include/proto/listener.h @@ -127,6 +127,9 @@ struct bind_kw *bind_find_kw(const char *kw); /* Dumps all registered "bind" keywords to the string pointer. */ void bind_dump_kws(char **out); +void bind_recount_thread_bits(struct bind_conf *conf); +unsigned int bind_map_thread_id(const struct bind_conf *conf, unsigned int r); + /* allocate an bind_conf struct for a bind line, and chain it to the frontend . * If is not NULL, it is duplicated into ->arg to store useful config * information for error reporting. diff --git a/include/types/listener.h b/include/types/listener.h index f9eeafaa9..8e9db71dc 100644 --- a/include/types/listener.h +++ b/include/types/listener.h @@ -165,21 +165,23 @@ struct bind_conf { struct xprt_ops *xprt; /* transport-layer operations for all listeners */ int is_ssl; /* SSL is required for these listeners */ int generate_certs; /* 1 if generate-certificates option is set, else 0 */ + int level; /* stats access level (ACCESS_LVL_*) */ + int severity_output; /* default severity output format in cli feedback messages */ + struct list listeners; /* list of listeners using this bind config */ unsigned long bind_proc; /* bitmask of processes allowed to use these listeners */ unsigned long bind_thread; /* bitmask of threads allowed to use these listeners */ + unsigned long thr_2, thr_4, thr_8, thr_16; /* intermediate values for bind_thread counting */ + unsigned int thr_count; /* #threads bound */ + uint32_t ns_cip_magic; /* Excepted NetScaler Client IP magic number */ + struct list by_fe; /* next binding for the same frontend, or NULL */ + char *arg; /* argument passed to "bind" for better error reporting */ + char *file; /* file where the section appears */ + int line; /* line where the section appears */ struct { /* UNIX socket permissions */ uid_t uid; /* -1 to leave unchanged */ gid_t gid; /* -1 to leave unchanged */ mode_t mode; /* 0 to leave unchanged */ } ux; - int level; /* stats access level (ACCESS_LVL_*) */ - int severity_output; /* default severity output format in cli feedback messages */ - struct list by_fe; /* next binding for the same frontend, or NULL */ - struct list listeners; /* list of listeners using this bind config */ - uint32_t ns_cip_magic; /* Excepted NetScaler Client IP magic number */ - char *arg; /* argument passed to "bind" for better error reporting */ - char *file; /* file where the section appears */ - int line; /* line where the section appears */ }; /* The listener will be directly referenced by the fdtab[] which holds its diff --git a/src/cfgparse.c b/src/cfgparse.c index 16d92512c..0833574e9 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -2318,6 +2318,8 @@ int check_config_validity() curproxy->id, bind_conf->arg, bind_conf->file, bind_conf->line, new_mask); } + bind_recount_thread_bits(bind_conf); + /* detect process and nbproc affinity inconsistencies */ mask = proc_mask(bind_conf->bind_proc) & proc_mask(curproxy->bind_proc); if (!(mask & all_proc_mask)) { diff --git a/src/listener.c b/src/listener.c index f642eb4d0..fb527ab16 100644 --- a/src/listener.c +++ b/src/listener.c @@ -802,6 +802,33 @@ void bind_dump_kws(char **out) } } +/* recompute the bit counts per parity for the bind_thread value. This will be + * used to quickly map a thread number from 1 to #thread to a thread ID among + * the ones bound. This is the preparation phase of the bit rank counting algo + * described here: https://graphics.stanford.edu/~seander/bithacks.html + */ +void bind_recount_thread_bits(struct bind_conf *conf) +{ + unsigned long m; + + m = thread_mask(conf->bind_thread); + conf->thr_count = my_popcountl(m); + mask_prep_rank_map(m, &conf->thr_2, &conf->thr_4, &conf->thr_8, &conf->thr_16); +} + +/* Report the ID of thread in bind_conf according to its thread_mask. + * must be between 0 and LONGBITS-1. This makes use of the pre-computed + * bits resulting from bind_recount_thread_bits. See this function for more + * info. + */ +unsigned int bind_map_thread_id(const struct bind_conf *conf, unsigned int r) +{ + unsigned long m; + + m = thread_mask(conf->bind_thread); + return mask_find_rank_bit_fast(r, m, conf->thr_2, conf->thr_4, conf->thr_8, conf->thr_16); +} + /************************************************************************/ /* All supported sample and ACL keywords must be declared here. */ /************************************************************************/ @@ -1012,6 +1039,7 @@ static int bind_parse_process(char **args, int cur_arg, struct proxy *px, struct conf->bind_proc |= proc; conf->bind_thread |= thread; + bind_recount_thread_bits(conf); return 0; }