Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'slab-for-6.7' of git://git.kernel.org/pub/scm/linux/kernel/git/vbabka/slab

Pull slab updates from Vlastimil Babka:

- SLUB: slab order calculation refactoring (Vlastimil Babka, Feng Tang)

Recent proposals to tune the slab order calculations have prompted us
to look at the current code and refactor it to make it easier to
follow and eliminate some odd corner cases.

The refactoring is mostly non-functional changes, but should make the
actual tuning easier to implement and review.

* tag 'slab-for-6.7' of git://git.kernel.org/pub/scm/linux/kernel/git/vbabka/slab:
mm/slub: refactor calculate_order() and calc_slab_order()
mm/slub: attempt to find layouts up to 1/2 waste in calculate_order()
mm/slub: remove min_objects loop from calculate_order()
mm/slub: simplify the last resort slab order calculation
mm/slub: add sanity check for slub_min/max_order cmdline setup

+36 -37
+36 -37
mm/slub.c
··· 4110 4110 * the smallest order which will fit the object. 4111 4111 */ 4112 4112 static inline unsigned int calc_slab_order(unsigned int size, 4113 - unsigned int min_objects, unsigned int max_order, 4113 + unsigned int min_order, unsigned int max_order, 4114 4114 unsigned int fract_leftover) 4115 4115 { 4116 - unsigned int min_order = slub_min_order; 4117 4116 unsigned int order; 4118 4117 4119 - if (order_objects(min_order, size) > MAX_OBJS_PER_PAGE) 4120 - return get_order(size * MAX_OBJS_PER_PAGE) - 1; 4121 - 4122 - for (order = max(min_order, (unsigned int)get_order(min_objects * size)); 4123 - order <= max_order; order++) { 4118 + for (order = min_order; order <= max_order; order++) { 4124 4119 4125 4120 unsigned int slab_size = (unsigned int)PAGE_SIZE << order; 4126 4121 unsigned int rem; ··· 4134 4139 unsigned int order; 4135 4140 unsigned int min_objects; 4136 4141 unsigned int max_objects; 4137 - unsigned int nr_cpus; 4142 + unsigned int min_order; 4138 4143 4139 - /* 4140 - * Attempt to find best configuration for a slab. This 4141 - * works by first attempting to generate a layout with 4142 - * the best configuration and backing off gradually. 4143 - * 4144 - * First we increase the acceptable waste in a slab. Then 4145 - * we reduce the minimum objects required in a slab. 4146 - */ 4147 4144 min_objects = slub_min_objects; 4148 4145 if (!min_objects) { 4149 4146 /* ··· 4147 4160 * order on systems that appear larger than they are, and too 4148 4161 * low order on systems that appear smaller than they are. 4149 4162 */ 4150 - nr_cpus = num_present_cpus(); 4163 + unsigned int nr_cpus = num_present_cpus(); 4151 4164 if (nr_cpus <= 1) 4152 4165 nr_cpus = nr_cpu_ids; 4153 4166 min_objects = 4 * (fls(nr_cpus) + 1); 4154 4167 } 4155 - max_objects = order_objects(slub_max_order, size); 4168 + /* min_objects can't be 0 because get_order(0) is undefined */ 4169 + max_objects = max(order_objects(slub_max_order, size), 1U); 4156 4170 min_objects = min(min_objects, max_objects); 4157 4171 4158 - while (min_objects > 1) { 4159 - unsigned int fraction; 4160 - 4161 - fraction = 16; 4162 - while (fraction >= 4) { 4163 - order = calc_slab_order(size, min_objects, 4164 - slub_max_order, fraction); 4165 - if (order <= slub_max_order) 4166 - return order; 4167 - fraction /= 2; 4168 - } 4169 - min_objects--; 4170 - } 4172 + min_order = max_t(unsigned int, slub_min_order, 4173 + get_order(min_objects * size)); 4174 + if (order_objects(min_order, size) > MAX_OBJS_PER_PAGE) 4175 + return get_order(size * MAX_OBJS_PER_PAGE) - 1; 4171 4176 4172 4177 /* 4173 - * We were unable to place multiple objects in a slab. Now 4174 - * lets see if we can place a single object there. 4178 + * Attempt to find best configuration for a slab. This works by first 4179 + * attempting to generate a layout with the best possible configuration 4180 + * and backing off gradually. 4181 + * 4182 + * We start with accepting at most 1/16 waste and try to find the 4183 + * smallest order from min_objects-derived/slub_min_order up to 4184 + * slub_max_order that will satisfy the constraint. Note that increasing 4185 + * the order can only result in same or less fractional waste, not more. 4186 + * 4187 + * If that fails, we increase the acceptable fraction of waste and try 4188 + * again. The last iteration with fraction of 1/2 would effectively 4189 + * accept any waste and give us the order determined by min_objects, as 4190 + * long as at least single object fits within slub_max_order. 4175 4191 */ 4176 - order = calc_slab_order(size, 1, slub_max_order, 1); 4177 - if (order <= slub_max_order) 4178 - return order; 4192 + for (unsigned int fraction = 16; fraction > 1; fraction /= 2) { 4193 + order = calc_slab_order(size, min_order, slub_max_order, 4194 + fraction); 4195 + if (order <= slub_max_order) 4196 + return order; 4197 + } 4179 4198 4180 4199 /* 4181 4200 * Doh this slab cannot be placed using slub_max_order. 4182 4201 */ 4183 - order = calc_slab_order(size, 1, MAX_ORDER, 1); 4202 + order = get_order(size); 4184 4203 if (order <= MAX_ORDER) 4185 4204 return order; 4186 4205 return -ENOSYS; ··· 4704 4711 { 4705 4712 get_option(&str, (int *)&slub_min_order); 4706 4713 4714 + if (slub_min_order > slub_max_order) 4715 + slub_max_order = slub_min_order; 4716 + 4707 4717 return 1; 4708 4718 } 4709 4719 ··· 4716 4720 { 4717 4721 get_option(&str, (int *)&slub_max_order); 4718 4722 slub_max_order = min_t(unsigned int, slub_max_order, MAX_ORDER); 4723 + 4724 + if (slub_min_order > slub_max_order) 4725 + slub_min_order = slub_max_order; 4719 4726 4720 4727 return 1; 4721 4728 }