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 | |
parent | b227313bc9f87f67001e92b898d5da7918102b20 (diff) |
Allocate only one page at a time. Add proc interface.
-rw-r--r-- | include/litmus/color.h | 12 | ||||
-rw-r--r-- | litmus/Makefile | 3 | ||||
-rw-r--r-- | litmus/color.c | 218 | ||||
-rw-r--r-- | litmus/color_proc.c | 79 |
4 files changed, 228 insertions, 84 deletions
diff --git a/include/litmus/color.h b/include/litmus/color.h index 3933cf12cf3f..ce182c2e65a7 100644 --- a/include/litmus/color.h +++ b/include/litmus/color.h | |||
@@ -1,6 +1,9 @@ | |||
1 | #ifndef LITMUS_COLOR_H | 1 | #ifndef LITMUS_COLOR_H |
2 | #define LITMUS_COLOR_H | 2 | #define LITMUS_COLOR_H |
3 | 3 | ||
4 | #define ONE_COLOR_LEN 11 | ||
5 | #define ONE_COLOR_FMT "%4lu: %4d\n" | ||
6 | |||
4 | struct color_cache_info { | 7 | struct color_cache_info { |
5 | unsigned long size; | 8 | unsigned long size; |
6 | unsigned long line_size; | 9 | unsigned long line_size; |
@@ -8,4 +11,13 @@ struct color_cache_info { | |||
8 | unsigned long sets; | 11 | unsigned long sets; |
9 | }; | 12 | }; |
10 | 13 | ||
14 | void _add_page_to_color_list(struct page*); | ||
15 | void add_page_to_color_list(struct page*); | ||
16 | struct page* _get_colored_page(unsigned long); | ||
17 | struct page* get_colored_page(unsigned long); | ||
18 | |||
19 | int color_add_pages_handler(struct ctl_table *, int, void __user *, | ||
20 | size_t *, loff_t *); | ||
21 | int color_nr_pages_handler(struct ctl_table *, int, void __user *, | ||
22 | size_t *, loff_t *); | ||
11 | #endif | 23 | #endif |
diff --git a/litmus/Makefile b/litmus/Makefile index 506fdf9b0c51..e4c937bc2850 100644 --- a/litmus/Makefile +++ b/litmus/Makefile | |||
@@ -18,7 +18,8 @@ obj-y = sched_plugin.o litmus.o \ | |||
18 | ctrldev.o \ | 18 | ctrldev.o \ |
19 | sched_gsn_edf.o \ | 19 | sched_gsn_edf.o \ |
20 | sched_psn_edf.o \ | 20 | sched_psn_edf.o \ |
21 | color.o | 21 | color.o \ |
22 | color_proc.o | ||
22 | 23 | ||
23 | obj-$(CONFIG_PLUGIN_CEDF) += sched_cedf.o | 24 | obj-$(CONFIG_PLUGIN_CEDF) += sched_cedf.o |
24 | obj-$(CONFIG_PLUGIN_PFAIR) += sched_pfair.o | 25 | obj-$(CONFIG_PLUGIN_PFAIR) += sched_pfair.o |
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); |
diff --git a/litmus/color_proc.c b/litmus/color_proc.c new file mode 100644 index 000000000000..1eba0740db9d --- /dev/null +++ b/litmus/color_proc.c | |||
@@ -0,0 +1,79 @@ | |||
1 | #include <linux/module.h> | ||
2 | #include <linux/sysctl.h> | ||
3 | #include <linux/slab.h> | ||
4 | |||
5 | #include <litmus/color.h> | ||
6 | |||
7 | extern int color_sysctl_add_pages_data; /* litmus/color.c */ | ||
8 | |||
9 | static int zero = 0; | ||
10 | static int one = 1; | ||
11 | |||
12 | #define NR_PAGES_INDEX 1 /* location of nr_pages in the table below */ | ||
13 | static struct ctl_table color_table[] = | ||
14 | { | ||
15 | { | ||
16 | .procname = "add_pages", | ||
17 | .data = &color_sysctl_add_pages_data, | ||
18 | .maxlen = sizeof(int), | ||
19 | .mode = 0644, | ||
20 | .proc_handler = color_add_pages_handler, | ||
21 | .extra1 = &zero, | ||
22 | .extra2 = &one, | ||
23 | }, | ||
24 | { | ||
25 | .procname = "nr_pages", | ||
26 | .mode = 0444, | ||
27 | .proc_handler = color_nr_pages_handler, | ||
28 | .data = NULL, /* dynamically later */ | ||
29 | .maxlen = 0, /* also set later */ | ||
30 | }, | ||
31 | { } | ||
32 | }; | ||
33 | |||
34 | static struct ctl_table litmus_table[] = | ||
35 | { | ||
36 | { | ||
37 | .procname = "color", | ||
38 | .mode = 0555, | ||
39 | .child = color_table, | ||
40 | }, | ||
41 | { } | ||
42 | }; | ||
43 | static struct ctl_table litmus_dir_table[] = { | ||
44 | { | ||
45 | .procname = "litmus", | ||
46 | .mode = 0555, | ||
47 | .child = litmus_table, | ||
48 | }, | ||
49 | { } | ||
50 | }; | ||
51 | |||
52 | extern unsigned long nr_colors; /* litmus/color.c */ | ||
53 | |||
54 | /* must be called AFTER nr_colors is set */ | ||
55 | static int __init init_sysctl_nr_colors(void) | ||
56 | { | ||
57 | int maxlen = ONE_COLOR_LEN * nr_colors; | ||
58 | color_table[NR_PAGES_INDEX].data = kmalloc(maxlen, GFP_KERNEL); | ||
59 | if (!color_table[NR_PAGES_INDEX].data) { | ||
60 | printk(KERN_WARNING "Could not allocate nr_pages buffer.\n"); | ||
61 | return -ENOMEM; | ||
62 | } | ||
63 | color_table[NR_PAGES_INDEX].maxlen = maxlen; | ||
64 | return 0; | ||
65 | } | ||
66 | |||
67 | static struct ctl_table_header *litmus_sysctls; | ||
68 | |||
69 | static int __init litmus_sysctl_init(void) | ||
70 | { | ||
71 | litmus_sysctls = register_sysctl_table(litmus_dir_table); | ||
72 | if (!litmus_sysctls) { | ||
73 | printk(KERN_WARNING "Could not register LITMUS^RT sysctl.\n"); | ||
74 | return -EFAULT; | ||
75 | } | ||
76 | return init_sysctl_nr_colors(); | ||
77 | } | ||
78 | |||
79 | module_init(litmus_sysctl_init); | ||