diff options
author | Namhoon Kim <namhoonk@cs.unc.edu> | 2017-06-05 12:26:29 -0400 |
---|---|---|
committer | Namhoon Kim <namhoonk@cs.unc.edu> | 2017-06-05 12:26:29 -0400 |
commit | 9b5f4aab419ba370062e28231f6910292813a9c9 (patch) | |
tree | 4bf6486a5b6f389ba52ec5263344fdcf428c769a | |
parent | fa0a28ee893e8e698263b0bbddee8d541d4c86a6 (diff) |
per-partition buddy allocator
-rw-r--r-- | include/linux/gfp.h | 7 | ||||
-rw-r--r-- | include/linux/mmzone.h | 19 | ||||
-rw-r--r-- | include/litmus/page_dev.h | 2 | ||||
-rw-r--r-- | litmus/bank_proc.c | 22 | ||||
-rw-r--r-- | litmus/color_shm.c | 8 | ||||
-rw-r--r-- | litmus/litmus.c | 39 | ||||
-rw-r--r-- | litmus/page_dev.c | 154 | ||||
-rw-r--r-- | mm/page_alloc.c | 417 | ||||
-rw-r--r-- | mm/vmstat.c | 89 |
9 files changed, 553 insertions, 204 deletions
diff --git a/include/linux/gfp.h b/include/linux/gfp.h index 15928f0647e4..10a4601c558b 100644 --- a/include/linux/gfp.h +++ b/include/linux/gfp.h | |||
@@ -35,6 +35,7 @@ struct vm_area_struct; | |||
35 | #define ___GFP_NO_KSWAPD 0x400000u | 35 | #define ___GFP_NO_KSWAPD 0x400000u |
36 | #define ___GFP_OTHER_NODE 0x800000u | 36 | #define ___GFP_OTHER_NODE 0x800000u |
37 | #define ___GFP_WRITE 0x1000000u | 37 | #define ___GFP_WRITE 0x1000000u |
38 | #define ___GFP_COLOR 0x2000000u | ||
38 | /* If the above are modified, __GFP_BITS_SHIFT may need updating */ | 39 | /* If the above are modified, __GFP_BITS_SHIFT may need updating */ |
39 | 40 | ||
40 | /* | 41 | /* |
@@ -94,6 +95,7 @@ struct vm_area_struct; | |||
94 | #define __GFP_NO_KSWAPD ((__force gfp_t)___GFP_NO_KSWAPD) | 95 | #define __GFP_NO_KSWAPD ((__force gfp_t)___GFP_NO_KSWAPD) |
95 | #define __GFP_OTHER_NODE ((__force gfp_t)___GFP_OTHER_NODE) /* On behalf of other node */ | 96 | #define __GFP_OTHER_NODE ((__force gfp_t)___GFP_OTHER_NODE) /* On behalf of other node */ |
96 | #define __GFP_WRITE ((__force gfp_t)___GFP_WRITE) /* Allocator intends to dirty page */ | 97 | #define __GFP_WRITE ((__force gfp_t)___GFP_WRITE) /* Allocator intends to dirty page */ |
98 | #define __GFP_COLOR ((__force gfp_t)___GFP_COLOR) /* Colored page request */ | ||
97 | 99 | ||
98 | /* | 100 | /* |
99 | * This may seem redundant, but it's a way of annotating false positives vs. | 101 | * This may seem redundant, but it's a way of annotating false positives vs. |
@@ -101,7 +103,7 @@ struct vm_area_struct; | |||
101 | */ | 103 | */ |
102 | #define __GFP_NOTRACK_FALSE_POSITIVE (__GFP_NOTRACK) | 104 | #define __GFP_NOTRACK_FALSE_POSITIVE (__GFP_NOTRACK) |
103 | 105 | ||
104 | #define __GFP_BITS_SHIFT 25 /* Room for N __GFP_FOO bits */ | 106 | #define __GFP_BITS_SHIFT 26 /* Room for N __GFP_FOO bits */ |
105 | #define __GFP_BITS_MASK ((__force gfp_t)((1 << __GFP_BITS_SHIFT) - 1)) | 107 | #define __GFP_BITS_MASK ((__force gfp_t)((1 << __GFP_BITS_SHIFT) - 1)) |
106 | 108 | ||
107 | /* This equals 0, but use constants in case they ever change */ | 109 | /* This equals 0, but use constants in case they ever change */ |
@@ -146,6 +148,9 @@ struct vm_area_struct; | |||
146 | /* 4GB DMA on some platforms */ | 148 | /* 4GB DMA on some platforms */ |
147 | #define GFP_DMA32 __GFP_DMA32 | 149 | #define GFP_DMA32 __GFP_DMA32 |
148 | 150 | ||
151 | /* Colored page requests */ | ||
152 | #define GFP_COLOR __GFP_COLOR | ||
153 | |||
149 | /* Convert GFP flags to their corresponding migrate type */ | 154 | /* Convert GFP flags to their corresponding migrate type */ |
150 | static inline int gfpflags_to_migratetype(const gfp_t gfp_flags) | 155 | static inline int gfpflags_to_migratetype(const gfp_t gfp_flags) |
151 | { | 156 | { |
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index 92084abf3cf5..d28f7ef8228d 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h | |||
@@ -38,11 +38,13 @@ | |||
38 | /* For page coloring - This address decoding is used in imx6-sabresd | 38 | /* For page coloring - This address decoding is used in imx6-sabresd |
39 | * platform without bank interleaving . | 39 | * platform without bank interleaving . |
40 | */ | 40 | */ |
41 | #define BANK_MASK 0x38000000 | 41 | #define BANK_MASK 0x38000000 |
42 | #define BANK_SHIFT 27 | 42 | #define BANK_SHIFT 27 |
43 | 43 | #define CACHE_MASK 0x0000f000 | |
44 | #define CACHE_MASK 0x0000f000 | 44 | #define CACHE_SHIFT 12 |
45 | #define CACHE_SHIFT 12 | 45 | #define MAX_NUM_COLOR 16 |
46 | #define MAX_NUM_BANK 8 | ||
47 | #define MAX_PARTITIONED_ORDER 3 | ||
46 | 48 | ||
47 | enum { | 49 | enum { |
48 | MIGRATE_UNMOVABLE, | 50 | MIGRATE_UNMOVABLE, |
@@ -485,7 +487,8 @@ struct zone { | |||
485 | ZONE_PADDING(_pad1_) | 487 | ZONE_PADDING(_pad1_) |
486 | /* free areas of different sizes */ | 488 | /* free areas of different sizes */ |
487 | struct free_area free_area[MAX_ORDER]; | 489 | struct free_area free_area[MAX_ORDER]; |
488 | 490 | struct free_area free_area_d[NR_CPUS][MAX_PARTITIONED_ORDER]; | |
491 | |||
489 | /* zone flags, see below */ | 492 | /* zone flags, see below */ |
490 | unsigned long flags; | 493 | unsigned long flags; |
491 | 494 | ||
@@ -532,7 +535,9 @@ struct zone { | |||
532 | /* Set to true when the PG_migrate_skip bits should be cleared */ | 535 | /* Set to true when the PG_migrate_skip bits should be cleared */ |
533 | bool compact_blockskip_flush; | 536 | bool compact_blockskip_flush; |
534 | #endif | 537 | #endif |
535 | 538 | ||
539 | struct list_head color_list[MAX_NUM_COLOR * MAX_NUM_BANK]; | ||
540 | DECLARE_BITMAP(color_map, MAX_NUM_COLOR*MAX_NUM_BANK); | ||
536 | ZONE_PADDING(_pad3_) | 541 | ZONE_PADDING(_pad3_) |
537 | /* Zone statistics */ | 542 | /* Zone statistics */ |
538 | atomic_long_t vm_stat[NR_VM_ZONE_STAT_ITEMS]; | 543 | atomic_long_t vm_stat[NR_VM_ZONE_STAT_ITEMS]; |
diff --git a/include/litmus/page_dev.h b/include/litmus/page_dev.h index 9dac293651f0..f1791469cba1 100644 --- a/include/litmus/page_dev.h +++ b/include/litmus/page_dev.h | |||
@@ -26,5 +26,7 @@ | |||
26 | 26 | ||
27 | int llc_partition_handler(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos); | 27 | int llc_partition_handler(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos); |
28 | int dram_partition_handler(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos); | 28 | int dram_partition_handler(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos); |
29 | int bank_to_partition(unsigned int bank); | ||
30 | int is_in_llc_partition(struct page* page, int cpu); | ||
29 | 31 | ||
30 | #endif /* _LITMUS_PAGE_DEV_H */ \ No newline at end of file | 32 | #endif /* _LITMUS_PAGE_DEV_H */ \ No newline at end of file |
diff --git a/litmus/bank_proc.c b/litmus/bank_proc.c index 097cff177a2d..353d38dbe9d6 100644 --- a/litmus/bank_proc.c +++ b/litmus/bank_proc.c | |||
@@ -120,26 +120,6 @@ unsigned int two_exp(unsigned int e) | |||
120 | return v; | 120 | return v; |
121 | } | 121 | } |
122 | 122 | ||
123 | unsigned int num_by_bitmask_index(unsigned int bitmask, unsigned int index) | ||
124 | { | ||
125 | unsigned int pos = 0; | ||
126 | |||
127 | while(true) | ||
128 | { | ||
129 | if(index ==0 && (bitmask & 1)==1) | ||
130 | { | ||
131 | break; | ||
132 | } | ||
133 | if(index !=0 && (bitmask & 1)==1){ | ||
134 | index--; | ||
135 | } | ||
136 | pos++; | ||
137 | bitmask = bitmask >>1; | ||
138 | |||
139 | } | ||
140 | return pos; | ||
141 | } | ||
142 | |||
143 | /* helper functions to find the next colored pool index */ | 123 | /* helper functions to find the next colored pool index */ |
144 | static inline unsigned int first_index(unsigned long node) | 124 | static inline unsigned int first_index(unsigned long node) |
145 | { | 125 | { |
@@ -160,7 +140,7 @@ static inline unsigned int first_index(unsigned long node) | |||
160 | 140 | ||
161 | static inline unsigned int last_index(unsigned long node) | 141 | static inline unsigned int last_index(unsigned long node) |
162 | { | 142 | { |
163 | unsigned int bank_no = 7, color_no = 15; | 143 | unsigned int bank_no = NUM_BANKS-1, color_no = NUM_COLORS-1; |
164 | 144 | ||
165 | while(bank_no >= 0) { | 145 | while(bank_no >= 0) { |
166 | if ((bank_partition[node]>>bank_no) & 0x1) | 146 | if ((bank_partition[node]>>bank_no) & 0x1) |
diff --git a/litmus/color_shm.c b/litmus/color_shm.c index d4913cd5f213..084262335466 100644 --- a/litmus/color_shm.c +++ b/litmus/color_shm.c | |||
@@ -264,10 +264,10 @@ static int litmus_color_shm_mmap(struct file *filp, struct vm_area_struct *vma) | |||
264 | TRACE_CUR("flags=0x%lx prot=0x%lx\n", vma->vm_flags, | 264 | TRACE_CUR("flags=0x%lx prot=0x%lx\n", vma->vm_flags, |
265 | pgprot_val(vma->vm_page_prot)); | 265 | pgprot_val(vma->vm_page_prot)); |
266 | out: | 266 | out: |
267 | color_param.color == 0x00000000; | 267 | color_param.color = 0x00000000; |
268 | color_param.bank == 0x00000000; | 268 | color_param.bank = 0x00000000; |
269 | color_offset.offset == 0xffffffff; | 269 | color_offset.offset = 0xffffffff; |
270 | color_offset.lock == -1; | 270 | color_offset.lock = -1; |
271 | 271 | ||
272 | return err; | 272 | return err; |
273 | 273 | ||
diff --git a/litmus/litmus.c b/litmus/litmus.c index 84446acb0869..1105408e405a 100644 --- a/litmus/litmus.c +++ b/litmus/litmus.c | |||
@@ -343,15 +343,19 @@ asmlinkage long sys_reservation_destroy(unsigned int reservation_id, int cpu) | |||
343 | 343 | ||
344 | static unsigned long color_mask; | 344 | static unsigned long color_mask; |
345 | 345 | ||
346 | static inline unsigned long page_color(struct page *page) | ||
347 | { | ||
348 | return ((page_to_phys(page) & color_mask) >> PAGE_SHIFT); | ||
349 | } | ||
350 | |||
351 | extern int isolate_lru_page(struct page *page); | 346 | extern int isolate_lru_page(struct page *page); |
352 | extern void putback_movable_page(struct page *page); | 347 | extern void putback_movable_page(struct page *page); |
353 | extern struct page *new_alloc_page(struct page *page, unsigned long node, int **x); | 348 | extern struct page *new_alloc_page(struct page *page, unsigned long node, int **x); |
354 | 349 | ||
350 | static struct page *alloc_colored_page(struct page *page, unsigned long node, int **result) | ||
351 | { | ||
352 | struct page *newpage; | ||
353 | |||
354 | newpage = alloc_pages(GFP_HIGHUSER_MOVABLE|GFP_COLOR, 0); | ||
355 | |||
356 | return newpage; | ||
357 | } | ||
358 | |||
355 | #define INVALID_PFN (0xffffffff) | 359 | #define INVALID_PFN (0xffffffff) |
356 | LIST_HEAD(shared_lib_pages); | 360 | LIST_HEAD(shared_lib_pages); |
357 | 361 | ||
@@ -479,7 +483,7 @@ asmlinkage long sys_set_page_color(int cpu) | |||
479 | 483 | ||
480 | /* Migrate private pages */ | 484 | /* Migrate private pages */ |
481 | if (!list_empty(&pagelist)) { | 485 | if (!list_empty(&pagelist)) { |
482 | ret = migrate_pages(&pagelist, new_alloc_page, NULL, node, MIGRATE_SYNC, MR_SYSCALL); | 486 | ret = migrate_pages(&pagelist, alloc_colored_page, NULL, node, MIGRATE_SYNC, MR_SYSCALL); |
483 | TRACE_TASK(current, "%ld pages not migrated.\n", ret); | 487 | TRACE_TASK(current, "%ld pages not migrated.\n", ret); |
484 | nr_not_migrated = ret; | 488 | nr_not_migrated = ret; |
485 | if (ret) { | 489 | if (ret) { |
@@ -489,7 +493,7 @@ asmlinkage long sys_set_page_color(int cpu) | |||
489 | 493 | ||
490 | /* Replicate shared pages */ | 494 | /* Replicate shared pages */ |
491 | if (!list_empty(&task_shared_pagelist)) { | 495 | if (!list_empty(&task_shared_pagelist)) { |
492 | ret = replicate_pages(&task_shared_pagelist, new_alloc_page, NULL, node, MIGRATE_SYNC, MR_SYSCALL); | 496 | ret = replicate_pages(&task_shared_pagelist, alloc_colored_page, NULL, node, MIGRATE_SYNC, MR_SYSCALL); |
493 | TRACE_TASK(current, "%ld shared pages not migrated.\n", ret); | 497 | TRACE_TASK(current, "%ld shared pages not migrated.\n", ret); |
494 | nr_not_migrated += ret; | 498 | nr_not_migrated += ret; |
495 | if (ret) { | 499 | if (ret) { |
@@ -501,12 +505,27 @@ asmlinkage long sys_set_page_color(int cpu) | |||
501 | 505 | ||
502 | TRACE_TASK(current, "nr_pages = %d nr_failed = %d nr_not_migrated = %d\n", nr_pages, nr_failed, nr_not_migrated); | 506 | TRACE_TASK(current, "nr_pages = %d nr_failed = %d nr_not_migrated = %d\n", nr_pages, nr_failed, nr_not_migrated); |
503 | printk(KERN_INFO "node = %ld, nr_private_pages = %d, nr_shared_pages = %d, nr_failed_to_isolate_lru = %d, nr_not_migrated = %d\n", node, nr_pages, nr_shared_pages, nr_failed, nr_not_migrated); | 507 | printk(KERN_INFO "node = %ld, nr_private_pages = %d, nr_shared_pages = %d, nr_failed_to_isolate_lru = %d, nr_not_migrated = %d\n", node, nr_pages, nr_shared_pages, nr_failed, nr_not_migrated); |
504 | |||
505 | flush_cache(1); | ||
506 | 508 | ||
507 | return nr_not_migrated; | 509 | return nr_not_migrated; |
508 | } | 510 | } |
509 | 511 | ||
512 | #define BANK_MASK 0x38000000 | ||
513 | #define BANK_SHIFT 27 | ||
514 | #define CACHE_MASK 0x0000f000 | ||
515 | #define CACHE_SHIFT 12 | ||
516 | |||
517 | /* Decoding page color, 0~15 */ | ||
518 | static inline unsigned int page_color(struct page *page) | ||
519 | { | ||
520 | return ((page_to_phys(page)& CACHE_MASK) >> CACHE_SHIFT); | ||
521 | } | ||
522 | |||
523 | /* Decoding page bank number, 0~7 */ | ||
524 | static inline unsigned int page_bank(struct page *page) | ||
525 | { | ||
526 | return ((page_to_phys(page)& BANK_MASK) >> BANK_SHIFT); | ||
527 | } | ||
528 | |||
510 | /* sys_test_call() is a test system call for debugging */ | 529 | /* sys_test_call() is a test system call for debugging */ |
511 | asmlinkage long sys_test_call(unsigned int param) | 530 | asmlinkage long sys_test_call(unsigned int param) |
512 | { | 531 | { |
@@ -549,7 +568,7 @@ asmlinkage long sys_test_call(unsigned int param) | |||
549 | continue; | 568 | continue; |
550 | } | 569 | } |
551 | 570 | ||
552 | TRACE_TASK(current, "addr: %08x, phy: %08x, pfn: %05lx, _mapcount: %d, _count: %d flags: %s%s%s mapping: %p\n", vma_itr->vm_start + PAGE_SIZE*i, page_to_phys(old_page), page_to_pfn(old_page), page_mapcount(old_page), page_count(old_page), vma_itr->vm_flags&VM_READ?"r":"-", vma_itr->vm_flags&VM_WRITE?"w":"-", vma_itr->vm_flags&VM_EXEC?"x":"-", &(old_page->mapping)); | 571 | TRACE_TASK(current, "addr: %08x, phy: %08x, color: %d, bank: %d, pfn: %05lx, _mapcount: %d, _count: %d flags: %s%s%s mapping: %p\n", vma_itr->vm_start + PAGE_SIZE*i, page_to_phys(old_page), page_color(old_page), page_bank(old_page), page_to_pfn(old_page), page_mapcount(old_page), page_count(old_page), vma_itr->vm_flags&VM_READ?"r":"-", vma_itr->vm_flags&VM_WRITE?"w":"-", vma_itr->vm_flags&VM_EXEC?"x":"-", &(old_page->mapping)); |
553 | put_page(old_page); | 572 | put_page(old_page); |
554 | } | 573 | } |
555 | vma_itr = vma_itr->vm_next; | 574 | vma_itr = vma_itr->vm_next; |
diff --git a/litmus/page_dev.c b/litmus/page_dev.c index 1e91b989dae2..8e29e68ed89a 100644 --- a/litmus/page_dev.c +++ b/litmus/page_dev.c | |||
@@ -7,36 +7,90 @@ | |||
7 | 7 | ||
8 | #include <litmus/page_dev.h> | 8 | #include <litmus/page_dev.h> |
9 | 9 | ||
10 | #define NR_PARTITIONS 9 | 10 | // This Address Decoding is used in imx6-sabredsd platform |
11 | #define NUM_BANKS 8 | ||
12 | #define BANK_MASK 0x38000000 | ||
13 | #define BANK_SHIFT 27 | ||
14 | |||
15 | #define NUM_COLORS 16 | ||
16 | #define CACHE_MASK 0x0000f000 | ||
17 | #define CACHE_SHIFT 12 | ||
18 | |||
19 | #define NR_LLC_PARTITIONS 9 | ||
20 | #define NR_DRAM_PARTITIONS 5 | ||
11 | 21 | ||
12 | struct mutex dev_mutex; | 22 | struct mutex dev_mutex; |
13 | 23 | ||
14 | /* Initial partitions for LLC and DRAM bank */ | 24 | /* Initial partitions for LLC and DRAM bank */ |
15 | /* 4 color for each core, all colors for Level C */ | 25 | /* 4 color for each core, all colors for Level C */ |
16 | unsigned int llc_partition[NR_PARTITIONS] = { | 26 | unsigned int llc_partition[NR_LLC_PARTITIONS] = { |
17 | 0x00000003, /* Core 0, and Level A*/ | 27 | 0x0000000f, /* Core 0, and Level A*/ |
18 | 0x00000003, /* Core 0, and Level B*/ | 28 | 0x0000000f, /* Core 0, and Level B*/ |
19 | 0x0000000C, /* Core 1, and Level A*/ | 29 | 0x000000f0, /* Core 1, and Level A*/ |
20 | 0x0000000C, /* Core 1, and Level B*/ | 30 | 0x000000f0, /* Core 1, and Level B*/ |
21 | 0x00000030, /* Core 2, and Level A*/ | 31 | 0x00000f00, /* Core 2, and Level A*/ |
22 | 0x00000030, /* Core 2, and Level B*/ | 32 | 0x00000f00, /* Core 2, and Level B*/ |
23 | 0x000000C0, /* Core 3, and Level A*/ | 33 | 0x0000f000, /* Core 3, and Level A*/ |
24 | 0x000000C0, /* Core 3, and Level B*/ | 34 | 0x0000f000, /* Core 3, and Level B*/ |
25 | 0x0000ffff, /* Level C */ | 35 | 0x0000ffff, /* Level C */ |
26 | }; | 36 | }; |
27 | 37 | ||
28 | /* 1 bank for each core, 2 banks for Level C */ | 38 | /* 1 bank for each core, 2 banks for Level C */ |
29 | unsigned int dram_partition[NR_PARTITIONS] = { | 39 | unsigned int dram_partition[NR_DRAM_PARTITIONS] = { |
30 | 0x00000010, /* Core 0, and Level A*/ | 40 | 0x00000010, |
31 | 0x00000010, /* Core 0, and Level B*/ | 41 | 0x00000020, |
32 | 0x00000020, /* Core 1, and Level A*/ | 42 | 0x00000040, |
33 | 0x00000020, /* Core 1, and Level B*/ | 43 | 0x00000080, |
34 | 0x00000040, /* Core 2, and Level A*/ | 44 | 0x0000000f, |
35 | 0x00000040, /* Core 2, and Level B*/ | 45 | }; |
36 | 0x00000080, /* Core 3, and Level A*/ | 46 | /* |
37 | 0x00000080, /* Core 3, and Level B*/ | 47 | unsigned int dram_partition[NR_DRAM_PARTITIONS] = { |
38 | 0x0000000c, /* Level C */ | 48 | 0x00000001, |
49 | 0x00000002, | ||
50 | 0x00000004, | ||
51 | 0x00000008, | ||
52 | 0x000000f0, | ||
39 | }; | 53 | }; |
54 | */ | ||
55 | |||
56 | /* Decoding page color, 0~15 */ | ||
57 | static inline unsigned int page_color(struct page *page) | ||
58 | { | ||
59 | return ((page_to_phys(page)& CACHE_MASK) >> CACHE_SHIFT); | ||
60 | } | ||
61 | |||
62 | /* Decoding page bank number, 0~7 */ | ||
63 | static inline unsigned int page_bank(struct page *page) | ||
64 | { | ||
65 | return ((page_to_phys(page)& BANK_MASK) >> BANK_SHIFT); | ||
66 | } | ||
67 | |||
68 | int bank_to_partition(unsigned int bank) | ||
69 | { | ||
70 | int i; | ||
71 | unsigned int bank_bit = 0x1<<bank; | ||
72 | |||
73 | for (i = 0; i<NR_DRAM_PARTITIONS; i++) { | ||
74 | if (dram_partition[i] & bank_bit) | ||
75 | return i; | ||
76 | } | ||
77 | |||
78 | return -EINVAL; | ||
79 | } | ||
80 | |||
81 | int is_in_llc_partition(struct page* page, int cpu) | ||
82 | { | ||
83 | int color; | ||
84 | unsigned int page_color_bit; | ||
85 | |||
86 | color = page_color(page); | ||
87 | page_color_bit = 1 << color; | ||
88 | |||
89 | if (cpu == NR_CPUS) | ||
90 | return (page_color_bit&llc_partition[cpu*2]); | ||
91 | else | ||
92 | return (page_color_bit & (llc_partition[cpu*2] | llc_partition[cpu*2+1])); | ||
93 | } | ||
40 | 94 | ||
41 | /* Bounds for values */ | 95 | /* Bounds for values */ |
42 | unsigned int llc_partition_max = 0x0000ffff; | 96 | unsigned int llc_partition_max = 0x0000ffff; |
@@ -129,7 +183,7 @@ static struct ctl_table partition_table[] = | |||
129 | .extra2 = &llc_partition_max, | 183 | .extra2 = &llc_partition_max, |
130 | }, | 184 | }, |
131 | { | 185 | { |
132 | .procname = "C0_LA_dram", | 186 | .procname = "C0_dram", |
133 | .mode = 0666, | 187 | .mode = 0666, |
134 | .proc_handler = dram_partition_handler, | 188 | .proc_handler = dram_partition_handler, |
135 | .data = &dram_partition[0], | 189 | .data = &dram_partition[0], |
@@ -138,34 +192,34 @@ static struct ctl_table partition_table[] = | |||
138 | .extra2 = &dram_partition_max, | 192 | .extra2 = &dram_partition_max, |
139 | }, | 193 | }, |
140 | { | 194 | { |
141 | .procname = "C0_LB_dram", | 195 | .procname = "C1_dram", |
142 | .mode = 0666, | 196 | .mode = 0666, |
143 | .proc_handler = dram_partition_handler, | 197 | .proc_handler = dram_partition_handler, |
144 | .data = &dram_partition[1], | 198 | .data = &dram_partition[1], |
145 | .maxlen = sizeof(llc_partition[1]), | 199 | .maxlen = sizeof(llc_partition[1]), |
146 | .extra1 = &dram_partition_min, | 200 | .extra1 = &dram_partition_min, |
147 | .extra2 = &dram_partition_max, | 201 | .extra2 = &dram_partition_max, |
148 | }, | 202 | }, |
149 | { | 203 | { |
150 | .procname = "C1_LA_dram", | 204 | .procname = "C2_dram", |
151 | .mode = 0666, | 205 | .mode = 0666, |
152 | .proc_handler = dram_partition_handler, | 206 | .proc_handler = dram_partition_handler, |
153 | .data = &dram_partition[2], | 207 | .data = &dram_partition[2], |
154 | .maxlen = sizeof(llc_partition[2]), | 208 | .maxlen = sizeof(llc_partition[2]), |
155 | .extra1 = &dram_partition_min, | 209 | .extra1 = &dram_partition_min, |
156 | .extra2 = &dram_partition_max, | 210 | .extra2 = &dram_partition_max, |
157 | }, | 211 | }, |
158 | { | 212 | { |
159 | .procname = "C1_LB_dram", | 213 | .procname = "C3_dram", |
160 | .mode = 0666, | 214 | .mode = 0666, |
161 | .proc_handler = dram_partition_handler, | 215 | .proc_handler = dram_partition_handler, |
162 | .data = &dram_partition[3], | 216 | .data = &dram_partition[3], |
163 | .maxlen = sizeof(llc_partition[3]), | 217 | .maxlen = sizeof(llc_partition[3]), |
164 | .extra1 = &dram_partition_min, | 218 | .extra1 = &dram_partition_min, |
165 | .extra2 = &dram_partition_max, | 219 | .extra2 = &dram_partition_max, |
166 | }, | 220 | }, |
167 | { | 221 | { |
168 | .procname = "C2_LA_dram", | 222 | .procname = "CS_dram", |
169 | .mode = 0666, | 223 | .mode = 0666, |
170 | .proc_handler = dram_partition_handler, | 224 | .proc_handler = dram_partition_handler, |
171 | .data = &dram_partition[4], | 225 | .data = &dram_partition[4], |
@@ -173,42 +227,6 @@ static struct ctl_table partition_table[] = | |||
173 | .extra1 = &dram_partition_min, | 227 | .extra1 = &dram_partition_min, |
174 | .extra2 = &dram_partition_max, | 228 | .extra2 = &dram_partition_max, |
175 | }, | 229 | }, |
176 | { | ||
177 | .procname = "C2_LB_dram", | ||
178 | .mode = 0666, | ||
179 | .proc_handler = dram_partition_handler, | ||
180 | .data = &dram_partition[5], | ||
181 | .maxlen = sizeof(llc_partition[5]), | ||
182 | .extra1 = &dram_partition_min, | ||
183 | .extra2 = &dram_partition_max, | ||
184 | }, | ||
185 | { | ||
186 | .procname = "C3_LA_dram", | ||
187 | .mode = 0666, | ||
188 | .proc_handler = dram_partition_handler, | ||
189 | .data = &dram_partition[6], | ||
190 | .maxlen = sizeof(llc_partition[6]), | ||
191 | .extra1 = &dram_partition_min, | ||
192 | .extra2 = &dram_partition_max, | ||
193 | }, | ||
194 | { | ||
195 | .procname = "C3_LB_dram", | ||
196 | .mode = 0666, | ||
197 | .proc_handler = dram_partition_handler, | ||
198 | .data = &dram_partition[7], | ||
199 | .maxlen = sizeof(llc_partition[7]), | ||
200 | .extra1 = &dram_partition_min, | ||
201 | .extra2 = &dram_partition_max, | ||
202 | }, | ||
203 | { | ||
204 | .procname = "Call_LC_dram", | ||
205 | .mode = 0666, | ||
206 | .proc_handler = dram_partition_handler, | ||
207 | .data = &dram_partition[8], | ||
208 | .maxlen = sizeof(llc_partition[8]), | ||
209 | .extra1 = &dram_partition_min, | ||
210 | .extra2 = &dram_partition_max, | ||
211 | }, | ||
212 | { } | 230 | { } |
213 | }; | 231 | }; |
214 | 232 | ||
@@ -232,8 +250,8 @@ int llc_partition_handler(struct ctl_table *table, int write, void __user *buffe | |||
232 | goto out; | 250 | goto out; |
233 | if (write) { | 251 | if (write) { |
234 | printk("New LLC Partition : \n"); | 252 | printk("New LLC Partition : \n"); |
235 | for(i = 0; i < NR_PARTITIONS; i++) { | 253 | for(i = 0; i < NR_LLC_PARTITIONS; i++) { |
236 | printk("llc_partition[%d] = %x\n", i, llc_partition[i]); | 254 | printk("llc_partition[%d] = 0x%04x\n", i, llc_partition[i]); |
237 | } | 255 | } |
238 | } | 256 | } |
239 | out: | 257 | out: |
@@ -249,8 +267,8 @@ int dram_partition_handler(struct ctl_table *table, int write, void __user *buff | |||
249 | if (ret) | 267 | if (ret) |
250 | goto out; | 268 | goto out; |
251 | if (write) { | 269 | if (write) { |
252 | for(i = 0; i < NR_PARTITIONS; i++) { | 270 | for(i = 0; i < NR_DRAM_PARTITIONS; i++) { |
253 | printk("dram_partition[%d] = %x\n", i, dram_partition[i]); | 271 | printk("dram_partition[%d] = 0x%04x\n", i, dram_partition[i]); |
254 | } | 272 | } |
255 | } | 273 | } |
256 | out: | 274 | out: |
diff --git a/mm/page_alloc.c b/mm/page_alloc.c index ff2d2830e877..45cce6a34295 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c | |||
@@ -71,6 +71,26 @@ | |||
71 | #include <asm/div64.h> | 71 | #include <asm/div64.h> |
72 | #include "internal.h" | 72 | #include "internal.h" |
73 | 73 | ||
74 | // This Address Decoding is used in imx6-sabredsd platform | ||
75 | #define BANK_MASK 0x38000000 | ||
76 | #define BANK_SHIFT 27 | ||
77 | |||
78 | #define CACHE_MASK 0x0000f000 | ||
79 | #define CACHE_SHIFT 12 | ||
80 | #define MAX_COLOR_NODE 128 | ||
81 | |||
82 | /* Decoding page color, 0~15 */ | ||
83 | static inline unsigned int page_color(struct page *page) | ||
84 | { | ||
85 | return ((page_to_phys(page)& CACHE_MASK) >> CACHE_SHIFT); | ||
86 | } | ||
87 | |||
88 | /* Decoding page bank number, 0~7 */ | ||
89 | static inline unsigned int page_bank(struct page *page) | ||
90 | { | ||
91 | return ((page_to_phys(page)& BANK_MASK) >> BANK_SHIFT); | ||
92 | } | ||
93 | |||
74 | /* prevent >1 _updater_ of zone percpu pageset ->high and ->batch fields */ | 94 | /* prevent >1 _updater_ of zone percpu pageset ->high and ->batch fields */ |
75 | static DEFINE_MUTEX(pcp_batch_high_lock); | 95 | static DEFINE_MUTEX(pcp_batch_high_lock); |
76 | #define MIN_PERCPU_PAGELIST_FRACTION (8) | 96 | #define MIN_PERCPU_PAGELIST_FRACTION (8) |
@@ -583,76 +603,153 @@ static inline void __free_one_page(struct page *page, | |||
583 | unsigned long combined_idx; | 603 | unsigned long combined_idx; |
584 | unsigned long uninitialized_var(buddy_idx); | 604 | unsigned long uninitialized_var(buddy_idx); |
585 | struct page *buddy; | 605 | struct page *buddy; |
586 | int max_order = MAX_ORDER; | 606 | int max_order, parti_no; |
607 | |||
608 | parti_no = bank_to_partition(page_bank(page)); | ||
609 | BUG_ON(parti_no < 0 || parti_no > NR_CPUS); | ||
610 | if (parti_no < 0 || parti_no > NR_CPUS) | ||
611 | printk(KERN_ALERT "PART_NO %d\n", parti_no); | ||
612 | |||
613 | if (parti_no < NR_CPUS) | ||
614 | printk(KERN_ALERT "pfn = %lx, part_no = %d order = %d\n", pfn, parti_no, order); | ||
615 | |||
616 | if (parti_no == NR_CPUS) { | ||
617 | max_order = MAX_ORDER; | ||
618 | |||
619 | VM_BUG_ON(!zone_is_initialized(zone)); | ||
620 | VM_BUG_ON_PAGE(page->flags & PAGE_FLAGS_CHECK_AT_PREP, page); | ||
621 | |||
622 | VM_BUG_ON(migratetype == -1); | ||
623 | if (is_migrate_isolate(migratetype)) { | ||
624 | /* | ||
625 | * We restrict max order of merging to prevent merge | ||
626 | * between freepages on isolate pageblock and normal | ||
627 | * pageblock. Without this, pageblock isolation | ||
628 | * could cause incorrect freepage accounting. | ||
629 | */ | ||
630 | max_order = min(MAX_ORDER, pageblock_order + 1); | ||
631 | } else { | ||
632 | __mod_zone_freepage_state(zone, 1 << order, migratetype); | ||
633 | } | ||
587 | 634 | ||
588 | VM_BUG_ON(!zone_is_initialized(zone)); | 635 | page_idx = pfn & ((1 << max_order) - 1); |
589 | VM_BUG_ON_PAGE(page->flags & PAGE_FLAGS_CHECK_AT_PREP, page); | 636 | |
637 | VM_BUG_ON_PAGE(page_idx & ((1 << order) - 1), page); | ||
638 | VM_BUG_ON_PAGE(bad_range(zone, page), page); | ||
639 | |||
640 | while (order < max_order - 1) { | ||
641 | buddy_idx = __find_buddy_index(page_idx, order); | ||
642 | buddy = page + (buddy_idx - page_idx); | ||
643 | if (!page_is_buddy(page, buddy, order)) | ||
644 | break; | ||
645 | /* | ||
646 | * Our buddy is free or it is CONFIG_DEBUG_PAGEALLOC guard page, | ||
647 | * merge with it and move up one order. | ||
648 | */ | ||
649 | if (page_is_guard(buddy)) { | ||
650 | clear_page_guard(zone, buddy, order, migratetype); | ||
651 | } else { | ||
652 | list_del(&buddy->lru); | ||
653 | zone->free_area[order].nr_free--; | ||
654 | rmv_page_order(buddy); | ||
655 | } | ||
656 | combined_idx = buddy_idx & page_idx; | ||
657 | page = page + (combined_idx - page_idx); | ||
658 | page_idx = combined_idx; | ||
659 | order++; | ||
660 | } | ||
661 | set_page_order(page, order); | ||
590 | 662 | ||
591 | VM_BUG_ON(migratetype == -1); | ||
592 | if (is_migrate_isolate(migratetype)) { | ||
593 | /* | 663 | /* |
594 | * We restrict max order of merging to prevent merge | 664 | * If this is not the largest possible page, check if the buddy |
595 | * between freepages on isolate pageblock and normal | 665 | * of the next-highest order is free. If it is, it's possible |
596 | * pageblock. Without this, pageblock isolation | 666 | * that pages are being freed that will coalesce soon. In case, |
597 | * could cause incorrect freepage accounting. | 667 | * that is happening, add the free page to the tail of the list |
668 | * so it's less likely to be used soon and more likely to be merged | ||
669 | * as a higher order page | ||
598 | */ | 670 | */ |
599 | max_order = min(MAX_ORDER, pageblock_order + 1); | 671 | if ((order < MAX_ORDER-2) && pfn_valid_within(page_to_pfn(buddy))) { |
600 | } else { | 672 | struct page *higher_page, *higher_buddy; |
601 | __mod_zone_freepage_state(zone, 1 << order, migratetype); | 673 | combined_idx = buddy_idx & page_idx; |
602 | } | 674 | higher_page = page + (combined_idx - page_idx); |
675 | buddy_idx = __find_buddy_index(combined_idx, order + 1); | ||
676 | higher_buddy = higher_page + (buddy_idx - combined_idx); | ||
677 | if (page_is_buddy(higher_page, higher_buddy, order + 1)) { | ||
678 | list_add_tail(&page->lru, | ||
679 | &zone->free_area[order].free_list[migratetype]); | ||
680 | goto out; | ||
681 | } | ||
682 | } | ||
603 | 683 | ||
604 | page_idx = pfn & ((1 << max_order) - 1); | 684 | list_add(&page->lru, &zone->free_area[order].free_list[migratetype]); |
685 | out: | ||
686 | zone->free_area[order].nr_free++; | ||
687 | } else { | ||
688 | max_order = MAX_PARTITIONED_ORDER; | ||
605 | 689 | ||
606 | VM_BUG_ON_PAGE(page_idx & ((1 << order) - 1), page); | 690 | VM_BUG_ON(!zone_is_initialized(zone)); |
607 | VM_BUG_ON_PAGE(bad_range(zone, page), page); | 691 | VM_BUG_ON_PAGE(page->flags & PAGE_FLAGS_CHECK_AT_PREP, page); |
608 | 692 | ||
609 | while (order < max_order - 1) { | 693 | VM_BUG_ON(migratetype == -1); |
610 | buddy_idx = __find_buddy_index(page_idx, order); | 694 | if (is_migrate_isolate(migratetype)) { |
611 | buddy = page + (buddy_idx - page_idx); | 695 | max_order = min(MAX_PARTITIONED_ORDER, pageblock_order + 1); |
612 | if (!page_is_buddy(page, buddy, order)) | ||
613 | break; | ||
614 | /* | ||
615 | * Our buddy is free or it is CONFIG_DEBUG_PAGEALLOC guard page, | ||
616 | * merge with it and move up one order. | ||
617 | */ | ||
618 | if (page_is_guard(buddy)) { | ||
619 | clear_page_guard(zone, buddy, order, migratetype); | ||
620 | } else { | 696 | } else { |
621 | list_del(&buddy->lru); | 697 | __mod_zone_freepage_state(zone, 1 << order, migratetype); |
622 | zone->free_area[order].nr_free--; | ||
623 | rmv_page_order(buddy); | ||
624 | } | 698 | } |
625 | combined_idx = buddy_idx & page_idx; | ||
626 | page = page + (combined_idx - page_idx); | ||
627 | page_idx = combined_idx; | ||
628 | order++; | ||
629 | } | ||
630 | set_page_order(page, order); | ||
631 | 699 | ||
632 | /* | 700 | page_idx = pfn & ((1 << max_order) - 1); |
633 | * If this is not the largest possible page, check if the buddy | 701 | |
634 | * of the next-highest order is free. If it is, it's possible | 702 | VM_BUG_ON_PAGE(page_idx & ((1 << order) - 1), page); |
635 | * that pages are being freed that will coalesce soon. In case, | 703 | VM_BUG_ON_PAGE(bad_range(zone, page), page); |
636 | * that is happening, add the free page to the tail of the list | 704 | |
637 | * so it's less likely to be used soon and more likely to be merged | 705 | while (order < max_order - 1) { |
638 | * as a higher order page | 706 | buddy_idx = __find_buddy_index(page_idx, order); |
639 | */ | 707 | buddy = page + (buddy_idx - page_idx); |
640 | if ((order < MAX_ORDER-2) && pfn_valid_within(page_to_pfn(buddy))) { | 708 | if (!page_is_buddy(page, buddy, order)) |
641 | struct page *higher_page, *higher_buddy; | 709 | break; |
642 | combined_idx = buddy_idx & page_idx; | 710 | |
643 | higher_page = page + (combined_idx - page_idx); | 711 | if (page_is_guard(buddy)) { |
644 | buddy_idx = __find_buddy_index(combined_idx, order + 1); | 712 | clear_page_guard(zone, buddy, order, migratetype); |
645 | higher_buddy = higher_page + (buddy_idx - combined_idx); | 713 | } else { |
646 | if (page_is_buddy(higher_page, higher_buddy, order + 1)) { | 714 | list_del(&buddy->lru); |
647 | list_add_tail(&page->lru, | 715 | zone->free_area_d[parti_no][order].nr_free--; |
648 | &zone->free_area[order].free_list[migratetype]); | 716 | rmv_page_order(buddy); |
649 | goto out; | 717 | } |
718 | combined_idx = buddy_idx & page_idx; | ||
719 | page = page + (combined_idx - page_idx); | ||
720 | page_idx = combined_idx; | ||
721 | order++; | ||
722 | } | ||
723 | set_page_order(page, order); | ||
724 | |||
725 | if ((order < MAX_PARTITIONED_ORDER-2) && pfn_valid_within(page_to_pfn(buddy))) { | ||
726 | struct page *higher_page, *higher_buddy; | ||
727 | combined_idx = buddy_idx & page_idx; | ||
728 | higher_page = page + (combined_idx - page_idx); | ||
729 | buddy_idx = __find_buddy_index(combined_idx, order + 1); | ||
730 | higher_buddy = higher_page + (buddy_idx - combined_idx); | ||
731 | if (page_is_buddy(higher_page, higher_buddy, order + 1)) { | ||
732 | list_add_tail(&page->lru, | ||
733 | &zone->free_area_d[parti_no][order].free_list[migratetype]); | ||
734 | zone->free_area_d[parti_no][order].nr_free++; | ||
735 | return; | ||
736 | } | ||
650 | } | 737 | } |
651 | } | ||
652 | 738 | ||
653 | list_add(&page->lru, &zone->free_area[order].free_list[migratetype]); | 739 | if (order >= MAX_PARTITIONED_ORDER) { |
654 | out: | 740 | int n_idx = 0; |
655 | zone->free_area[order].nr_free++; | 741 | struct page *lower_page; |
742 | for (n_idx = 0 ; n_idx < (1 << (order - MAX_PARTITIONED_ORDER + 1)); n_idx++) { | ||
743 | lower_page = page + (n_idx << (MAX_PARTITIONED_ORDER - 1)); | ||
744 | set_page_order(lower_page, MAX_PARTITIONED_ORDER-1); | ||
745 | list_add(&lower_page->lru, &zone->free_area_d[parti_no][MAX_PARTITIONED_ORDER-1].free_list[migratetype]); | ||
746 | zone->free_area_d[parti_no][MAX_PARTITIONED_ORDER-1].nr_free++; | ||
747 | } | ||
748 | } else { | ||
749 | list_add(&page->lru, &zone->free_area_d[parti_no][order].free_list[migratetype]); | ||
750 | zone->free_area_d[parti_no][order].nr_free++; | ||
751 | } | ||
752 | } | ||
656 | } | 753 | } |
657 | 754 | ||
658 | static inline int free_pages_check(struct page *page) | 755 | static inline int free_pages_check(struct page *page) |
@@ -997,34 +1094,140 @@ static int prep_new_page(struct page *page, unsigned int order, gfp_t gfp_flags, | |||
997 | return 0; | 1094 | return 0; |
998 | } | 1095 | } |
999 | 1096 | ||
1097 | /* Kernel page coloring */ | ||
1098 | |||
1099 | /* build colored page list */ | ||
1100 | static void build_colored_pages(struct zone *zone, struct page *page, int order) | ||
1101 | { | ||
1102 | int i, color, bank; | ||
1103 | |||
1104 | list_del(&page->lru); | ||
1105 | zone->free_area[order].nr_free--; | ||
1106 | |||
1107 | /* insert pages to zone->color_list[] */ | ||
1108 | for (i = 0; i < (1<<order); i++) { | ||
1109 | int node; | ||
1110 | color = page_color(&page[i]); | ||
1111 | bank = page_bank(&page[i]); | ||
1112 | node = bank*MAX_NUM_COLOR+color; | ||
1113 | |||
1114 | INIT_LIST_HEAD(&page[i].lru); | ||
1115 | list_add_tail(&page[i].lru, &zone->color_list[node]); | ||
1116 | bitmap_set(zone->color_map, node, 1); | ||
1117 | zone->free_area[0].nr_free++; | ||
1118 | rmv_page_order(&page[i]); | ||
1119 | } | ||
1120 | } | ||
1121 | |||
1122 | int color_seq_index[9] = { | ||
1123 | 0, /* Core 0, and Level A*/ | ||
1124 | 0, /* Core 0, and Level B*/ | ||
1125 | 0, /* Core 1, and Level A*/ | ||
1126 | 0, /* Core 1, and Level B*/ | ||
1127 | 0, /* Core 2, and Level A*/ | ||
1128 | 0, /* Core 2, and Level B*/ | ||
1129 | 0, /* Core 3, and Level A*/ | ||
1130 | 0, /* Core 3, and Level B*/ | ||
1131 | 0, /* Level C */ | ||
1132 | }; | ||
1133 | |||
1134 | /* return a colored page */ | ||
1135 | static inline struct page *get_colored_page(struct zone *zone, unsigned long req_color_map[BITS_TO_LONGS(MAX_COLOR_NODE)], int order, int partition) | ||
1136 | { | ||
1137 | struct page *page; | ||
1138 | unsigned int color, bank, index; | ||
1139 | int i; | ||
1140 | DECLARE_BITMAP(candidate_bit, MAX_COLOR_NODE); | ||
1141 | |||
1142 | /* if req_color_map does not exist in zone, return NULL */ | ||
1143 | if (!bitmap_intersects(zone->color_map, req_color_map, MAX_COLOR_NODE)) | ||
1144 | return NULL; | ||
1145 | |||
1146 | bitmap_and(candidate_bit, zone->color_map, req_color_map, MAX_COLOR_NODE); | ||
1147 | index = color_seq_index[partition]; | ||
1148 | |||
1149 | for_each_set_bit(i, candidate_bit, MAX_COLOR_NODE) { | ||
1150 | if (index-- <= 0) | ||
1151 | break; | ||
1152 | } | ||
1153 | |||
1154 | BUG_ON(i >= MAX_COLOR_NODE); | ||
1155 | BUG_ON(list_empty(&zone->color_list[i])); | ||
1156 | |||
1157 | page = list_entry(zone->color_list[i].next, struct page, lru); | ||
1158 | |||
1159 | list_del(&page->lru); | ||
1160 | |||
1161 | if (list_empty(&zone->color_list[i])) | ||
1162 | bitmap_clear(zone->color_map, i, 1); | ||
1163 | |||
1164 | zone->free_area[0].nr_free--; | ||
1165 | color = page_color(page); | ||
1166 | bank = page_bank(page); | ||
1167 | printk(KERN_INFO "color=%d, bank=%d allocated\n", color, bank); | ||
1168 | return page; | ||
1169 | } | ||
1170 | |||
1000 | /* | 1171 | /* |
1001 | * Go through the free lists for the given migratetype and remove | 1172 | * Go through the free lists for the given migratetype and remove |
1002 | * the smallest available page from the freelists | 1173 | * the smallest available page from the freelists |
1003 | */ | 1174 | */ |
1004 | static inline | 1175 | static inline |
1005 | struct page *__rmqueue_smallest(struct zone *zone, unsigned int order, | 1176 | struct page *__rmqueue_smallest(struct zone *zone, unsigned int order, |
1006 | int migratetype) | 1177 | int migratetype, int color_req) |
1007 | { | 1178 | { |
1008 | unsigned int current_order; | 1179 | unsigned int current_order; |
1009 | struct free_area *area; | 1180 | struct free_area *area; |
1010 | struct page *page; | 1181 | struct page *page; |
1182 | int cpu = raw_smp_processor_id(); | ||
1183 | |||
1184 | if (order == 0 && color_req == 1) { | ||
1185 | int found = 0; | ||
1186 | /* Colored page request with order = 0 */ | ||
1187 | if (is_realtime(current)) | ||
1188 | printk(KERN_INFO "COLORED PAGE IS REQUESTED on CPU%d\n", cpu); | ||
1189 | /* Find a page of the appropriate size in the preferred list */ | ||
1190 | for (current_order = order; current_order < MAX_PARTITIONED_ORDER; ++current_order) { | ||
1191 | area = &(zone->free_area_d[cpu][current_order]); | ||
1192 | if (list_empty(&area->free_list[migratetype])) | ||
1193 | continue; | ||
1194 | |||
1195 | page = list_entry(area->free_list[migratetype].next, | ||
1196 | struct page, lru); | ||
1197 | if (is_in_llc_partition(page, cpu)) | ||
1198 | found = 1; | ||
1199 | |||
1200 | while(!found) { | ||
1201 | page = list_next_entry(page, lru); | ||
1202 | if (is_in_llc_partition(page, cpu)) | ||
1203 | found = 1; | ||
1204 | } | ||
1205 | list_del(&page->lru); | ||
1206 | rmv_page_order(page); | ||
1207 | area->nr_free--; | ||
1208 | expand(zone, page, order, current_order, area, migratetype); | ||
1209 | set_freepage_migratetype(page, migratetype); | ||
1210 | return page; | ||
1211 | } | ||
1212 | } else { | ||
1213 | /* Buddy allocator */ | ||
1214 | /* Find a page of the appropriate size in the preferred list */ | ||
1215 | for (current_order = order; current_order < MAX_ORDER; ++current_order) { | ||
1216 | area = &(zone->free_area[current_order]); | ||
1217 | if (list_empty(&area->free_list[migratetype])) | ||
1218 | continue; | ||
1011 | 1219 | ||
1012 | /* Find a page of the appropriate size in the preferred list */ | 1220 | page = list_entry(area->free_list[migratetype].next, |
1013 | for (current_order = order; current_order < MAX_ORDER; ++current_order) { | 1221 | struct page, lru); |
1014 | area = &(zone->free_area[current_order]); | 1222 | list_del(&page->lru); |
1015 | if (list_empty(&area->free_list[migratetype])) | 1223 | rmv_page_order(page); |
1016 | continue; | 1224 | area->nr_free--; |
1017 | 1225 | expand(zone, page, order, current_order, area, migratetype); | |
1018 | page = list_entry(area->free_list[migratetype].next, | 1226 | set_freepage_migratetype(page, migratetype); |
1019 | struct page, lru); | 1227 | return page; |
1020 | list_del(&page->lru); | 1228 | } |
1021 | rmv_page_order(page); | ||
1022 | area->nr_free--; | ||
1023 | expand(zone, page, order, current_order, area, migratetype); | ||
1024 | set_freepage_migratetype(page, migratetype); | ||
1025 | return page; | ||
1026 | } | 1229 | } |
1027 | 1230 | ||
1028 | return NULL; | 1231 | return NULL; |
1029 | } | 1232 | } |
1030 | 1233 | ||
@@ -1050,7 +1253,7 @@ static int fallbacks[MIGRATE_TYPES][4] = { | |||
1050 | static struct page *__rmqueue_cma_fallback(struct zone *zone, | 1253 | static struct page *__rmqueue_cma_fallback(struct zone *zone, |
1051 | unsigned int order) | 1254 | unsigned int order) |
1052 | { | 1255 | { |
1053 | return __rmqueue_smallest(zone, order, MIGRATE_CMA); | 1256 | return __rmqueue_smallest(zone, order, MIGRATE_CMA, 0); |
1054 | } | 1257 | } |
1055 | #else | 1258 | #else |
1056 | static inline struct page *__rmqueue_cma_fallback(struct zone *zone, | 1259 | static inline struct page *__rmqueue_cma_fallback(struct zone *zone, |
@@ -1291,12 +1494,12 @@ __rmqueue_fallback(struct zone *zone, unsigned int order, int start_migratetype) | |||
1291 | * Call me with the zone->lock already held. | 1494 | * Call me with the zone->lock already held. |
1292 | */ | 1495 | */ |
1293 | static struct page *__rmqueue(struct zone *zone, unsigned int order, | 1496 | static struct page *__rmqueue(struct zone *zone, unsigned int order, |
1294 | int migratetype) | 1497 | int migratetype, int color_req) |
1295 | { | 1498 | { |
1296 | struct page *page; | 1499 | struct page *page; |
1297 | 1500 | ||
1298 | retry_reserve: | 1501 | retry_reserve: |
1299 | page = __rmqueue_smallest(zone, order, migratetype); | 1502 | page = __rmqueue_smallest(zone, order, migratetype, color_req); |
1300 | 1503 | ||
1301 | if (unlikely(!page) && migratetype != MIGRATE_RESERVE) { | 1504 | if (unlikely(!page) && migratetype != MIGRATE_RESERVE) { |
1302 | if (migratetype == MIGRATE_MOVABLE) | 1505 | if (migratetype == MIGRATE_MOVABLE) |
@@ -1333,7 +1536,7 @@ static int rmqueue_bulk(struct zone *zone, unsigned int order, | |||
1333 | 1536 | ||
1334 | spin_lock(&zone->lock); | 1537 | spin_lock(&zone->lock); |
1335 | for (i = 0; i < count; ++i) { | 1538 | for (i = 0; i < count; ++i) { |
1336 | struct page *page = __rmqueue(zone, order, migratetype); | 1539 | struct page *page = __rmqueue(zone, order, migratetype, 1); |
1337 | if (unlikely(page == NULL)) | 1540 | if (unlikely(page == NULL)) |
1338 | break; | 1541 | break; |
1339 | 1542 | ||
@@ -1543,6 +1746,8 @@ void free_hot_cold_page(struct page *page, bool cold) | |||
1543 | unsigned long flags; | 1746 | unsigned long flags; |
1544 | unsigned long pfn = page_to_pfn(page); | 1747 | unsigned long pfn = page_to_pfn(page); |
1545 | int migratetype; | 1748 | int migratetype; |
1749 | unsigned int cpu; | ||
1750 | int is_local, is_in_pcp; | ||
1546 | 1751 | ||
1547 | if (!free_pages_prepare(page, 0)) | 1752 | if (!free_pages_prepare(page, 0)) |
1548 | return; | 1753 | return; |
@@ -1566,19 +1771,33 @@ void free_hot_cold_page(struct page *page, bool cold) | |||
1566 | } | 1771 | } |
1567 | migratetype = MIGRATE_MOVABLE; | 1772 | migratetype = MIGRATE_MOVABLE; |
1568 | } | 1773 | } |
1569 | 1774 | ||
1570 | pcp = &this_cpu_ptr(zone->pageset)->pcp; | 1775 | cpu = bank_to_partition(page_bank(page)); |
1571 | if (!cold) | 1776 | BUG_ON(cpu<0); |
1572 | list_add(&page->lru, &pcp->lists[migratetype]); | 1777 | |
1778 | if (cpu == smp_processor_id()) | ||
1779 | is_local = 1; | ||
1573 | else | 1780 | else |
1574 | list_add_tail(&page->lru, &pcp->lists[migratetype]); | 1781 | is_local = 0; |
1575 | pcp->count++; | 1782 | |
1576 | if (pcp->count >= pcp->high) { | 1783 | is_in_pcp = is_in_llc_partition(page, smp_processor_id()); |
1577 | unsigned long batch = READ_ONCE(pcp->batch); | 1784 | if (cpu != NR_CPUS) |
1578 | free_pcppages_bulk(zone, batch, pcp); | 1785 | printk(KERN_ALERT "CPU%d Free order-0 page bank = %d, color = %d, is_local %d is_in_pcp %d\n", smp_processor_id(), page_bank(page), page_color(page), is_local, is_in_pcp); |
1579 | pcp->count -= batch; | 1786 | if (is_local && is_in_pcp) { |
1787 | pcp = &this_cpu_ptr(zone->pageset)->pcp; | ||
1788 | if (!cold) | ||
1789 | list_add(&page->lru, &pcp->lists[migratetype]); | ||
1790 | else | ||
1791 | list_add_tail(&page->lru, &pcp->lists[migratetype]); | ||
1792 | pcp->count++; | ||
1793 | if (pcp->count >= pcp->high) { | ||
1794 | unsigned long batch = READ_ONCE(pcp->batch); | ||
1795 | free_pcppages_bulk(zone, batch, pcp); | ||
1796 | pcp->count -= batch; | ||
1797 | } | ||
1798 | } else { | ||
1799 | __free_page(page); | ||
1580 | } | 1800 | } |
1581 | |||
1582 | out: | 1801 | out: |
1583 | local_irq_restore(flags); | 1802 | local_irq_restore(flags); |
1584 | } | 1803 | } |
@@ -1706,8 +1925,9 @@ struct page *buffered_rmqueue(struct zone *preferred_zone, | |||
1706 | unsigned long flags; | 1925 | unsigned long flags; |
1707 | struct page *page; | 1926 | struct page *page; |
1708 | bool cold = ((gfp_flags & __GFP_COLD) != 0); | 1927 | bool cold = ((gfp_flags & __GFP_COLD) != 0); |
1709 | 1928 | bool colored_req = ((gfp_flags & __GFP_COLOR) != 0); | |
1710 | if (likely(order == 0)) { | 1929 | |
1930 | if (likely(order == 0) && colored_req) { | ||
1711 | struct per_cpu_pages *pcp; | 1931 | struct per_cpu_pages *pcp; |
1712 | struct list_head *list; | 1932 | struct list_head *list; |
1713 | 1933 | ||
@@ -1744,7 +1964,7 @@ struct page *buffered_rmqueue(struct zone *preferred_zone, | |||
1744 | WARN_ON_ONCE(order > 1); | 1964 | WARN_ON_ONCE(order > 1); |
1745 | } | 1965 | } |
1746 | spin_lock_irqsave(&zone->lock, flags); | 1966 | spin_lock_irqsave(&zone->lock, flags); |
1747 | page = __rmqueue(zone, order, migratetype); | 1967 | page = __rmqueue(zone, order, migratetype, 0); |
1748 | spin_unlock(&zone->lock); | 1968 | spin_unlock(&zone->lock); |
1749 | if (!page) | 1969 | if (!page) |
1750 | goto failed; | 1970 | goto failed; |
@@ -4231,10 +4451,23 @@ void __meminit memmap_init_zone(unsigned long size, int nid, unsigned long zone, | |||
4231 | static void __meminit zone_init_free_lists(struct zone *zone) | 4451 | static void __meminit zone_init_free_lists(struct zone *zone) |
4232 | { | 4452 | { |
4233 | unsigned int order, t; | 4453 | unsigned int order, t; |
4454 | int cpu; | ||
4455 | |||
4234 | for_each_migratetype_order(order, t) { | 4456 | for_each_migratetype_order(order, t) { |
4235 | INIT_LIST_HEAD(&zone->free_area[order].free_list[t]); | 4457 | INIT_LIST_HEAD(&zone->free_area[order].free_list[t]); |
4236 | zone->free_area[order].nr_free = 0; | 4458 | zone->free_area[order].nr_free = 0; |
4237 | } | 4459 | } |
4460 | |||
4461 | /* Initialize per-partition free_area data structures */ | ||
4462 | for (cpu = 0; cpu < NR_CPUS; cpu++) { | ||
4463 | for (order = 0; order < MAX_PARTITIONED_ORDER; order++) { | ||
4464 | for (t = 0; t < MIGRATE_TYPES; t++) { | ||
4465 | INIT_LIST_HEAD(&zone->free_area_d[cpu][order].free_list[t]); | ||
4466 | zone->free_area_d[cpu][order].nr_free = 0; | ||
4467 | printk(KERN_ALERT "free_area_d[%d][%d].free_list[%d] init.\n", cpu, order, t); | ||
4468 | } | ||
4469 | } | ||
4470 | } | ||
4238 | } | 4471 | } |
4239 | 4472 | ||
4240 | #ifndef __HAVE_ARCH_MEMMAP_INIT | 4473 | #ifndef __HAVE_ARCH_MEMMAP_INIT |
diff --git a/mm/vmstat.c b/mm/vmstat.c index 4f5cd974e11a..4bbf65f7335b 100644 --- a/mm/vmstat.c +++ b/mm/vmstat.c | |||
@@ -956,6 +956,67 @@ static void pagetypeinfo_showfree_print(struct seq_file *m, | |||
956 | } | 956 | } |
957 | } | 957 | } |
958 | 958 | ||
959 | static void pagetypeinfo_showpartitionfree_print(struct seq_file *m, | ||
960 | pg_data_t *pgdat, struct zone *zone, int cpu) | ||
961 | { | ||
962 | int order, mtype; | ||
963 | |||
964 | for (mtype = 0; mtype < MIGRATE_TYPES; mtype++) { | ||
965 | seq_printf(m, "Node %4d, zone %8s, type %12s ", | ||
966 | pgdat->node_id, | ||
967 | zone->name, | ||
968 | migratetype_names[mtype]); | ||
969 | for (order = 0; order < MAX_PARTITIONED_ORDER; ++order) { | ||
970 | unsigned long freecount = 0; | ||
971 | struct free_area *area; | ||
972 | struct list_head *curr; | ||
973 | |||
974 | area = &(zone->free_area_d[cpu][order]); | ||
975 | |||
976 | list_for_each(curr, &area->free_list[mtype]) | ||
977 | freecount++; | ||
978 | seq_printf(m, "%6lu ", freecount); | ||
979 | } | ||
980 | seq_putc(m, '\n'); | ||
981 | } | ||
982 | } | ||
983 | |||
984 | static void walk_zones_in_node_in_partition(struct seq_file *m, pg_data_t *pgdat, | ||
985 | int cpu, void (*print)(struct seq_file *m, pg_data_t *, struct zone *, int)) | ||
986 | { | ||
987 | struct zone *zone; | ||
988 | struct zone *node_zones = pgdat->node_zones; | ||
989 | unsigned long flags; | ||
990 | |||
991 | for (zone = node_zones; zone - node_zones < MAX_NR_ZONES; ++zone) { | ||
992 | if (!populated_zone(zone)) | ||
993 | continue; | ||
994 | |||
995 | spin_lock_irqsave(&zone->lock, flags); | ||
996 | print(m, pgdat, zone, cpu); | ||
997 | spin_unlock_irqrestore(&zone->lock, flags); | ||
998 | } | ||
999 | } | ||
1000 | |||
1001 | /* Print out the free pages at each order for each migatetype and partition */ | ||
1002 | static int pagetypeinfo_showpartitioned(struct seq_file *m, void *arg) | ||
1003 | { | ||
1004 | int order, cpu; | ||
1005 | pg_data_t *pgdat = (pg_data_t *)arg; | ||
1006 | |||
1007 | for_each_online_cpu(cpu) { | ||
1008 | /* Print header */ | ||
1009 | seq_putc(m, '\n'); | ||
1010 | seq_printf(m, "CPU%d %-43s ", cpu, "free pages count per migrate type at order"); | ||
1011 | for (order = 0; order < MAX_PARTITIONED_ORDER; ++order) | ||
1012 | seq_printf(m, "%6d ", order); | ||
1013 | seq_putc(m, '\n'); | ||
1014 | |||
1015 | walk_zones_in_node_in_partition(m, pgdat, cpu, pagetypeinfo_showpartitionfree_print); | ||
1016 | } | ||
1017 | return 0; | ||
1018 | } | ||
1019 | |||
959 | /* Print out the free pages at each order for each migatetype */ | 1020 | /* Print out the free pages at each order for each migatetype */ |
960 | static int pagetypeinfo_showfree(struct seq_file *m, void *arg) | 1021 | static int pagetypeinfo_showfree(struct seq_file *m, void *arg) |
961 | { | 1022 | { |
@@ -1138,7 +1199,7 @@ static int pagetypeinfo_show(struct seq_file *m, void *arg) | |||
1138 | pagetypeinfo_showfree(m, pgdat); | 1199 | pagetypeinfo_showfree(m, pgdat); |
1139 | pagetypeinfo_showblockcount(m, pgdat); | 1200 | pagetypeinfo_showblockcount(m, pgdat); |
1140 | pagetypeinfo_showmixedcount(m, pgdat); | 1201 | pagetypeinfo_showmixedcount(m, pgdat); |
1141 | 1202 | pagetypeinfo_showpartitioned(m, pgdat); | |
1142 | return 0; | 1203 | return 0; |
1143 | } | 1204 | } |
1144 | 1205 | ||
@@ -1180,10 +1241,27 @@ static const struct file_operations pagetypeinfo_file_ops = { | |||
1180 | .release = seq_release, | 1241 | .release = seq_release, |
1181 | }; | 1242 | }; |
1182 | 1243 | ||
1244 | #define BANK_MASK 0x38000000 | ||
1245 | #define BANK_SHIFT 27 | ||
1246 | #define CACHE_MASK 0x0000f000 | ||
1247 | #define CACHE_SHIFT 12 | ||
1248 | /* Decoding page bank number, 0~7 */ | ||
1249 | static inline unsigned int page_bank(struct page *page) | ||
1250 | { | ||
1251 | return ((page_to_phys(page)& BANK_MASK) >> BANK_SHIFT); | ||
1252 | } | ||
1253 | /* Decoding page color, 0~15 */ | ||
1254 | static inline unsigned int page_color(struct page *page) | ||
1255 | { | ||
1256 | return ((page_to_phys(page)& CACHE_MASK) >> CACHE_SHIFT); | ||
1257 | } | ||
1258 | |||
1183 | static void zoneinfo_show_print(struct seq_file *m, pg_data_t *pgdat, | 1259 | static void zoneinfo_show_print(struct seq_file *m, pg_data_t *pgdat, |
1184 | struct zone *zone) | 1260 | struct zone *zone) |
1185 | { | 1261 | { |
1186 | int i; | 1262 | int i; |
1263 | int mtype; | ||
1264 | |||
1187 | seq_printf(m, "Node %d, zone %8s", pgdat->node_id, zone->name); | 1265 | seq_printf(m, "Node %d, zone %8s", pgdat->node_id, zone->name); |
1188 | seq_printf(m, | 1266 | seq_printf(m, |
1189 | "\n pages free %lu" | 1267 | "\n pages free %lu" |
@@ -1232,6 +1310,15 @@ static void zoneinfo_show_print(struct seq_file *m, pg_data_t *pgdat, | |||
1232 | seq_printf(m, "\n vm stats threshold: %d", | 1310 | seq_printf(m, "\n vm stats threshold: %d", |
1233 | pageset->stat_threshold); | 1311 | pageset->stat_threshold); |
1234 | #endif | 1312 | #endif |
1313 | /* test */ | ||
1314 | seq_printf(m, "\n"); | ||
1315 | for (mtype = 0; mtype < MIGRATE_PCPTYPES; mtype++) { | ||
1316 | struct page *p; | ||
1317 | list_for_each_entry(p, &pageset->pcp.lists[mtype], lru) { | ||
1318 | if (p) | ||
1319 | seq_printf(m, "page bank = %d color = %d\n", page_bank(p), page_color(p)); | ||
1320 | } | ||
1321 | } | ||
1235 | } | 1322 | } |
1236 | seq_printf(m, | 1323 | seq_printf(m, |
1237 | "\n all_unreclaimable: %u" | 1324 | "\n all_unreclaimable: %u" |