Whamcloud - gitweb
LU-12931 libcfs: skip cfs_time_seconds() indirection
[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  * GPL HEADER END
17  */
18 /*
19  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
20  *
21  * Copyright (c) 2012, 2017, Intel Corporation.
22  */
23 /*
24  * This file is part of Lustre, http://www.lustre.org/
25  * Lustre is a trademark of Sun Microsystems, Inc.
26  *
27  * libcfs/include/libcfs/libcfs_cpu.h
28  *
29  * CPU partition
30  *   . CPU partition is virtual processing unit
31  *
32  *   . CPU partition can present 1-N cores, or 1-N NUMA nodes,
33  *     in other words, CPU partition is a processors pool.
34  *
35  * CPU Partition Table (CPT)
36  *   . a set of CPU partitions
37  *
38  *   . There are two modes for CPT: CFS_CPU_MODE_NUMA and CFS_CPU_MODE_SMP
39  *
40  *   . User can specify total number of CPU partitions while creating a
41  *     CPT, ID of CPU partition is always start from 0.
42  *
43  *     Example: if there are 8 cores on the system, while creating a CPT
44  *     with cpu_npartitions=4:
45  *              core[0, 1] = partition[0], core[2, 3] = partition[1]
46  *              core[4, 5] = partition[2], core[6, 7] = partition[3]
47  *
48  *          cpu_npartitions=1:
49  *              core[0, 1, ... 7] = partition[0]
50  *
51  *   . User can also specify CPU partitions by string pattern
52  *
53  *     Examples: cpu_partitions="0[0,1], 1[2,3]"
54  *               cpu_partitions="N 0[0-3], 1[4-8]"
55  *
56  *     The first character "N" means following numbers are numa ID
57  *
58  *   . NUMA allocators, CPU affinity threads are built over CPU partitions,
59  *     instead of HW CPUs or HW nodes.
60  *
61  *   . By default, Lustre modules should refer to the global cfs_cpt_tab,
62  *     instead of accessing HW CPUs directly, so concurrency of Lustre can be
63  *     configured by cpu_npartitions of the global cfs_cpt_tab
64  *
65  *   . If cpu_npartitions=1(all CPUs in one pool), lustre should work the
66  *     same way as 2.2 or earlier versions
67  *
68  * Author: liang@whamcloud.com
69  */
70
71 #ifndef __LIBCFS_CPU_H__
72 #define __LIBCFS_CPU_H__
73
74 #include <linux/cpu.h>
75 #include <linux/cpuset.h>
76 #include <linux/slab.h>
77 #include <linux/topology.h>
78 #include <linux/version.h>
79 #include <linux/vmalloc.h>
80
81 #include <libcfs/linux/linux-cpu.h>
82
83 /* any CPU partition */
84 #define CFS_CPT_ANY             (-1)
85
86 struct cfs_cpt_table;
87
88 #ifdef CONFIG_SMP
89 extern struct cfs_cpt_table     *cfs_cpt_tab;
90
91 /**
92  * destroy a CPU partition table
93  */
94 void cfs_cpt_table_free(struct cfs_cpt_table *cptab);
95 /**
96  * create a cfs_cpt_table with \a ncpt number of partitions
97  */
98 struct cfs_cpt_table *cfs_cpt_table_alloc(int ncpt);
99 /**
100  * print string information of cpt-table
101  */
102 int cfs_cpt_table_print(struct cfs_cpt_table *cptab, char *buf, int len);
103 /**
104  * print distance information of cpt-table
105  */
106 int cfs_cpt_distance_print(struct cfs_cpt_table *cptab, char *buf, int len);
107 /**
108  * return total number of CPU partitions in \a cptab
109  */
110 int cfs_cpt_number(struct cfs_cpt_table *cptab);
111 /**
112  * return number of HW cores or hyper-threadings in a CPU partition \a cpt
113  */
114 int cfs_cpt_weight(struct cfs_cpt_table *cptab, int cpt);
115 /**
116  * is there any online CPU in CPU partition \a cpt
117  */
118 int cfs_cpt_online(struct cfs_cpt_table *cptab, int cpt);
119 /**
120  * return cpumask of CPU partition \a cpt
121  */
122 cpumask_var_t *cfs_cpt_cpumask(struct cfs_cpt_table *cptab, int cpt);
123 /**
124  * return nodemask of CPU partition \a cpt
125  */
126 nodemask_t *cfs_cpt_nodemask(struct cfs_cpt_table *cptab, int cpt);
127 /**
128  * shadow current HW processor ID to CPU-partition ID of \a cptab
129  */
130 int cfs_cpt_current(struct cfs_cpt_table *cptab, int remap);
131 /**
132  * shadow HW processor ID \a CPU to CPU-partition ID by \a cptab
133  */
134 int cfs_cpt_of_cpu(struct cfs_cpt_table *cptab, int cpu);
135 /**
136  * shadow HW node ID \a NODE to CPU-partition ID by \a cptab
137  */
138 int cfs_cpt_of_node(struct cfs_cpt_table *cptab, int node);
139 /**
140  * NUMA distance between \a cpt1 and \a cpt2 in \a cptab
141  */
142 unsigned int cfs_cpt_distance(struct cfs_cpt_table *cptab, int cpt1, int cpt2);
143 /**
144  * bind current thread on a CPU-partition \a cpt of \a cptab
145  */
146 int cfs_cpt_bind(struct cfs_cpt_table *cptab, int cpt);
147 /**
148  * add \a cpu to CPU partition @cpt of \a cptab, return 1 for success,
149  * otherwise 0 is returned
150  */
151 int cfs_cpt_set_cpu(struct cfs_cpt_table *cptab, int cpt, int cpu);
152 /**
153  * remove \a cpu from CPU partition \a cpt of \a cptab
154  */
155 void cfs_cpt_unset_cpu(struct cfs_cpt_table *cptab, int cpt, int cpu);
156 /**
157  * add all cpus in \a mask to CPU partition \a cpt
158  * return 1 if successfully set all CPUs, otherwise return 0
159  */
160 int cfs_cpt_set_cpumask(struct cfs_cpt_table *cptab, int cpt,
161                         const cpumask_t *mask);
162 /**
163  * remove all cpus in \a mask from CPU partition \a cpt
164  */
165 void cfs_cpt_unset_cpumask(struct cfs_cpt_table *cptab, int cpt,
166                            const cpumask_t *mask);
167 /**
168  * add all cpus in NUMA node \a node to CPU partition \a cpt
169  * return 1 if successfully set all CPUs, otherwise return 0
170  */
171 int cfs_cpt_set_node(struct cfs_cpt_table *cptab, int cpt, int node);
172 /**
173  * remove all cpus in NUMA node \a node from CPU partition \a cpt
174  */
175 void cfs_cpt_unset_node(struct cfs_cpt_table *cptab, int cpt, int node);
176 /**
177  * add all cpus in node mask \a mask to CPU partition \a cpt
178  * return 1 if successfully set all CPUs, otherwise return 0
179  */
180 int cfs_cpt_set_nodemask(struct cfs_cpt_table *cptab, int cpt,
181                          const nodemask_t *mask);
182 /**
183  * remove all cpus in node mask \a mask from CPU partition \a cpt
184  */
185 void cfs_cpt_unset_nodemask(struct cfs_cpt_table *cptab, int cpt,
186                             const nodemask_t *mask);
187 /**
188  * convert partition id \a cpt to numa node id, if there are more than one
189  * nodes in this partition, it might return a different node id each time.
190  */
191 int cfs_cpt_spread_node(struct cfs_cpt_table *cptab, int cpt);
192
193 int cfs_cpu_init(void);
194 void cfs_cpu_fini(void);
195
196 #else /* !CONFIG_SMP */
197
198 #define cfs_cpt_tab ((struct cfs_cpt_table *)NULL)
199
200 static inline void cfs_cpt_table_free(struct cfs_cpt_table *cptab)
201 {
202 }
203
204 static inline struct cfs_cpt_table *cfs_cpt_table_alloc(int ncpt)
205 {
206         return NULL;
207 }
208
209 static inline int cfs_cpt_table_print(struct cfs_cpt_table *cptab,
210                                       char *buf, int len)
211 {
212         int rc;
213
214         rc = snprintf(buf, len, "0\t: 0\n");
215         len -= rc;
216         if (len <= 0)
217                 return -EFBIG;
218
219         return rc;
220 }
221
222 static inline int cfs_cpt_distance_print(struct cfs_cpt_table *cptab,
223                                          char *buf, int len)
224 {
225         int rc;
226
227         rc = snprintf(buf, len, "0\t: 0:1\n");
228         len -= rc;
229         if (len <= 0)
230                 return -EFBIG;
231
232         return rc;
233 }
234
235 static inline cpumask_var_t *cfs_cpt_cpumask(struct cfs_cpt_table *cptab,
236                                              int cpt)
237 {
238         return (cpumask_var_t *) cpu_online_mask;
239 }
240
241 static inline int cfs_cpt_number(struct cfs_cpt_table *cptab)
242 {
243         return 1;
244 }
245
246 static inline int cfs_cpt_weight(struct cfs_cpt_table *cptab, int cpt)
247 {
248         return 1;
249 }
250
251 static inline nodemask_t *cfs_cpt_nodemask(struct cfs_cpt_table *cptab,
252                                            int cpt)
253 {
254         return &node_online_map;
255 }
256
257 static inline unsigned int cfs_cpt_distance(struct cfs_cpt_table *cptab,
258                                             int cpt1, int cpt2)
259 {
260         return 1;
261 }
262
263 static inline int cfs_cpt_set_node(struct cfs_cpt_table *cptab, int cpt,
264                                    int node)
265 {
266         return 1;
267 }
268
269 static inline int cfs_cpt_spread_node(struct cfs_cpt_table *cptab, int cpt)
270 {
271         return 0;
272 }
273
274 static inline int cfs_cpt_current(struct cfs_cpt_table *cptab, int remap)
275 {
276         return 0;
277 }
278
279 static inline int cfs_cpt_of_node(struct cfs_cpt_table *cptab, int node)
280 {
281         return 0;
282 }
283
284 static inline int cfs_cpt_bind(struct cfs_cpt_table *cptab, int cpt)
285 {
286         return 0;
287 }
288
289 static inline int cfs_cpu_init(void)
290 {
291         return 0;
292 }
293
294 static inline void cfs_cpu_fini(void)
295 {
296 }
297
298 #endif /* CONFIG_SMP */
299
300 static inline
301 struct workqueue_struct *cfs_cpt_bind_workqueue(const char *wq_name,
302                                                 struct cfs_cpt_table *tbl,
303                                                 int flags, int cpt, int nthrs)
304 {
305         cpumask_var_t *mask = cfs_cpt_cpumask(tbl, cpt);
306         struct workqueue_attrs attrs = { };
307         struct workqueue_struct *wq;
308
309         wq = alloc_workqueue(wq_name, WQ_UNBOUND | flags, nthrs);
310         if (!wq)
311                 return ERR_PTR(-ENOMEM);
312
313         if (mask && alloc_cpumask_var(&attrs.cpumask, GFP_KERNEL)) {
314                 cpumask_copy(attrs.cpumask, *mask);
315                 cpus_read_lock();
316                 cfs_apply_workqueue_attrs(wq, &attrs);
317                 cpus_read_unlock();
318                 free_cpumask_var(attrs.cpumask);
319         }
320
321         return wq;
322 }
323
324 /*
325  * allocate per-cpu-partition data, returned value is an array of pointers,
326  * variable can be indexed by CPU ID.
327  *      cptab != NULL: size of array is number of CPU partitions
328  *      cptab == NULL: size of array is number of HW cores
329  */
330 void *cfs_percpt_alloc(struct cfs_cpt_table *cptab, unsigned int size);
331 /*
332  * destroy per-cpu-partition variable
333  */
334 void cfs_percpt_free(void *vars);
335 int cfs_percpt_number(void *vars);
336
337 #define cfs_percpt_for_each(var, i, vars)               \
338         for (i = 0; i < cfs_percpt_number(vars) &&      \
339                 ((var) = (vars)[i]) != NULL; i++)
340
341 /*
342  * percpu partition lock
343  *
344  * There are some use-cases like this in Lustre:
345  * . each CPU partition has it's own private data which is frequently changed,
346  *   and mostly by the local CPU partition.
347  * . all CPU partitions share some global data, these data are rarely changed.
348  *
349  * LNet is typical example.
350  * CPU partition lock is designed for this kind of use-cases:
351  * . each CPU partition has it's own private lock
352  * . change on private data just needs to take the private lock
353  * . read on shared data just needs to take _any_ of private locks
354  * . change on shared data needs to take _all_ private locks,
355  *   which is slow and should be really rare.
356  */
357 enum {
358         CFS_PERCPT_LOCK_EX      = -1,   /* negative */
359 };
360
361 struct cfs_percpt_lock {
362         /* cpu-partition-table for this lock */
363         struct cfs_cpt_table     *pcl_cptab;
364         /* exclusively locked */
365         unsigned int              pcl_locked;
366         /* private lock table */
367         spinlock_t              **pcl_locks;
368 };
369
370 /* return number of private locks */
371 #define cfs_percpt_lock_num(pcl)        cfs_cpt_number(pcl->pcl_cptab)
372
373 /*
374  * create a cpu-partition lock based on CPU partition table \a cptab,
375  * each private lock has extra \a psize bytes padding data
376  */
377 struct cfs_percpt_lock *cfs_percpt_lock_create(struct cfs_cpt_table *cptab,
378                                                struct lock_class_key *keys);
379 /* destroy a cpu-partition lock */
380 void cfs_percpt_lock_free(struct cfs_percpt_lock *pcl);
381
382 /* lock private lock \a index of \a pcl */
383 void cfs_percpt_lock(struct cfs_percpt_lock *pcl, int index);
384
385 /* unlock private lock \a index of \a pcl */
386 void cfs_percpt_unlock(struct cfs_percpt_lock *pcl, int index);
387
388 #define CFS_PERCPT_LOCK_KEYS    256
389
390 /* NB: don't allocate keys dynamically, lockdep needs them to be in ".data" */
391 #define cfs_percpt_lock_alloc(cptab)                                    \
392 ({                                                                      \
393         static struct lock_class_key ___keys[CFS_PERCPT_LOCK_KEYS];     \
394         struct cfs_percpt_lock *___lk;                                  \
395                                                                         \
396         if (cfs_cpt_number(cptab) > CFS_PERCPT_LOCK_KEYS)               \
397                 ___lk = cfs_percpt_lock_create(cptab, NULL);            \
398         else                                                            \
399                 ___lk = cfs_percpt_lock_create(cptab, ___keys);         \
400         ___lk;                                                          \
401 })
402
403 /**
404  * allocate \a nr_bytes of physical memory from a contiguous region with the
405  * properties of \a flags which are bound to the partition id \a cpt. This
406  * function should only be used for the case when only a few pages of memory
407  * are need.
408  */
409 static inline void *
410 cfs_cpt_malloc(struct cfs_cpt_table *cptab, int cpt, size_t nr_bytes,
411                gfp_t flags)
412 {
413         return kmalloc_node(nr_bytes, flags,
414                             cfs_cpt_spread_node(cptab, cpt));
415 }
416
417 /**
418  * allocate \a nr_bytes of virtually contiguous memory that is bound to the
419  * partition id \a cpt.
420  */
421 static inline void *
422 cfs_cpt_vzalloc(struct cfs_cpt_table *cptab, int cpt, size_t nr_bytes)
423 {
424         /* vzalloc_node() sets __GFP_FS by default but no current Kernel
425          * exported entry-point allows for both a NUMA node specification
426          * and a custom allocation flags mask. This may be an issue since
427          * __GFP_FS usage can cause some deadlock situations in our code,
428          * like when memory reclaim started, within the same context of a
429          * thread doing FS operations, that can also attempt conflicting FS
430          * operations, ...
431          */
432         return vzalloc_node(nr_bytes, cfs_cpt_spread_node(cptab, cpt));
433 }
434
435 /**
436  * allocate a single page of memory with the properties of \a flags were
437  * that page is bound to the partition id \a cpt.
438  */
439 static inline struct page *
440 cfs_page_cpt_alloc(struct cfs_cpt_table *cptab, int cpt, gfp_t flags)
441 {
442         return alloc_pages_node(cfs_cpt_spread_node(cptab, cpt), flags, 0);
443 }
444
445 /**
446  * allocate a chunck of memory from a memory pool that is bound to the
447  * partition id \a cpt with the properites of \a flags.
448  */
449 static inline void *
450 cfs_mem_cache_cpt_alloc(struct kmem_cache *cachep, struct cfs_cpt_table *cptab,
451                         int cpt, gfp_t flags)
452 {
453         return kmem_cache_alloc_node(cachep, flags,
454                                      cfs_cpt_spread_node(cptab, cpt));
455 }
456
457 /**
458  * iterate over all CPU partitions in \a cptab
459  */
460 #define cfs_cpt_for_each(i, cptab)      \
461         for (i = 0; i < cfs_cpt_number(cptab); i++)
462
463 #endif /* __LIBCFS_CPU_H__ */