diff options
author | Christopher Kenna <cjk@cs.unc.edu> | 2012-03-29 16:58:20 -0400 |
---|---|---|
committer | Christopher Kenna <cjk@cs.unc.edu> | 2012-03-29 17:21:02 -0400 |
commit | 606f24606ecf76a62c2e262e260a51bf6f8dc009 (patch) | |
tree | 24bcaaeba38dbfffabf98e5000e8dcdffeca6d14 /litmus/color.c | |
parent | b227313bc9f87f67001e92b898d5da7918102b20 (diff) |
Allocate only one page at a time. Add proc interface.
Diffstat (limited to 'litmus/color.c')
-rw-r--r-- | litmus/color.c | 218 |
1 files changed, 135 insertions, 83 deletions
diff --git a/litmus/color.c b/litmus/color.c index b74b524655c8..e7aeab8c6598 100644 --- a/litmus/color.c +++ b/litmus/color.c | |||
@@ -5,9 +5,8 @@ | |||
5 | #include <linux/cpu.h> | 5 | #include <linux/cpu.h> |
6 | #include <linux/mm_types.h> | 6 | #include <linux/mm_types.h> |
7 | #include <linux/slab.h> | 7 | #include <linux/slab.h> |
8 | 8 | #include <linux/page-flags.h> | |
9 | //#include <asm/page.h> | 9 | #include <linux/sysctl.h> |
10 | //#include <asm/io.h> | ||
11 | 10 | ||
12 | #include <litmus/color.h> | 11 | #include <litmus/color.h> |
13 | 12 | ||
@@ -15,28 +14,139 @@ | |||
15 | printk(KERN_INFO "[%s@%s:%d]: " fmt, \ | 14 | printk(KERN_INFO "[%s@%s:%d]: " fmt, \ |
16 | __FUNCTION__, __FILE__, __LINE__, ## args) | 15 | __FUNCTION__, __FILE__, __LINE__, ## args) |
17 | 16 | ||
18 | #define ALLOC_ORDER (MAX_ORDER - 1) | 17 | #define PAGES_PER_COLOR 2000 |
19 | #define PAGES_PER_COLOR 1000 | ||
20 | |||
21 | struct color_cache_info color_cache_info; | ||
22 | unsigned long color_mask; | ||
23 | unsigned long nr_colors; | ||
24 | 18 | ||
25 | struct color_group { | 19 | struct color_group { |
26 | spinlock_t lock; | 20 | spinlock_t lock; |
27 | struct list_head list; | 21 | struct list_head list; |
28 | unsigned long nr_pages; | 22 | atomic_t nr_pages; |
29 | }; | 23 | }; |
30 | 24 | ||
31 | struct color_group *color_groups; | 25 | static unsigned long color_mask; |
26 | static struct color_group *color_groups; | ||
27 | |||
28 | /* non-static: extern'ed in various files */ | ||
29 | unsigned long nr_colors; | ||
30 | struct color_cache_info color_cache_info; | ||
31 | int color_sysctl_add_pages_data; | ||
32 | 32 | ||
33 | static inline unsigned int page_color(struct page *page) | 33 | static inline unsigned long page_color(struct page *page) |
34 | { | 34 | { |
35 | return ((page_to_phys(page) & color_mask) >> PAGE_SHIFT); | 35 | return ((page_to_phys(page) & color_mask) >> PAGE_SHIFT); |
36 | } | 36 | } |
37 | 37 | ||
38 | void add_page_to_color_list(struct page *page) | ||
39 | { | ||
40 | const unsigned long color = page_color(page); | ||
41 | struct color_group *cgroup = &color_groups[color]; | ||
42 | spin_lock(&cgroup->lock); | ||
43 | list_add_tail(&page->lru, &cgroup->list); | ||
44 | atomic_inc(&cgroup->nr_pages); | ||
45 | spin_unlock(&cgroup->lock); | ||
46 | } | ||
47 | |||
48 | struct page* get_colored_page(unsigned long color) | ||
49 | { | ||
50 | struct color_group *cgroup; | ||
51 | struct page *page; | ||
52 | BUG_ON(color >= nr_colors); | ||
53 | cgroup = &color_groups[color]; | ||
54 | spin_lock(&cgroup->lock); | ||
55 | BUG_ON(!atomic_read(&cgroup->nr_pages)); | ||
56 | page = list_first_entry(&cgroup->list, struct page, lru); | ||
57 | list_del(&page->lru); | ||
58 | atomic_dec(&cgroup->nr_pages); | ||
59 | spin_unlock(&cgroup->lock); | ||
60 | return page; | ||
61 | |||
62 | } | ||
63 | |||
64 | static unsigned long smallest_nr_pages(void) | ||
65 | { | ||
66 | unsigned long i, min_pages = -1; | ||
67 | struct color_group *cgroup; | ||
68 | for (i = 0; i < nr_colors; ++i) { | ||
69 | cgroup = &color_groups[i]; | ||
70 | if (atomic_read(&cgroup->nr_pages) < min_pages) | ||
71 | min_pages = atomic_read(&cgroup->nr_pages); | ||
72 | } | ||
73 | return min_pages; | ||
74 | } | ||
75 | |||
76 | static int do_add_pages(void) | ||
77 | { | ||
78 | struct page *page, *page_tmp; | ||
79 | struct list_head free_later; | ||
80 | unsigned long color; | ||
81 | int ret = 0; | ||
82 | |||
83 | INIT_LIST_HEAD(&free_later); | ||
84 | |||
85 | while (smallest_nr_pages() < PAGES_PER_COLOR) { | ||
86 | page = alloc_page(GFP_HIGHUSER | __GFP_ZERO | | ||
87 | __GFP_MOVABLE); | ||
88 | if (!page) { | ||
89 | MPRINT("could not allocate pages\n"); | ||
90 | BUG(); | ||
91 | } | ||
92 | color = page_color(page); | ||
93 | if (atomic_read(&color_groups[color].nr_pages) < PAGES_PER_COLOR) | ||
94 | add_page_to_color_list(page); | ||
95 | else | ||
96 | list_add_tail(&page->lru, &free_later); | ||
97 | } | ||
98 | list_for_each_entry_safe(page, page_tmp, &free_later, lru) { | ||
99 | list_del(&page->lru); | ||
100 | __free_page(page); | ||
101 | } | ||
102 | return ret; | ||
103 | } | ||
104 | |||
105 | |||
106 | /*********************************************************** | ||
107 | * Proc | ||
108 | ***********************************************************/ | ||
109 | |||
110 | int color_add_pages_handler(struct ctl_table *table, int write, void __user *buffer, | ||
111 | size_t *lenp, loff_t *ppos) | ||
112 | { | ||
113 | int ret; | ||
114 | |||
115 | ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos); | ||
116 | if (ret) | ||
117 | return ret; | ||
118 | if (write && color_sysctl_add_pages_data) | ||
119 | do_add_pages(); | ||
120 | return 0; | ||
121 | } | ||
122 | |||
123 | |||
124 | int color_nr_pages_handler(struct ctl_table *table, int write, void __user *buffer, | ||
125 | size_t *lenp, loff_t *ppos) | ||
126 | { | ||
127 | struct color_group *cgroup; | ||
128 | char *buf; | ||
129 | unsigned long i; | ||
130 | int used = 0; | ||
131 | |||
132 | if (write) | ||
133 | return -EPERM; | ||
134 | |||
135 | for (i = 0; i < nr_colors; ++i) { | ||
136 | cgroup = &color_groups[i]; | ||
137 | buf = ((char*)table->data) + used; | ||
138 | used += snprintf(buf, table->maxlen - used, ONE_COLOR_FMT, | ||
139 | i, atomic_read(&cgroup->nr_pages)); | ||
140 | } | ||
141 | return proc_dostring(table, write, buffer, lenp, ppos); | ||
142 | } | ||
143 | |||
144 | /*********************************************************** | ||
145 | * Initialization | ||
146 | ***********************************************************/ | ||
147 | |||
38 | /* slowest possible way to find a log, but we only do this once on boot */ | 148 | /* slowest possible way to find a log, but we only do this once on boot */ |
39 | static unsigned int slow_log(unsigned int v) | 149 | static unsigned int __init slow_log(unsigned int v) |
40 | { | 150 | { |
41 | unsigned int r = 0; | 151 | unsigned int r = 0; |
42 | while (v >>= 1) | 152 | while (v >>= 1) |
@@ -44,7 +154,7 @@ static unsigned int slow_log(unsigned int v) | |||
44 | return r; | 154 | return r; |
45 | } | 155 | } |
46 | 156 | ||
47 | static void __init setup_mask(void) | 157 | static void __init init_mask(void) |
48 | { | 158 | { |
49 | const unsigned int line_size_log = slow_log(color_cache_info.line_size); | 159 | const unsigned int line_size_log = slow_log(color_cache_info.line_size); |
50 | 160 | ||
@@ -58,103 +168,45 @@ static void __init setup_mask(void) | |||
58 | nr_colors); | 168 | nr_colors); |
59 | } | 169 | } |
60 | 170 | ||
61 | /* don't trust nr_pages returned from here. it's just used on startup */ | ||
62 | static void _add_page_to_color_list(struct page *page) | ||
63 | { | ||
64 | const unsigned long color = page_color(page); | ||
65 | struct color_group *cgroup = &color_groups[color]; | ||
66 | spin_lock(&cgroup->lock); | ||
67 | list_add_tail(&page->lru, &cgroup->list); | ||
68 | cgroup->nr_pages++; | ||
69 | spin_unlock(&cgroup->lock); | ||
70 | } | ||
71 | |||
72 | static void add_page_to_color_list(struct page *page) | ||
73 | { | ||
74 | unsigned long flags; | ||
75 | local_irq_save(flags); | ||
76 | _add_page_to_color_list(page); | ||
77 | local_irq_restore(flags); | ||
78 | } | ||
79 | |||
80 | static unsigned long __init smallest_nr_pages(void) | ||
81 | { | ||
82 | unsigned long flags, i, min_pages = -1; | ||
83 | struct color_group *cgroup; | ||
84 | local_irq_save(flags); | ||
85 | for (i = 0; i < nr_colors; ++i) { | ||
86 | cgroup = &color_groups[i]; | ||
87 | spin_lock(&cgroup->lock); | ||
88 | if (cgroup->nr_pages < min_pages) | ||
89 | min_pages = cgroup->nr_pages; | ||
90 | spin_unlock(&cgroup->lock); | ||
91 | } | ||
92 | local_irq_restore(flags); | ||
93 | return min_pages; | ||
94 | } | ||
95 | |||
96 | static int __init init_color_groups(void) | 171 | static int __init init_color_groups(void) |
97 | { | 172 | { |
98 | struct color_group *cgroup; | 173 | struct color_group *cgroup; |
99 | unsigned long i, flags; | 174 | unsigned long i; |
100 | int ret = 0; | ||
101 | 175 | ||
102 | color_groups = kmalloc(nr_colors * sizeof(struct color_group), GFP_KERNEL); | 176 | color_groups = kmalloc(nr_colors * sizeof(struct color_group), GFP_KERNEL); |
103 | if (!color_groups) { | 177 | if (!color_groups) { |
104 | printk(KERN_WARNING "Could not allocate color groups.\n"); | 178 | printk(KERN_WARNING "Could not allocate color groups.\n"); |
105 | ret = -ENOMEM; | 179 | return -ENOMEM; |
106 | goto out; | ||
107 | } | 180 | } |
108 | 181 | ||
109 | for (i = 0; i < nr_colors; ++i) { | 182 | for (i = 0; i < nr_colors; ++i) { |
110 | cgroup = &color_groups[i]; | 183 | cgroup = &color_groups[i]; |
111 | cgroup->nr_pages = 0; | 184 | atomic_set(&cgroup->nr_pages, 0); |
112 | INIT_LIST_HEAD(&cgroup->list); | 185 | INIT_LIST_HEAD(&cgroup->list); |
113 | spin_lock_init(&cgroup->lock); | 186 | spin_lock_init(&cgroup->lock); |
114 | } | 187 | } |
115 | 188 | return 0; | |
116 | while (smallest_nr_pages() < PAGES_PER_COLOR) { | ||
117 | struct page *page = alloc_pages( | ||
118 | GFP_KERNEL | __GFP_HIGHMEM | __GFP_REPEAT, | ||
119 | ALLOC_ORDER); | ||
120 | if (!page) { | ||
121 | MPRINT("could not allocate pages\n"); | ||
122 | BUG(); | ||
123 | } | ||
124 | local_irq_save(flags); | ||
125 | for (i = 0; i < (1UL << ALLOC_ORDER); ++i) | ||
126 | _add_page_to_color_list(&page[i]); | ||
127 | local_irq_restore(flags); | ||
128 | } | ||
129 | |||
130 | local_irq_save(flags); | ||
131 | for (i = 0; i < nr_colors; ++i) { | ||
132 | cgroup = &color_groups[i]; | ||
133 | spin_lock(&cgroup->lock); | ||
134 | MPRINT("color %3lu: %4lu pages\n", i, cgroup->nr_pages); | ||
135 | spin_unlock(&cgroup->lock); | ||
136 | } | ||
137 | local_irq_restore(flags); | ||
138 | out: | ||
139 | return ret; | ||
140 | } | 189 | } |
141 | 190 | ||
142 | static int __init init_color(void) | 191 | static int __init init_color(void) |
143 | { | 192 | { |
193 | int ret = 0; | ||
144 | 194 | ||
145 | MPRINT("ALLOC_ORDER is %d\n", ALLOC_ORDER); | ||
146 | MPRINT("Cache size: %lu line-size: %lu ways: %lu sets: %lu\n", | 195 | MPRINT("Cache size: %lu line-size: %lu ways: %lu sets: %lu\n", |
147 | color_cache_info.size, color_cache_info.line_size, | 196 | color_cache_info.size, color_cache_info.line_size, |
148 | color_cache_info.ways, color_cache_info.sets); | 197 | color_cache_info.ways, color_cache_info.sets); |
149 | if (!color_cache_info.size){ | 198 | if (!color_cache_info.size){ |
150 | printk(KERN_WARNING "No cache information found.\n"); | 199 | printk(KERN_WARNING "No cache information found.\n"); |
151 | return -EINVAL; | 200 | ret = -EINVAL; |
201 | goto out; | ||
152 | } | 202 | } |
153 | BUG_ON(color_cache_info.size <= 1048576 || | 203 | BUG_ON(color_cache_info.size <= 1048576 || |
154 | color_cache_info.ways < 15 || | 204 | color_cache_info.ways < 15 || |
155 | color_cache_info.line_size != 64); | 205 | color_cache_info.line_size != 64); |
156 | setup_mask(); | 206 | init_mask(); |
157 | return init_color_groups(); | 207 | ret = init_color_groups(); |
208 | out: | ||
209 | return ret; | ||
158 | } | 210 | } |
159 | 211 | ||
160 | module_init(init_color); | 212 | module_init(init_color); |