diff options
author | Matthew Wilcox <mawilcox@microsoft.com> | 2016-12-17 08:18:17 -0500 |
---|---|---|
committer | Matthew Wilcox <mawilcox@microsoft.com> | 2017-02-13 21:44:02 -0500 |
commit | d37cacc5adace7f3e0824e1f559192ad7299d029 (patch) | |
tree | 9932ecc9ba3010ecc53bdbf5cd299eb0842106ec /tools | |
parent | 7ad3d4d85c7af9632055a6ac0aa15b6b6a321c6b (diff) |
ida: Use exceptional entries for small IDAs
We can use the root entry as a bitmap and save allocating a 128 byte
bitmap for an IDA that contains only a few entries (30 on a 32-bit
machine, 62 on a 64-bit machine). This costs about 300 bytes of kernel
text on x86-64, so as long as 3 IDAs fall into this category, this
is a net win for memory consumption.
Thanks to Rasmus Villemoes for his work documenting the problem and
collecting statistics on IDAs.
Signed-off-by: Matthew Wilcox <mawilcox@microsoft.com>
Diffstat (limited to 'tools')
-rw-r--r-- | tools/testing/radix-tree/idr-test.c | 93 |
1 files changed, 92 insertions, 1 deletions
diff --git a/tools/testing/radix-tree/idr-test.c b/tools/testing/radix-tree/idr-test.c index 4dffad9284e0..59081122c63d 100644 --- a/tools/testing/radix-tree/idr-test.c +++ b/tools/testing/radix-tree/idr-test.c | |||
@@ -11,6 +11,7 @@ | |||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
12 | * more details. | 12 | * more details. |
13 | */ | 13 | */ |
14 | #include <linux/bitmap.h> | ||
14 | #include <linux/idr.h> | 15 | #include <linux/idr.h> |
15 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
16 | #include <linux/kernel.h> | 17 | #include <linux/kernel.h> |
@@ -214,7 +215,7 @@ void ida_check_nomem(void) | |||
214 | DEFINE_IDA(ida); | 215 | DEFINE_IDA(ida); |
215 | int id, err; | 216 | int id, err; |
216 | 217 | ||
217 | err = ida_get_new(&ida, &id); | 218 | err = ida_get_new_above(&ida, 256, &id); |
218 | assert(err == -EAGAIN); | 219 | assert(err == -EAGAIN); |
219 | err = ida_get_new_above(&ida, 1UL << 30, &id); | 220 | err = ida_get_new_above(&ida, 1UL << 30, &id); |
220 | assert(err == -EAGAIN); | 221 | assert(err == -EAGAIN); |
@@ -247,6 +248,66 @@ void ida_check_leaf(void) | |||
247 | } | 248 | } |
248 | 249 | ||
249 | /* | 250 | /* |
251 | * Check handling of conversions between exceptional entries and full bitmaps. | ||
252 | */ | ||
253 | void ida_check_conv(void) | ||
254 | { | ||
255 | DEFINE_IDA(ida); | ||
256 | int id; | ||
257 | unsigned long i; | ||
258 | |||
259 | for (i = 0; i < IDA_BITMAP_BITS * 2; i += IDA_BITMAP_BITS) { | ||
260 | assert(ida_pre_get(&ida, GFP_KERNEL)); | ||
261 | assert(!ida_get_new_above(&ida, i + 1, &id)); | ||
262 | assert(id == i + 1); | ||
263 | assert(!ida_get_new_above(&ida, i + BITS_PER_LONG, &id)); | ||
264 | assert(id == i + BITS_PER_LONG); | ||
265 | ida_remove(&ida, i + 1); | ||
266 | ida_remove(&ida, i + BITS_PER_LONG); | ||
267 | assert(ida_is_empty(&ida)); | ||
268 | } | ||
269 | |||
270 | assert(ida_pre_get(&ida, GFP_KERNEL)); | ||
271 | |||
272 | for (i = 0; i < IDA_BITMAP_BITS * 2; i++) { | ||
273 | assert(ida_pre_get(&ida, GFP_KERNEL)); | ||
274 | assert(!ida_get_new(&ida, &id)); | ||
275 | assert(id == i); | ||
276 | } | ||
277 | |||
278 | for (i = IDA_BITMAP_BITS * 2; i > 0; i--) { | ||
279 | ida_remove(&ida, i - 1); | ||
280 | } | ||
281 | assert(ida_is_empty(&ida)); | ||
282 | |||
283 | for (i = 0; i < IDA_BITMAP_BITS + BITS_PER_LONG - 4; i++) { | ||
284 | assert(ida_pre_get(&ida, GFP_KERNEL)); | ||
285 | assert(!ida_get_new(&ida, &id)); | ||
286 | assert(id == i); | ||
287 | } | ||
288 | |||
289 | for (i = IDA_BITMAP_BITS + BITS_PER_LONG - 4; i > 0; i--) { | ||
290 | ida_remove(&ida, i - 1); | ||
291 | } | ||
292 | assert(ida_is_empty(&ida)); | ||
293 | |||
294 | radix_tree_cpu_dead(1); | ||
295 | for (i = 0; i < 1000000; i++) { | ||
296 | int err = ida_get_new(&ida, &id); | ||
297 | if (err == -EAGAIN) { | ||
298 | assert((i % IDA_BITMAP_BITS) == (BITS_PER_LONG - 2)); | ||
299 | assert(ida_pre_get(&ida, GFP_KERNEL)); | ||
300 | err = ida_get_new(&ida, &id); | ||
301 | } else { | ||
302 | assert((i % IDA_BITMAP_BITS) != (BITS_PER_LONG - 2)); | ||
303 | } | ||
304 | assert(!err); | ||
305 | assert(id == i); | ||
306 | } | ||
307 | ida_destroy(&ida); | ||
308 | } | ||
309 | |||
310 | /* | ||
250 | * Check allocations up to and slightly above the maximum allowed (2^31-1) ID. | 311 | * Check allocations up to and slightly above the maximum allowed (2^31-1) ID. |
251 | * Allocating up to 2^31-1 should succeed, and then allocating the next one | 312 | * Allocating up to 2^31-1 should succeed, and then allocating the next one |
252 | * should fail. | 313 | * should fail. |
@@ -273,6 +334,34 @@ void ida_check_max(void) | |||
273 | } | 334 | } |
274 | } | 335 | } |
275 | 336 | ||
337 | void ida_check_random(void) | ||
338 | { | ||
339 | DEFINE_IDA(ida); | ||
340 | DECLARE_BITMAP(bitmap, 2048); | ||
341 | int id; | ||
342 | unsigned int i; | ||
343 | time_t s = time(NULL); | ||
344 | |||
345 | repeat: | ||
346 | memset(bitmap, 0, sizeof(bitmap)); | ||
347 | for (i = 0; i < 100000; i++) { | ||
348 | int i = rand(); | ||
349 | int bit = i & 2047; | ||
350 | if (test_bit(bit, bitmap)) { | ||
351 | __clear_bit(bit, bitmap); | ||
352 | ida_remove(&ida, bit); | ||
353 | } else { | ||
354 | __set_bit(bit, bitmap); | ||
355 | ida_pre_get(&ida, GFP_KERNEL); | ||
356 | assert(!ida_get_new_above(&ida, bit, &id)); | ||
357 | assert(id == bit); | ||
358 | } | ||
359 | } | ||
360 | ida_destroy(&ida); | ||
361 | if (time(NULL) < s + 10) | ||
362 | goto repeat; | ||
363 | } | ||
364 | |||
276 | void ida_checks(void) | 365 | void ida_checks(void) |
277 | { | 366 | { |
278 | DEFINE_IDA(ida); | 367 | DEFINE_IDA(ida); |
@@ -337,6 +426,8 @@ void ida_checks(void) | |||
337 | 426 | ||
338 | ida_check_leaf(); | 427 | ida_check_leaf(); |
339 | ida_check_max(); | 428 | ida_check_max(); |
429 | ida_check_conv(); | ||
430 | ida_check_random(); | ||
340 | 431 | ||
341 | radix_tree_cpu_dead(1); | 432 | radix_tree_cpu_dead(1); |
342 | } | 433 | } |