Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/lib/cpumask.c
26131 views
1
// SPDX-License-Identifier: GPL-2.0
2
#include <linux/slab.h>
3
#include <linux/kernel.h>
4
#include <linux/bitops.h>
5
#include <linux/cpumask.h>
6
#include <linux/export.h>
7
#include <linux/memblock.h>
8
#include <linux/numa.h>
9
10
/* These are not inline because of header tangles. */
11
#ifdef CONFIG_CPUMASK_OFFSTACK
12
/**
13
* alloc_cpumask_var_node - allocate a struct cpumask on a given node
14
* @mask: pointer to cpumask_var_t where the cpumask is returned
15
* @flags: GFP_ flags
16
* @node: memory node from which to allocate or %NUMA_NO_NODE
17
*
18
* Only defined when CONFIG_CPUMASK_OFFSTACK=y, otherwise is
19
* a nop returning a constant 1 (in <linux/cpumask.h>).
20
*
21
* Return: TRUE if memory allocation succeeded, FALSE otherwise.
22
*
23
* In addition, mask will be NULL if this fails. Note that gcc is
24
* usually smart enough to know that mask can never be NULL if
25
* CONFIG_CPUMASK_OFFSTACK=n, so does code elimination in that case
26
* too.
27
*/
28
bool alloc_cpumask_var_node(cpumask_var_t *mask, gfp_t flags, int node)
29
{
30
*mask = kmalloc_node(cpumask_size(), flags, node);
31
32
#ifdef CONFIG_DEBUG_PER_CPU_MAPS
33
if (!*mask) {
34
printk(KERN_ERR "=> alloc_cpumask_var: failed!\n");
35
dump_stack();
36
}
37
#endif
38
39
return *mask != NULL;
40
}
41
EXPORT_SYMBOL(alloc_cpumask_var_node);
42
43
/**
44
* alloc_bootmem_cpumask_var - allocate a struct cpumask from the bootmem arena.
45
* @mask: pointer to cpumask_var_t where the cpumask is returned
46
*
47
* Only defined when CONFIG_CPUMASK_OFFSTACK=y, otherwise is
48
* a nop (in <linux/cpumask.h>).
49
* Either returns an allocated (zero-filled) cpumask, or causes the
50
* system to panic.
51
*/
52
void __init alloc_bootmem_cpumask_var(cpumask_var_t *mask)
53
{
54
*mask = memblock_alloc_or_panic(cpumask_size(), SMP_CACHE_BYTES);
55
}
56
57
/**
58
* free_cpumask_var - frees memory allocated for a struct cpumask.
59
* @mask: cpumask to free
60
*
61
* This is safe on a NULL mask.
62
*/
63
void free_cpumask_var(cpumask_var_t mask)
64
{
65
kfree(mask);
66
}
67
EXPORT_SYMBOL(free_cpumask_var);
68
69
/**
70
* free_bootmem_cpumask_var - frees result of alloc_bootmem_cpumask_var
71
* @mask: cpumask to free
72
*/
73
void __init free_bootmem_cpumask_var(cpumask_var_t mask)
74
{
75
memblock_free(mask, cpumask_size());
76
}
77
#endif
78
79
/**
80
* cpumask_local_spread - select the i'th cpu based on NUMA distances
81
* @i: index number
82
* @node: local numa_node
83
*
84
* Return: online CPU according to a numa aware policy; local cpus are returned
85
* first, followed by non-local ones, then it wraps around.
86
*
87
* For those who wants to enumerate all CPUs based on their NUMA distances,
88
* i.e. call this function in a loop, like:
89
*
90
* for (i = 0; i < num_online_cpus(); i++) {
91
* cpu = cpumask_local_spread(i, node);
92
* do_something(cpu);
93
* }
94
*
95
* There's a better alternative based on for_each()-like iterators:
96
*
97
* for_each_numa_hop_mask(mask, node) {
98
* for_each_cpu_andnot(cpu, mask, prev)
99
* do_something(cpu);
100
* prev = mask;
101
* }
102
*
103
* It's simpler and more verbose than above. Complexity of iterator-based
104
* enumeration is O(sched_domains_numa_levels * nr_cpu_ids), while
105
* cpumask_local_spread() when called for each cpu is
106
* O(sched_domains_numa_levels * nr_cpu_ids * log(nr_cpu_ids)).
107
*/
108
unsigned int cpumask_local_spread(unsigned int i, int node)
109
{
110
unsigned int cpu;
111
112
/* Wrap: we always want a cpu. */
113
i %= num_online_cpus();
114
115
cpu = sched_numa_find_nth_cpu(cpu_online_mask, i, node);
116
117
WARN_ON(cpu >= nr_cpu_ids);
118
return cpu;
119
}
120
EXPORT_SYMBOL(cpumask_local_spread);
121
122
static DEFINE_PER_CPU(int, distribute_cpu_mask_prev);
123
124
/**
125
* cpumask_any_and_distribute - Return an arbitrary cpu within src1p & src2p.
126
* @src1p: first &cpumask for intersection
127
* @src2p: second &cpumask for intersection
128
*
129
* Iterated calls using the same srcp1 and srcp2 will be distributed within
130
* their intersection.
131
*
132
* Return: >= nr_cpu_ids if the intersection is empty.
133
*/
134
unsigned int cpumask_any_and_distribute(const struct cpumask *src1p,
135
const struct cpumask *src2p)
136
{
137
unsigned int next, prev;
138
139
/* NOTE: our first selection will skip 0. */
140
prev = __this_cpu_read(distribute_cpu_mask_prev);
141
142
next = cpumask_next_and_wrap(prev, src1p, src2p);
143
if (next < nr_cpu_ids)
144
__this_cpu_write(distribute_cpu_mask_prev, next);
145
146
return next;
147
}
148
EXPORT_SYMBOL(cpumask_any_and_distribute);
149
150
/**
151
* cpumask_any_distribute - Return an arbitrary cpu from srcp
152
* @srcp: &cpumask for selection
153
*
154
* Return: >= nr_cpu_ids if the intersection is empty.
155
*/
156
unsigned int cpumask_any_distribute(const struct cpumask *srcp)
157
{
158
unsigned int next, prev;
159
160
/* NOTE: our first selection will skip 0. */
161
prev = __this_cpu_read(distribute_cpu_mask_prev);
162
next = cpumask_next_wrap(prev, srcp);
163
if (next < nr_cpu_ids)
164
__this_cpu_write(distribute_cpu_mask_prev, next);
165
166
return next;
167
}
168
EXPORT_SYMBOL(cpumask_any_distribute);
169
170