Re: [PATCH v3 4/5] locking/qspinlock: Introduce starvation avoidance into CNA

From: Peter Zijlstra
Date: Tue Jul 16 2019 - 11:59:17 EST


On Mon, Jul 15, 2019 at 03:25:35PM -0400, Alex Kogan wrote:

> @@ -36,6 +37,33 @@ struct cna_node {
>
> #define CNA_NODE(ptr) ((struct cna_node *)(ptr))
>
> +/* Per-CPU pseudo-random number seed */
> +static DEFINE_PER_CPU(u32, seed);
> +
> +/*
> + * Controls the probability for intra-node lock hand-off. It can be
> + * tuned and depend, e.g., on the number of CPUs per node. For now,
> + * choose a value that provides reasonable long-term fairness without
> + * sacrificing performance compared to a version that does not have any
> + * fairness guarantees.
> + */
> +#define INTRA_NODE_HANDOFF_PROB_ARG 0x10000
> +
> +/*
> + * Return false with probability 1 / @range.
> + * @range must be a power of 2.
> + */
> +static bool probably(unsigned int range)
> +{
> + u32 s;
> +
> + s = this_cpu_read(seed);
> + s = next_pseudo_random32(s);
> + this_cpu_write(seed, s);
> +
> + return s & (range - 1);

This is fragile, better to take a number of bits as argument.

> +}
> +
> static void cna_init_node(struct mcs_spinlock *node)
> {
> struct cna_node *cn = CNA_NODE(node);
> @@ -140,7 +168,13 @@ static inline void cna_pass_mcs_lock(struct mcs_spinlock *node,
> u64 *var = &next->locked;
> u64 val = 1;
>
> - succ = find_successor(node);
> + /*
> + * Try to pass the lock to a thread running on the same node.
> + * For long-term fairness, search for such a thread with high
> + * probability rather than always.
> + */
> + if (probably(INTRA_NODE_HANDOFF_PROB_ARG))
> + succ = find_successor(node);
>
> if (succ) {
> var = &succ->mcs.locked;

And this is where that tertiary condition comes from.. I think.