aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristopher Kenna <cjk@cs.unc.edu>2012-03-29 16:58:20 -0400
committerChristopher Kenna <cjk@cs.unc.edu>2012-03-29 17:21:02 -0400
commit606f24606ecf76a62c2e262e260a51bf6f8dc009 (patch)
tree24bcaaeba38dbfffabf98e5000e8dcdffeca6d14
parentb227313bc9f87f67001e92b898d5da7918102b20 (diff)
Allocate only one page at a time. Add proc interface.
-rw-r--r--include/litmus/color.h12
-rw-r--r--litmus/Makefile3
-rw-r--r--litmus/color.c218
-rw-r--r--litmus/color_proc.c79
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
4struct color_cache_info { 7struct 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
14void _add_page_to_color_list(struct page*);
15void add_page_to_color_list(struct page*);
16struct page* _get_colored_page(unsigned long);
17struct page* get_colored_page(unsigned long);
18
19int color_add_pages_handler(struct ctl_table *, int, void __user *,
20 size_t *, loff_t *);
21int 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
23obj-$(CONFIG_PLUGIN_CEDF) += sched_cedf.o 24obj-$(CONFIG_PLUGIN_CEDF) += sched_cedf.o
24obj-$(CONFIG_PLUGIN_PFAIR) += sched_pfair.o 25obj-$(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
21struct color_cache_info color_cache_info;
22unsigned long color_mask;
23unsigned long nr_colors;
24 18
25struct color_group { 19struct 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
31struct color_group *color_groups; 25static unsigned long color_mask;
26static struct color_group *color_groups;
27
28/* non-static: extern'ed in various files */
29unsigned long nr_colors;
30struct color_cache_info color_cache_info;
31int color_sysctl_add_pages_data;
32 32
33static inline unsigned int page_color(struct page *page) 33static 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
38void 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
48struct 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
64static 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
76static 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
110int 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
124int 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 */
39static unsigned int slow_log(unsigned int v) 149static 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
47static void __init setup_mask(void) 157static 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 */
62static 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
72static 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
80static 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
96static int __init init_color_groups(void) 171static 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);
138out:
139 return ret;
140} 189}
141 190
142static int __init init_color(void) 191static 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();
208out:
209 return ret;
158} 210}
159 211
160module_init(init_color); 212module_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
7extern int color_sysctl_add_pages_data; /* litmus/color.c */
8
9static int zero = 0;
10static int one = 1;
11
12#define NR_PAGES_INDEX 1 /* location of nr_pages in the table below */
13static 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
34static struct ctl_table litmus_table[] =
35{
36 {
37 .procname = "color",
38 .mode = 0555,
39 .child = color_table,
40 },
41 { }
42};
43static struct ctl_table litmus_dir_table[] = {
44 {
45 .procname = "litmus",
46 .mode = 0555,
47 .child = litmus_table,
48 },
49 { }
50};
51
52extern unsigned long nr_colors; /* litmus/color.c */
53
54/* must be called AFTER nr_colors is set */
55static 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
67static struct ctl_table_header *litmus_sysctls;
68
69static 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
79module_init(litmus_sysctl_init);