Skip to content

Commit

Permalink
sched: add sched_numa_find_nth_cpu()
Browse files Browse the repository at this point in the history
The function finds Nth set CPU in a given cpumask starting from a given
node.

Leveraging the fact that each hop in sched_domains_numa_masks includes the
same or greater number of CPUs than the previous one, we can use binary
search on hops instead of linear walk, which makes the overall complexity
of O(log n) in terms of number of cpumask_weight() calls.

Signed-off-by: Yury Norov <[email protected]>
Acked-by: Tariq Toukan <[email protected]>
Reviewed-by: Jacob Keller <[email protected]>
Reviewed-by: Peter Lafreniere <[email protected]>
Signed-off-by: Jakub Kicinski <[email protected]>
  • Loading branch information
YuryNorov authored and kuba-moo committed Feb 8, 2023
1 parent 62f4386 commit cd7f553
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 0 deletions.
8 changes: 8 additions & 0 deletions include/linux/topology.h
Original file line number Diff line number Diff line change
Expand Up @@ -245,5 +245,13 @@ static inline const struct cpumask *cpu_cpu_mask(int cpu)
return cpumask_of_node(cpu_to_node(cpu));
}

#ifdef CONFIG_NUMA
int sched_numa_find_nth_cpu(const struct cpumask *cpus, int cpu, int node);
#else
static __always_inline int sched_numa_find_nth_cpu(const struct cpumask *cpus, int cpu, int node)
{
return cpumask_nth(cpu, cpus);
}
#endif /* CONFIG_NUMA */

#endif /* _LINUX_TOPOLOGY_H */
57 changes: 57 additions & 0 deletions kernel/sched/topology.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
* Scheduler topology setup/handling methods
*/

#include <linux/bsearch.h>

DEFINE_MUTEX(sched_domains_mutex);

/* Protected by sched_domains_mutex: */
Expand Down Expand Up @@ -2067,6 +2069,61 @@ int sched_numa_find_closest(const struct cpumask *cpus, int cpu)
return found;
}

struct __cmp_key {
const struct cpumask *cpus;
struct cpumask ***masks;
int node;
int cpu;
int w;
};

static int hop_cmp(const void *a, const void *b)
{
struct cpumask **prev_hop = *((struct cpumask ***)b - 1);
struct cpumask **cur_hop = *(struct cpumask ***)b;
struct __cmp_key *k = (struct __cmp_key *)a;

if (cpumask_weight_and(k->cpus, cur_hop[k->node]) <= k->cpu)
return 1;

k->w = (b == k->masks) ? 0 : cpumask_weight_and(k->cpus, prev_hop[k->node]);
if (k->w <= k->cpu)
return 0;

return -1;
}

/*
* sched_numa_find_nth_cpu() - given the NUMA topology, find the Nth next cpu
* closest to @cpu from @cpumask.
* cpumask: cpumask to find a cpu from
* cpu: Nth cpu to find
*
* returns: cpu, or nr_cpu_ids when nothing found.
*/
int sched_numa_find_nth_cpu(const struct cpumask *cpus, int cpu, int node)
{
struct __cmp_key k = { .cpus = cpus, .node = node, .cpu = cpu };
struct cpumask ***hop_masks;
int hop, ret = nr_cpu_ids;

rcu_read_lock();

k.masks = rcu_dereference(sched_domains_numa_masks);
if (!k.masks)
goto unlock;

hop_masks = bsearch(&k, k.masks, sched_domains_numa_levels, sizeof(k.masks[0]), hop_cmp);
hop = hop_masks - k.masks;

ret = hop ?
cpumask_nth_and_andnot(cpu - k.w, cpus, k.masks[hop][node], k.masks[hop-1][node]) :
cpumask_nth_and(cpu, cpus, k.masks[0][node]);
unlock:
rcu_read_unlock();
return ret;
}
EXPORT_SYMBOL_GPL(sched_numa_find_nth_cpu);
#endif /* CONFIG_NUMA */

static int __sdt_alloc(const struct cpumask *cpu_map)
Expand Down

0 comments on commit cd7f553

Please sign in to comment.