aboutsummaryrefslogtreecommitdiffstats
path: root/mm/percpu.c
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2014-03-06 20:52:32 -0500
committerTejun Heo <tj@kernel.org>2014-03-07 07:52:26 -0500
commit3d331ad74fa33f0b14a46cf0de8358012d3c1500 (patch)
tree17b8d8615001e4de1a7a3a1e86418485fd4179d1 /mm/percpu.c
parent723ad1d90b5663ab623bb3bfba3e4ee7101795d7 (diff)
percpu: speed alloc_pcpu_area() up
If we know that first N areas are all in use, we can obviously skip them when searching for a free one. And that kind of hint is very easy to maintain. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Tejun Heo <tj@kernel.org>
Diffstat (limited to 'mm/percpu.c')
-rw-r--r--mm/percpu.c18
1 files changed, 17 insertions, 1 deletions
diff --git a/mm/percpu.c b/mm/percpu.c
index 49dfccf9169c..c7206d06f8de 100644
--- a/mm/percpu.c
+++ b/mm/percpu.c
@@ -106,6 +106,7 @@ struct pcpu_chunk {
106 int map_alloc; /* # of map entries allocated */ 106 int map_alloc; /* # of map entries allocated */
107 int *map; /* allocation map */ 107 int *map; /* allocation map */
108 void *data; /* chunk data */ 108 void *data; /* chunk data */
109 int first_free; /* no free below this */
109 bool immutable; /* no [de]population allowed */ 110 bool immutable; /* no [de]population allowed */
110 unsigned long populated[]; /* populated bitmap */ 111 unsigned long populated[]; /* populated bitmap */
111}; 112};
@@ -441,9 +442,10 @@ static int pcpu_alloc_area(struct pcpu_chunk *chunk, int size, int align)
441 int oslot = pcpu_chunk_slot(chunk); 442 int oslot = pcpu_chunk_slot(chunk);
442 int max_contig = 0; 443 int max_contig = 0;
443 int i, off; 444 int i, off;
445 bool seen_free = false;
444 int *p; 446 int *p;
445 447
446 for (i = 0, p = chunk->map; i < chunk->map_used; i++, p++) { 448 for (i = chunk->first_free, p = chunk->map + i; i < chunk->map_used; i++, p++) {
447 int head, tail; 449 int head, tail;
448 int this_size; 450 int this_size;
449 451
@@ -456,6 +458,10 @@ static int pcpu_alloc_area(struct pcpu_chunk *chunk, int size, int align)
456 458
457 this_size = (p[1] & ~1) - off; 459 this_size = (p[1] & ~1) - off;
458 if (this_size < head + size) { 460 if (this_size < head + size) {
461 if (!seen_free) {
462 chunk->first_free = i;
463 seen_free = true;
464 }
459 max_contig = max(this_size, max_contig); 465 max_contig = max(this_size, max_contig);
460 continue; 466 continue;
461 } 467 }
@@ -491,6 +497,10 @@ static int pcpu_alloc_area(struct pcpu_chunk *chunk, int size, int align)
491 chunk->map_used += nr_extra; 497 chunk->map_used += nr_extra;
492 498
493 if (head) { 499 if (head) {
500 if (!seen_free) {
501 chunk->first_free = i;
502 seen_free = true;
503 }
494 *++p = off += head; 504 *++p = off += head;
495 ++i; 505 ++i;
496 max_contig = max(head, max_contig); 506 max_contig = max(head, max_contig);
@@ -501,6 +511,9 @@ static int pcpu_alloc_area(struct pcpu_chunk *chunk, int size, int align)
501 } 511 }
502 } 512 }
503 513
514 if (!seen_free)
515 chunk->first_free = i + 1;
516
504 /* update hint and mark allocated */ 517 /* update hint and mark allocated */
505 if (i + 1 == chunk->map_used) 518 if (i + 1 == chunk->map_used)
506 chunk->contig_hint = max_contig; /* fully scanned */ 519 chunk->contig_hint = max_contig; /* fully scanned */
@@ -558,6 +571,9 @@ static void pcpu_free_area(struct pcpu_chunk *chunk, int freeme)
558 } 571 }
559 BUG_ON(off != freeme); 572 BUG_ON(off != freeme);
560 573
574 if (i < chunk->first_free)
575 chunk->first_free = i;
576
561 p = chunk->map + i; 577 p = chunk->map + i;
562 *p = off &= ~1; 578 *p = off &= ~1;
563 chunk->free_size += (p[1] & ~1) - off; 579 chunk->free_size += (p[1] & ~1) - off;