Skip to content

Commit cd7f553

Browse files
YuryNorovkuba-moo
authored andcommitted
sched: add sched_numa_find_nth_cpu()
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]>
1 parent 62f4386 commit cd7f553

File tree

2 files changed

+65
-0
lines changed

2 files changed

+65
-0
lines changed

include/linux/topology.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,5 +245,13 @@ static inline const struct cpumask *cpu_cpu_mask(int cpu)
245245
return cpumask_of_node(cpu_to_node(cpu));
246246
}
247247

248+
#ifdef CONFIG_NUMA
249+
int sched_numa_find_nth_cpu(const struct cpumask *cpus, int cpu, int node);
250+
#else
251+
static __always_inline int sched_numa_find_nth_cpu(const struct cpumask *cpus, int cpu, int node)
252+
{
253+
return cpumask_nth(cpu, cpus);
254+
}
255+
#endif /* CONFIG_NUMA */
248256

249257
#endif /* _LINUX_TOPOLOGY_H */

kernel/sched/topology.c

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
* Scheduler topology setup/handling methods
44
*/
55

6+
#include <linux/bsearch.h>
7+
68
DEFINE_MUTEX(sched_domains_mutex);
79

810
/* Protected by sched_domains_mutex: */
@@ -2067,6 +2069,61 @@ int sched_numa_find_closest(const struct cpumask *cpus, int cpu)
20672069
return found;
20682070
}
20692071

2072+
struct __cmp_key {
2073+
const struct cpumask *cpus;
2074+
struct cpumask ***masks;
2075+
int node;
2076+
int cpu;
2077+
int w;
2078+
};
2079+
2080+
static int hop_cmp(const void *a, const void *b)
2081+
{
2082+
struct cpumask **prev_hop = *((struct cpumask ***)b - 1);
2083+
struct cpumask **cur_hop = *(struct cpumask ***)b;
2084+
struct __cmp_key *k = (struct __cmp_key *)a;
2085+
2086+
if (cpumask_weight_and(k->cpus, cur_hop[k->node]) <= k->cpu)
2087+
return 1;
2088+
2089+
k->w = (b == k->masks) ? 0 : cpumask_weight_and(k->cpus, prev_hop[k->node]);
2090+
if (k->w <= k->cpu)
2091+
return 0;
2092+
2093+
return -1;
2094+
}
2095+
2096+
/*
2097+
* sched_numa_find_nth_cpu() - given the NUMA topology, find the Nth next cpu
2098+
* closest to @cpu from @cpumask.
2099+
* cpumask: cpumask to find a cpu from
2100+
* cpu: Nth cpu to find
2101+
*
2102+
* returns: cpu, or nr_cpu_ids when nothing found.
2103+
*/
2104+
int sched_numa_find_nth_cpu(const struct cpumask *cpus, int cpu, int node)
2105+
{
2106+
struct __cmp_key k = { .cpus = cpus, .node = node, .cpu = cpu };
2107+
struct cpumask ***hop_masks;
2108+
int hop, ret = nr_cpu_ids;
2109+
2110+
rcu_read_lock();
2111+
2112+
k.masks = rcu_dereference(sched_domains_numa_masks);
2113+
if (!k.masks)
2114+
goto unlock;
2115+
2116+
hop_masks = bsearch(&k, k.masks, sched_domains_numa_levels, sizeof(k.masks[0]), hop_cmp);
2117+
hop = hop_masks - k.masks;
2118+
2119+
ret = hop ?
2120+
cpumask_nth_and_andnot(cpu - k.w, cpus, k.masks[hop][node], k.masks[hop-1][node]) :
2121+
cpumask_nth_and(cpu, cpus, k.masks[0][node]);
2122+
unlock:
2123+
rcu_read_unlock();
2124+
return ret;
2125+
}
2126+
EXPORT_SYMBOL_GPL(sched_numa_find_nth_cpu);
20702127
#endif /* CONFIG_NUMA */
20712128

20722129
static int __sdt_alloc(const struct cpumask *cpu_map)

0 commit comments

Comments
 (0)