4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
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.
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).
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
24 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
26 * Copyright (c) 2012, 2015, Intel Corporation.
29 * This file is part of Lustre, http://www.lustre.org/
30 * Lustre is a trademark of Sun Microsystems, Inc.
32 * libcfs/include/libcfs/libcfs_cpu.h
35 * . CPU partition is virtual processing unit
37 * . CPU partition can present 1-N cores, or 1-N NUMA nodes,
38 * in other words, CPU partition is a processors pool.
40 * CPU Partition Table (CPT)
41 * . a set of CPU partitions
43 * . There are two modes for CPT: CFS_CPU_MODE_NUMA and CFS_CPU_MODE_SMP
45 * . User can specify total number of CPU partitions while creating a
46 * CPT, ID of CPU partition is always start from 0.
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]
54 * core[0, 1, ... 7] = partition[0]
56 * . User can also specify CPU partitions by string pattern
58 * Examples: cpu_partitions="0[0,1], 1[2,3]"
59 * cpu_partitions="N 0[0-3], 1[4-8]"
61 * The first character "N" means following numbers are numa ID
63 * . NUMA allocators, CPU affinity threads are built over CPU partitions,
64 * instead of HW CPUs or HW nodes.
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
70 * . If cpu_npartitions=1(all CPUs in one pool), lustre should work the
71 * same way as 2.2 or earlier versions
73 * Author: liang@whamcloud.com
76 #ifndef __LIBCFS_CPU_H__
77 #define __LIBCFS_CPU_H__
79 #ifndef HAVE_LIBCFS_CPT
81 struct cfs_cpt_table {
82 /* # of CPU partitions */
87 nodemask_t ctb_nodemask;
92 #endif /* !HAVE_LIBCFS_CPT */
94 /* any CPU partition */
95 #define CFS_CPT_ANY (-1)
97 extern struct cfs_cpt_table *cfs_cpt_table;
100 * destroy a CPU partition table
102 void cfs_cpt_table_free(struct cfs_cpt_table *cptab);
104 * create a cfs_cpt_table with \a ncpt number of partitions
106 struct cfs_cpt_table *cfs_cpt_table_alloc(unsigned int ncpt);
108 * print string information of cpt-table
110 int cfs_cpt_table_print(struct cfs_cpt_table *cptab, char *buf, int len);
112 * return total number of CPU partitions in \a cptab
115 cfs_cpt_number(struct cfs_cpt_table *cptab);
117 * return number of HW cores or hypter-threadings in a CPU partition \a cpt
119 int cfs_cpt_weight(struct cfs_cpt_table *cptab, int cpt);
121 * is there any online CPU in CPU partition \a cpt
123 int cfs_cpt_online(struct cfs_cpt_table *cptab, int cpt);
125 * return cpumask of CPU partition \a cpt
127 cpumask_t *cfs_cpt_cpumask(struct cfs_cpt_table *cptab, int cpt);
129 * return nodemask of CPU partition \a cpt
131 nodemask_t *cfs_cpt_nodemask(struct cfs_cpt_table *cptab, int cpt);
133 * shadow current HW processor ID to CPU-partition ID of \a cptab
135 int cfs_cpt_current(struct cfs_cpt_table *cptab, int remap);
137 * shadow HW processor ID \a CPU to CPU-partition ID by \a cptab
139 int cfs_cpt_of_cpu(struct cfs_cpt_table *cptab, int cpu);
141 * bind current thread on a CPU-partition \a cpt of \a cptab
143 int cfs_cpt_bind(struct cfs_cpt_table *cptab, int cpt);
145 * add \a cpu to CPU partion @cpt of \a cptab, return 1 for success,
146 * otherwise 0 is returned
148 int cfs_cpt_set_cpu(struct cfs_cpt_table *cptab, int cpt, int cpu);
150 * remove \a cpu from CPU partition \a cpt of \a cptab
152 void cfs_cpt_unset_cpu(struct cfs_cpt_table *cptab, int cpt, int cpu);
154 * add all cpus in \a mask to CPU partition \a cpt
155 * return 1 if successfully set all CPUs, otherwise return 0
157 int cfs_cpt_set_cpumask(struct cfs_cpt_table *cptab,
158 int cpt, cpumask_t *mask);
160 * remove all cpus in \a mask from CPU partition \a cpt
162 void cfs_cpt_unset_cpumask(struct cfs_cpt_table *cptab,
163 int cpt, cpumask_t *mask);
165 * add all cpus in NUMA node \a node to CPU partition \a cpt
166 * return 1 if successfully set all CPUs, otherwise return 0
168 int cfs_cpt_set_node(struct cfs_cpt_table *cptab, int cpt, int node);
170 * remove all cpus in NUMA node \a node from CPU partition \a cpt
172 void cfs_cpt_unset_node(struct cfs_cpt_table *cptab, int cpt, int node);
175 * add all cpus in node mask \a mask to CPU partition \a cpt
176 * return 1 if successfully set all CPUs, otherwise return 0
178 int cfs_cpt_set_nodemask(struct cfs_cpt_table *cptab,
179 int cpt, nodemask_t *mask);
181 * remove all cpus in node mask \a mask from CPU partition \a cpt
183 void cfs_cpt_unset_nodemask(struct cfs_cpt_table *cptab,
184 int cpt, nodemask_t *mask);
186 * unset all cpus for CPU partition \a cpt
188 void cfs_cpt_clear(struct cfs_cpt_table *cptab, int cpt);
190 * convert partition id \a cpt to numa node id, if there are more than one
191 * nodes in this partition, it might return a different node id each time.
193 int cfs_cpt_spread_node(struct cfs_cpt_table *cptab, int cpt);
196 * return number of HTs in the same core of \a cpu
198 int cfs_cpu_ht_nsiblings(int cpu);
201 * allocate per-cpu-partition data, returned value is an array of pointers,
202 * variable can be indexed by CPU ID.
203 * cptab != NULL: size of array is number of CPU partitions
204 * cptab == NULL: size of array is number of HW cores
206 void *cfs_percpt_alloc(struct cfs_cpt_table *cptab, unsigned int size);
208 * destory per-cpu-partition variable
210 void cfs_percpt_free(void *vars);
211 int cfs_percpt_number(void *vars);
213 #define cfs_percpt_for_each(var, i, vars) \
214 for (i = 0; i < cfs_percpt_number(vars) && \
215 ((var) = (vars)[i]) != NULL; i++)
218 * percpu partition lock
220 * There are some use-cases like this in Lustre:
221 * . each CPU partition has it's own private data which is frequently changed,
222 * and mostly by the local CPU partition.
223 * . all CPU partitions share some global data, these data are rarely changed.
225 * LNet is typical example.
226 * CPU partition lock is designed for this kind of use-cases:
227 * . each CPU partition has it's own private lock
228 * . change on private data just needs to take the private lock
229 * . read on shared data just needs to take _any_ of private locks
230 * . change on shared data needs to take _all_ private locks,
231 * which is slow and should be really rare.
234 CFS_PERCPT_LOCK_EX = -1, /* negative */
237 struct cfs_percpt_lock {
238 /* cpu-partition-table for this lock */
239 struct cfs_cpt_table *pcl_cptab;
240 /* exclusively locked */
241 unsigned int pcl_locked;
242 /* private lock table */
243 spinlock_t **pcl_locks;
246 /* return number of private locks */
247 #define cfs_percpt_lock_num(pcl) cfs_cpt_number(pcl->pcl_cptab)
250 * create a cpu-partition lock based on CPU partition table \a cptab,
251 * each private lock has extra \a psize bytes padding data
253 struct cfs_percpt_lock *cfs_percpt_lock_create(struct cfs_cpt_table *cptab,
254 struct lock_class_key *keys);
255 /* destroy a cpu-partition lock */
256 void cfs_percpt_lock_free(struct cfs_percpt_lock *pcl);
258 /* lock private lock \a index of \a pcl */
259 void cfs_percpt_lock(struct cfs_percpt_lock *pcl, int index);
260 /* unlock private lock \a index of \a pcl */
261 void cfs_percpt_unlock(struct cfs_percpt_lock *pcl, int index);
263 #define CFS_PERCPT_LOCK_KEYS 256
265 /* NB: don't allocate keys dynamically, lockdep needs them to be in ".data" */
266 #define cfs_percpt_lock_alloc(cptab) \
268 static struct lock_class_key ___keys[CFS_PERCPT_LOCK_KEYS]; \
269 struct cfs_percpt_lock *___lk; \
271 if (cfs_cpt_number(cptab) > CFS_PERCPT_LOCK_KEYS) \
272 ___lk = cfs_percpt_lock_create(cptab, NULL); \
274 ___lk = cfs_percpt_lock_create(cptab, ___keys); \
279 * allocate \a nr_bytes of physical memory from a contiguous region with the
280 * properties of \a flags which are bound to the partition id \a cpt. This
281 * function should only be used for the case when only a few pages of memory
285 cfs_cpt_malloc(struct cfs_cpt_table *cptab, int cpt, size_t nr_bytes,
288 return kmalloc_node(nr_bytes, flags,
289 cfs_cpt_spread_node(cptab, cpt));
293 * allocate \a nr_bytes of virtually contiguous memory that is bound to the
294 * partition id \a cpt.
297 cfs_cpt_vzalloc(struct cfs_cpt_table *cptab, int cpt, size_t nr_bytes)
299 /* vzalloc_node() sets __GFP_FS by default but no current Kernel
300 * exported entry-point allows for both a NUMA node specification
301 * and a custom allocation flags mask. This may be an issue since
302 * __GFP_FS usage can cause some deadlock situations in our code,
303 * like when memory reclaim started, within the same context of a
304 * thread doing FS operations, that can also attempt conflicting FS
307 return vzalloc_node(nr_bytes, cfs_cpt_spread_node(cptab, cpt));
311 * allocate a single page of memory with the properties of \a flags were
312 * that page is bound to the partition id \a cpt.
314 static inline struct page *
315 cfs_page_cpt_alloc(struct cfs_cpt_table *cptab, int cpt, gfp_t flags)
317 return alloc_pages_node(cfs_cpt_spread_node(cptab, cpt), flags, 0);
321 * allocate a chunck of memory from a memory pool that is bound to the
322 * partition id \a cpt with the properites of \a flags.
325 cfs_mem_cache_cpt_alloc(struct kmem_cache *cachep, struct cfs_cpt_table *cptab,
326 int cpt, gfp_t flags)
328 return kmem_cache_alloc_node(cachep, flags,
329 cfs_cpt_spread_node(cptab, cpt));
333 * iterate over all CPU partitions in \a cptab
335 #define cfs_cpt_for_each(i, cptab) \
336 for (i = 0; i < cfs_cpt_number(cptab); i++)
338 #ifndef __read_mostly
339 # define __read_mostly
342 #ifndef ____cacheline_aligned
343 #define ____cacheline_aligned
346 int cfs_cpu_init(void);
347 void cfs_cpu_fini(void);
349 #endif /* __LIBCFS_CPU_H__ */