Whamcloud - gitweb
LU-7734 lnet: NUMA support
[fs/lustre-release.git] / libcfs / include / libcfs / libcfs_cpu.h
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 021110-1307, USA
20  *
21  * GPL HEADER END
22  */
23 /*
24  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
25  *
26  * Copyright (c) 2012, 2015, Intel Corporation.
27  */
28 /*
29  * This file is part of Lustre, http://www.lustre.org/
30  * Lustre is a trademark of Sun Microsystems, Inc.
31  *
32  * libcfs/include/libcfs/libcfs_cpu.h
33  *
34  * CPU partition
35  *   . CPU partition is virtual processing unit
36  *
37  *   . CPU partition can present 1-N cores, or 1-N NUMA nodes,
38  *     in other words, CPU partition is a processors pool.
39  *
40  * CPU Partition Table (CPT)
41  *   . a set of CPU partitions
42  *
43  *   . There are two modes for CPT: CFS_CPU_MODE_NUMA and CFS_CPU_MODE_SMP
44  *
45  *   . User can specify total number of CPU partitions while creating a
46  *     CPT, ID of CPU partition is always start from 0.
47  *
48  *     Example: if there are 8 cores on the system, while creating a CPT
49  *     with cpu_npartitions=4:
50  *              core[0, 1] = partition[0], core[2, 3] = partition[1]
51  *              core[4, 5] = partition[2], core[6, 7] = partition[3]
52  *
53  *          cpu_npartitions=1:
54  *              core[0, 1, ... 7] = partition[0]
55  *
56  *   . User can also specify CPU partitions by string pattern
57  *
58  *     Examples: cpu_partitions="0[0,1], 1[2,3]"
59  *               cpu_partitions="N 0[0-3], 1[4-8]"
60  *
61  *     The first character "N" means following numbers are numa ID
62  *
63  *   . NUMA allocators, CPU affinity threads are built over CPU partitions,
64  *     instead of HW CPUs or HW nodes.
65  *
66  *   . By default, Lustre modules should refer to the global cfs_cpt_table,
67  *     instead of accessing HW CPUs directly, so concurrency of Lustre can be
68  *     configured by cpu_npartitions of the global cfs_cpt_table
69  *
70  *   . If cpu_npartitions=1(all CPUs in one pool), lustre should work the
71  *     same way as 2.2 or earlier versions
72  *
73  * Author: liang@whamcloud.com
74  */
75
76 #ifndef __LIBCFS_CPU_H__
77 #define __LIBCFS_CPU_H__
78
79 #ifndef HAVE_LIBCFS_CPT
80
81 struct cfs_cpt_table {
82         /* # of CPU partitions */
83         int                     ctb_nparts;
84         /* cpu mask */
85         cpumask_t               ctb_mask;
86         /* node mask */
87         nodemask_t              ctb_nodemask;
88         /* version */
89         __u64                   ctb_version;
90 };
91
92 #endif /* !HAVE_LIBCFS_CPT */
93
94 /* any CPU partition */
95 #define CFS_CPT_ANY             (-1)
96
97 extern struct cfs_cpt_table     *cfs_cpt_table;
98
99 /**
100  * destroy a CPU partition table
101  */
102 void cfs_cpt_table_free(struct cfs_cpt_table *cptab);
103 /**
104  * create a cfs_cpt_table with \a ncpt number of partitions
105  */
106 struct cfs_cpt_table *cfs_cpt_table_alloc(unsigned int ncpt);
107 /**
108  * print string information of cpt-table
109  */
110 int cfs_cpt_table_print(struct cfs_cpt_table *cptab, char *buf, int len);
111 /**
112  * print distance information of cpt-table
113  */
114 int cfs_cpt_distance_print(struct cfs_cpt_table *cptab, char *buf, int len);
115 /**
116  * return total number of CPU partitions in \a cptab
117  */
118 int
119 cfs_cpt_number(struct cfs_cpt_table *cptab);
120 /**
121  * return number of HW cores or hypter-threadings in a CPU partition \a cpt
122  */
123 int cfs_cpt_weight(struct cfs_cpt_table *cptab, int cpt);
124 /**
125  * is there any online CPU in CPU partition \a cpt
126  */
127 int cfs_cpt_online(struct cfs_cpt_table *cptab, int cpt);
128 /**
129  * return cpumask of CPU partition \a cpt
130  */
131 cpumask_t *cfs_cpt_cpumask(struct cfs_cpt_table *cptab, int cpt);
132 /**
133  * return nodemask of CPU partition \a cpt
134  */
135 nodemask_t *cfs_cpt_nodemask(struct cfs_cpt_table *cptab, int cpt);
136 /**
137  * shadow current HW processor ID to CPU-partition ID of \a cptab
138  */
139 int cfs_cpt_current(struct cfs_cpt_table *cptab, int remap);
140 /**
141  * shadow HW processor ID \a CPU to CPU-partition ID by \a cptab
142  */
143 int cfs_cpt_of_cpu(struct cfs_cpt_table *cptab, int cpu);
144 /**
145  * shadow HW node ID \a NODE to CPU-partition ID by \a cptab
146  */
147 int cfs_cpt_of_node(struct cfs_cpt_table *cptab, int node);
148 /**
149  * NUMA distance between \a cpt1 and \a cpt2 in \a cptab
150  */
151 unsigned cfs_cpt_distance(struct cfs_cpt_table *cptab, int cpt1, int cpt2);
152 /**
153  * bind current thread on a CPU-partition \a cpt of \a cptab
154  */
155 int cfs_cpt_bind(struct cfs_cpt_table *cptab, int cpt);
156 /**
157  * add \a cpu to CPU partion @cpt of \a cptab, return 1 for success,
158  * otherwise 0 is returned
159  */
160 int cfs_cpt_set_cpu(struct cfs_cpt_table *cptab, int cpt, int cpu);
161 /**
162  * remove \a cpu from CPU partition \a cpt of \a cptab
163  */
164 void cfs_cpt_unset_cpu(struct cfs_cpt_table *cptab, int cpt, int cpu);
165 /**
166  * add all cpus in \a mask to CPU partition \a cpt
167  * return 1 if successfully set all CPUs, otherwise return 0
168  */
169 int cfs_cpt_set_cpumask(struct cfs_cpt_table *cptab,
170                         int cpt, const cpumask_t *mask);
171 /**
172  * remove all cpus in \a mask from CPU partition \a cpt
173  */
174 void cfs_cpt_unset_cpumask(struct cfs_cpt_table *cptab,
175                            int cpt, const cpumask_t *mask);
176 /**
177  * add all cpus in NUMA node \a node to CPU partition \a cpt
178  * return 1 if successfully set all CPUs, otherwise return 0
179  */
180 int cfs_cpt_set_node(struct cfs_cpt_table *cptab, int cpt, int node);
181 /**
182  * remove all cpus in NUMA node \a node from CPU partition \a cpt
183  */
184 void cfs_cpt_unset_node(struct cfs_cpt_table *cptab, int cpt, int node);
185
186 /**
187  * add all cpus in node mask \a mask to CPU partition \a cpt
188  * return 1 if successfully set all CPUs, otherwise return 0
189  */
190 int cfs_cpt_set_nodemask(struct cfs_cpt_table *cptab,
191                          int cpt, nodemask_t *mask);
192 /**
193  * remove all cpus in node mask \a mask from CPU partition \a cpt
194  */
195 void cfs_cpt_unset_nodemask(struct cfs_cpt_table *cptab,
196                             int cpt, nodemask_t *mask);
197 /**
198  * convert partition id \a cpt to numa node id, if there are more than one
199  * nodes in this partition, it might return a different node id each time.
200  */
201 int cfs_cpt_spread_node(struct cfs_cpt_table *cptab, int cpt);
202
203 /**
204  * return number of HTs in the same core of \a cpu
205  */
206 int cfs_cpu_ht_nsiblings(int cpu);
207
208 /*
209  * allocate per-cpu-partition data, returned value is an array of pointers,
210  * variable can be indexed by CPU ID.
211  *      cptab != NULL: size of array is number of CPU partitions
212  *      cptab == NULL: size of array is number of HW cores
213  */
214 void *cfs_percpt_alloc(struct cfs_cpt_table *cptab, unsigned int size);
215 /*
216  * destory per-cpu-partition variable
217  */
218 void  cfs_percpt_free(void *vars);
219 int   cfs_percpt_number(void *vars);
220
221 #define cfs_percpt_for_each(var, i, vars)               \
222         for (i = 0; i < cfs_percpt_number(vars) &&      \
223                 ((var) = (vars)[i]) != NULL; i++)
224
225 /*
226  * percpu partition lock
227  *
228  * There are some use-cases like this in Lustre:
229  * . each CPU partition has it's own private data which is frequently changed,
230  *   and mostly by the local CPU partition.
231  * . all CPU partitions share some global data, these data are rarely changed.
232  *
233  * LNet is typical example.
234  * CPU partition lock is designed for this kind of use-cases:
235  * . each CPU partition has it's own private lock
236  * . change on private data just needs to take the private lock
237  * . read on shared data just needs to take _any_ of private locks
238  * . change on shared data needs to take _all_ private locks,
239  *   which is slow and should be really rare.
240  */
241 enum {
242         CFS_PERCPT_LOCK_EX      = -1,   /* negative */
243 };
244
245 struct cfs_percpt_lock {
246         /* cpu-partition-table for this lock */
247         struct cfs_cpt_table     *pcl_cptab;
248         /* exclusively locked */
249         unsigned int              pcl_locked;
250         /* private lock table */
251         spinlock_t              **pcl_locks;
252 };
253
254 /* return number of private locks */
255 #define cfs_percpt_lock_num(pcl)        cfs_cpt_number(pcl->pcl_cptab)
256
257 /*
258  * create a cpu-partition lock based on CPU partition table \a cptab,
259  * each private lock has extra \a psize bytes padding data
260  */
261 struct cfs_percpt_lock *cfs_percpt_lock_create(struct cfs_cpt_table *cptab,
262                                                struct lock_class_key *keys);
263 /* destroy a cpu-partition lock */
264 void cfs_percpt_lock_free(struct cfs_percpt_lock *pcl);
265
266 /* lock private lock \a index of \a pcl */
267 void cfs_percpt_lock(struct cfs_percpt_lock *pcl, int index);
268 /* unlock private lock \a index of \a pcl */
269 void cfs_percpt_unlock(struct cfs_percpt_lock *pcl, int index);
270
271 #define CFS_PERCPT_LOCK_KEYS   256
272
273 /* NB: don't allocate keys dynamically, lockdep needs them to be in ".data" */
274 #define cfs_percpt_lock_alloc(cptab)                                    \
275 ({                                                                      \
276         static struct lock_class_key  ___keys[CFS_PERCPT_LOCK_KEYS];    \
277         struct cfs_percpt_lock       *___lk;                            \
278                                                                         \
279         if (cfs_cpt_number(cptab) > CFS_PERCPT_LOCK_KEYS)               \
280                 ___lk = cfs_percpt_lock_create(cptab, NULL);            \
281         else                                                            \
282                 ___lk = cfs_percpt_lock_create(cptab, ___keys);         \
283         ___lk;                                                          \
284 })
285
286 /**
287  * allocate \a nr_bytes of physical memory from a contiguous region with the
288  * properties of \a flags which are bound to the partition id \a cpt. This
289  * function should only be used for the case when only a few pages of memory
290  * are need.
291  */
292 static inline void *
293 cfs_cpt_malloc(struct cfs_cpt_table *cptab, int cpt, size_t nr_bytes,
294                gfp_t flags)
295 {
296         return kmalloc_node(nr_bytes, flags,
297                             cfs_cpt_spread_node(cptab, cpt));
298 }
299
300 /**
301  * allocate \a nr_bytes of virtually contiguous memory that is bound to the
302  * partition id \a cpt.
303  */
304 static inline void *
305 cfs_cpt_vzalloc(struct cfs_cpt_table *cptab, int cpt, size_t nr_bytes)
306 {
307         /* vzalloc_node() sets __GFP_FS by default but no current Kernel
308          * exported entry-point allows for both a NUMA node specification
309          * and a custom allocation flags mask. This may be an issue since
310          * __GFP_FS usage can cause some deadlock situations in our code,
311          * like when memory reclaim started, within the same context of a
312          * thread doing FS operations, that can also attempt conflicting FS
313          * operations, ...
314          */
315         return vzalloc_node(nr_bytes, cfs_cpt_spread_node(cptab, cpt));
316 }
317
318 /**
319  * allocate a single page of memory with the properties of \a flags were
320  * that page is bound to the partition id \a cpt.
321  */
322 static inline struct page *
323 cfs_page_cpt_alloc(struct cfs_cpt_table *cptab, int cpt, gfp_t flags)
324 {
325         return alloc_pages_node(cfs_cpt_spread_node(cptab, cpt), flags, 0);
326 }
327
328 /**
329  * allocate a chunck of memory from a memory pool that is bound to the
330  * partition id \a cpt with the properites of \a flags.
331  */
332 static inline void *
333 cfs_mem_cache_cpt_alloc(struct kmem_cache *cachep, struct cfs_cpt_table *cptab,
334                         int cpt, gfp_t flags)
335 {
336         return kmem_cache_alloc_node(cachep, flags,
337                                      cfs_cpt_spread_node(cptab, cpt));
338 }
339
340 /**
341  * iterate over all CPU partitions in \a cptab
342  */
343 #define cfs_cpt_for_each(i, cptab)      \
344         for (i = 0; i < cfs_cpt_number(cptab); i++)
345
346 #ifndef __read_mostly
347 # define __read_mostly
348 #endif
349
350 #ifndef ____cacheline_aligned
351 #define ____cacheline_aligned
352 #endif
353
354 int  cfs_cpu_init(void);
355 void cfs_cpu_fini(void);
356
357 #endif /* __LIBCFS_CPU_H__ */