SLUB allocator 4 for Linux memory management [slub page size calculation method]
Today, I tracked the calculation methods of object and page order in SLUB in detail and sorted them out to avoid forgetting later, mainly including:
- The calculation method of page order is to apply for kmem_ How many pages should each slab apply for when caching?
- order_ Calculation and API description of objects
1. Calculation description of order
Order is the parameter passed in when applying for page. 2^order is the number of pages;
During calculation, the number of objects that can be accommodated in this slab and the remaining (wasted) space after removing objects need to be considered. First, look at the overall calculation logic diagram:
-
Judgment on the minimum number of objects that can be accommodated:
-
Confirm according to the number of CPUs of the machine: min_objects = 4 * (fls(nr_cpu_ids) + 1)
fls is the highest position of the parameter, that is, fls(100B) = 3 for 4 cores, and min is obtained_ Objects is 16
-
According to size and configured Max_ Order confirmation: ((page_size < < max_order) - reserved) / size
PAGE_ According to the machine configuration, the size is 4K, max_ The order quantity is configured as 3
That is, if the object size is 5K, the Min obtained here_ Objects is 6
size(Bytes) max_order page_size max_objects min_objects(fls) min_result 128 Bytes 3 4K 256 16 16 256 Bytes 3 4K 128 16 16 512 Bytes 3 4K 64 16 16 1024 Bytes 3 4K 32 16 16 2048 Bytes 3 4K 16 16 16 4096 Bytes 3 4K 8 16 8 8192 Bytes 3 4K 4 16 4 4*1024*2^3/size 4*(fls(n)+1) min(max_obj, min_obj) Relevant parts:
min_objects = slub_min_objects; //According to the print value, it is 0 here, that is, at least 0 object s if (!min_objects) min_objects = 4 * (fls(nr_cpu_ids) + 1);//fls is the highest position, that is, fls(100B)=3 for 4 cores, and min is obtained_ Objects is 16; //This is used to calculate the maximum number of object s of size that can be allocated if we apply for the maximum number of order s? max_objects = order_objects(slub_max_order, size, reserved);//slab_max_order = 3 min_objects = min(min_objects, max_objects);//Take the smaller one //Obviously, 4K * 2 ^ 3 = 32K at most, that is, object s less than 2K basically use the value of 16;
-
-
The amount of wasted space, i.e. according to min_objects * size how many page s will be available after getting the order application:
Calculation method: (page_size < < order - reserved)% size
size(Bytes) max_order min_result min_order rem 128 Bytes 3 16 0 0 256 Bytes 3 16 0 0 512 Bytes 3 16 1 0 1024 Bytes 3 16 2 0 2048 Bytes 3 16 3 0 4096 Bytes 3 8 3 0 8192 Bytes 3 4 3 0 min(max_obj, min_obj) size*min_result -1 Since the above size examples are all integer multiples of 2, the calculated rmem is 0, and the order uses min_ Just order
Relevant parts:
while (min_objects > 1) {// fraction = 16;//Influence factor while (fraction >= 4) { //Combining size and minobject to calculate the appropriate order is actually the ability to apply for min_ There are so many objects, and then the waste can be within 1/fraction of the whole order = slab_order(size, min_objects, slub_max_order, fraction, reserved); if (order <= slub_max_order) return order; fraction /= 2;//If you are not satisfied, halve the fraction, that is, the waste of free mem can reach twice the original } min_objects--; } static inline int slab_order(int size, int min_objects, int max_order, int fract_leftover, int reserved) { int order; int rem; int min_order = slub_min_order;//0 ... for (order = max(min_order, get_order(min_objects * size + reserved)); order <= max_order; order++) { unsigned long slab_size = PAGE_SIZE << order;//Suppose you apply for an order page at a time rem = (slab_size - reserved) % size;//How much mem is wasted if (rem <= slab_size / fract_leftover)//If the waste does not exceed 1 / 16 of the application, it is considered OK; break; } return order; }
-
Obtain the appropriate order value according to the results of the first two steps
- Meet the minimum number of objects;
- Meet the requirement that the wasted mem is less than 1/fraction of the overall mem;
- If the above two requirements cannot be met, proceed as follows:
- Increase the number of order s
- Decrease the value of fraction
- Decrease min_ Value of object
Relevant code s and notes in this part are as follows:
static inline int calculate_order(int size, int reserved) { int order; int min_objects; int fraction; int max_objects; min_objects = slub_min_objects; //According to the print value, it is 0 here, that is, at least 0 object s if (!min_objects) min_objects = 4 * (fls(nr_cpu_ids) + 1);//fls is the highest position, that is, fls(100B)=3 for 4 cores, and min is obtained_ Objects is 16; //This is used to calculate the maximum number of object s of size that can be allocated if we apply for the maximum number of order s? max_objects = order_objects(slub_max_order, size, reserved);//slab_max_order = 3 min_objects = min(min_objects, max_objects);//Take the smaller one //Obviously, 4K * 2 ^ 3 = 32K at most, that is, object s less than 2K basically use the value of 16; while (min_objects > 1) {// fraction = 16;//Influence factor while (fraction >= 4) { //Combining size and minobject to calculate the appropriate order is actually the ability to apply for min_ There are so many objects, and then the waste can be within 1/fraction of the whole order = slab_order(size, min_objects, slub_max_order, fraction, reserved); if (order <= slub_max_order) return order; fraction /= 2;//If you are not satisfied, halve the fraction, that is, the waste of free mem can reach twice the original } min_objects--; } order = slab_order(size, 1, slub_max_order, 1, reserved);//Apply for one if (order <= slub_max_order) return order; order = slab_order(size, 1, MAX_ORDER, 1, reserved);//Expand the number of order s if (order < MAX_ORDER) return order; return -ENOSYS; } static inline int order_objects(int order, unsigned long size, int reserved) { return ((PAGE_SIZE << order) - reserved) / size;//A simple division calculation } static inline int slab_order(int size, int min_objects, int max_order, int fract_leftover, int reserved) { int order; int rem; int min_order = slub_min_order;//0 if (order_objects(min_order, size, reserved) > MAX_OBJS_PER_PAGE)//Determine whether to apply for content < = 1bit return get_order(size * MAX_OBJS_PER_PAGE) - 1;//Assuming 1 bit, the maximum order is actually returned here, that is, 3 for (order = max(min_order, get_order(min_objects * size + reserved)); order <= max_order; order++) { unsigned long slab_size = PAGE_SIZE << order;//Suppose you apply for an order page at a time rem = (slab_size - reserved) % size;//How much mem is wasted if (rem <= slab_size / fract_leftover)//If the waste does not exceed 1 / 16 of the application, it is considered OK; break; } return order; } static inline __attribute_const__ int __get_order(unsigned long size) { int order; size--; size >>= PAGE_SHIFT;//12, shift right 12bit order = fls64(size); return order; }
2. order_ API for object calculation and construction
order_ The structure of object is kmem_ The structure used to save order and objects count in cache is as follows:
Interface | explain |
---|---|
kmem_cache_order_objects | definition |
oo_make | Constructor |
oo_order | Get order, i.e. high 16bits |
oo_objects | Get objects, i.e. low 16bits |
order_objects | Calculate objects |
-
definition
struct kmem_cache_order_objects { unsigned long x; };
-
Constructor
static inline struct kmem_cache_order_objects oo_make(int order, unsigned long size, int reserved) { struct kmem_cache_order_objects x = { (order << OO_SHIFT) + order_objects(order, size, reserved) }; return x; } #define OO_SHIFT 16 #define OO_MASK ((1 << OO_SHIFT) - 1)
Save the order in high 16bits and the number of objects in low 16bits
-
Get order, i.e. high 16bits
static inline int oo_order(struct kmem_cache_order_objects x) { return x.x >> OO_SHIFT; }
-
Get objects, i.e. low 16bits
static inline int oo_objects(struct kmem_cache_order_objects x) { return x.x & OO_MASK; }
-
Calculate objects
static inline int order_objects(int order, unsigned long size, int reserved) { return ((PAGE_SIZE << order) - reserved) / size; }