diff options
author | Bjoern B. Brandenburg <bbb@cs.unc.edu> | 2011-01-26 20:42:49 -0500 |
---|---|---|
committer | Bjoern B. Brandenburg <bbb@cs.unc.edu> | 2011-02-01 17:00:26 -0500 |
commit | 4ce37704ec0bedb28b5708d32964fca471e793d0 (patch) | |
tree | 4e622b0d2d6793e944455ba108ae6dd5bf05ee80 | |
parent | 963fd846e36b48d5338ef2a134d3ee8d208abc07 (diff) |
Litmus core: extract userspace interface from C-EDF
Make the cluster size configuration in C-EDF generic so that it can be
used by other clustered schedulers.
-rw-r--r-- | include/litmus/clustered.h | 22 | ||||
-rw-r--r-- | litmus/litmus_proc.c | 78 | ||||
-rw-r--r-- | litmus/sched_cedf.c | 88 |
3 files changed, 106 insertions, 82 deletions
diff --git a/include/litmus/clustered.h b/include/litmus/clustered.h new file mode 100644 index 000000000000..cad12467b4ee --- /dev/null +++ b/include/litmus/clustered.h | |||
@@ -0,0 +1,22 @@ | |||
1 | #ifndef CLUSTERED_H | ||
2 | #define CLUSTERED_H | ||
3 | |||
4 | /* Which cache level should be used to group CPUs into clusters? | ||
5 | * GLOBAL_CLUSTER means that all CPUs form a single cluster (just like under | ||
6 | * global scheduling). | ||
7 | */ | ||
8 | enum cache_level { | ||
9 | GLOBAL_CLUSTER = 0, | ||
10 | L1_CLUSTER = 1, | ||
11 | L2_CLUSTER = 2, | ||
12 | L3_CLUSTER = 3 | ||
13 | }; | ||
14 | |||
15 | int parse_cache_level(const char *str, enum cache_level *level); | ||
16 | const char* cache_level_name(enum cache_level level); | ||
17 | |||
18 | /* expose a cache level in a /proc dir */ | ||
19 | struct proc_dir_entry* create_cluster_file(struct proc_dir_entry* parent, | ||
20 | enum cache_level* level); | ||
21 | |||
22 | #endif | ||
diff --git a/litmus/litmus_proc.c b/litmus/litmus_proc.c index e3f3f11f80e1..4bf725a36c9c 100644 --- a/litmus/litmus_proc.c +++ b/litmus/litmus_proc.c | |||
@@ -8,6 +8,8 @@ | |||
8 | #include <litmus/litmus.h> | 8 | #include <litmus/litmus.h> |
9 | #include <litmus/litmus_proc.h> | 9 | #include <litmus/litmus_proc.h> |
10 | 10 | ||
11 | #include <litmus/clustered.h> | ||
12 | |||
11 | /* in litmus/litmus.c */ | 13 | /* in litmus/litmus.c */ |
12 | extern atomic_t rt_task_count; | 14 | extern atomic_t rt_task_count; |
13 | 15 | ||
@@ -267,3 +269,79 @@ int copy_and_chomp(char *kbuf, unsigned long ksize, | |||
267 | 269 | ||
268 | return ksize; | 270 | return ksize; |
269 | } | 271 | } |
272 | |||
273 | /* helper functions for clustered plugins */ | ||
274 | static const char* cache_level_names[] = { | ||
275 | "ALL", | ||
276 | "L1", | ||
277 | "L2", | ||
278 | "L3", | ||
279 | }; | ||
280 | |||
281 | int parse_cache_level(const char *cache_name, enum cache_level *level) | ||
282 | { | ||
283 | int err = -EINVAL; | ||
284 | int i; | ||
285 | /* do a quick and dirty comparison to find the cluster size */ | ||
286 | for (i = GLOBAL_CLUSTER; i <= L3_CLUSTER; i++) | ||
287 | if (!strcmp(cache_name, cache_level_names[i])) { | ||
288 | *level = (enum cache_level) i; | ||
289 | err = 0; | ||
290 | break; | ||
291 | } | ||
292 | return err; | ||
293 | } | ||
294 | |||
295 | const char* cache_level_name(enum cache_level level) | ||
296 | { | ||
297 | int idx = level; | ||
298 | |||
299 | if (idx >= GLOBAL_CLUSTER && idx <= L3_CLUSTER) | ||
300 | return cache_level_names[idx]; | ||
301 | else | ||
302 | return "INVALID"; | ||
303 | } | ||
304 | |||
305 | |||
306 | /* proc file interface to configure the cluster size */ | ||
307 | static int proc_read_cluster_size(char *page, char **start, | ||
308 | off_t off, int count, | ||
309 | int *eof, void *data) | ||
310 | { | ||
311 | return snprintf(page, PAGE_SIZE, "%s\n", | ||
312 | cache_level_name(*((enum cache_level*) data)));; | ||
313 | } | ||
314 | |||
315 | static int proc_write_cluster_size(struct file *file, | ||
316 | const char *buffer, | ||
317 | unsigned long count, | ||
318 | void *data) | ||
319 | { | ||
320 | int len; | ||
321 | char cache_name[8]; | ||
322 | |||
323 | len = copy_and_chomp(cache_name, sizeof(cache_name), buffer, count); | ||
324 | |||
325 | if (len > 0 && parse_cache_level(cache_name, (enum cache_level*) data)) | ||
326 | printk(KERN_INFO "Cluster '%s' is unknown.\n", cache_name); | ||
327 | |||
328 | return len; | ||
329 | } | ||
330 | |||
331 | struct proc_dir_entry* create_cluster_file(struct proc_dir_entry* parent, | ||
332 | enum cache_level* level) | ||
333 | { | ||
334 | struct proc_dir_entry* cluster_file; | ||
335 | |||
336 | cluster_file = create_proc_entry("cluster", 0644, parent); | ||
337 | if (!cluster_file) { | ||
338 | printk(KERN_ERR "Could not allocate %s/cluster " | ||
339 | "procfs entry.\n", parent->name); | ||
340 | } else { | ||
341 | cluster_file->read_proc = proc_read_cluster_size; | ||
342 | cluster_file->write_proc = proc_write_cluster_size; | ||
343 | cluster_file->data = level; | ||
344 | } | ||
345 | return cluster_file; | ||
346 | } | ||
347 | |||
diff --git a/litmus/sched_cedf.c b/litmus/sched_cedf.c index 098a449c2490..73fe1c442a0d 100644 --- a/litmus/sched_cedf.c +++ b/litmus/sched_cedf.c | |||
@@ -39,6 +39,8 @@ | |||
39 | #include <litmus/edf_common.h> | 39 | #include <litmus/edf_common.h> |
40 | #include <litmus/sched_trace.h> | 40 | #include <litmus/sched_trace.h> |
41 | 41 | ||
42 | #include <litmus/clustered.h> | ||
43 | |||
42 | #include <litmus/bheap.h> | 44 | #include <litmus/bheap.h> |
43 | 45 | ||
44 | /* to configure the cluster size */ | 46 | /* to configure the cluster size */ |
@@ -49,12 +51,7 @@ | |||
49 | * group CPUs into clusters. GLOBAL_CLUSTER, which is the default, means that | 51 | * group CPUs into clusters. GLOBAL_CLUSTER, which is the default, means that |
50 | * all CPUs form a single cluster (just like GSN-EDF). | 52 | * all CPUs form a single cluster (just like GSN-EDF). |
51 | */ | 53 | */ |
52 | static enum { | 54 | static enum cache_level cluster_config = GLOBAL_CLUSTER; |
53 | GLOBAL_CLUSTER = 0, | ||
54 | L1_CLUSTER = 1, | ||
55 | L2_CLUSTER = 2, | ||
56 | L3_CLUSTER = 3 | ||
57 | } cluster_config = GLOBAL_CLUSTER; | ||
58 | 55 | ||
59 | struct clusterdomain; | 56 | struct clusterdomain; |
60 | 57 | ||
@@ -770,73 +767,8 @@ static struct sched_plugin cedf_plugin __cacheline_aligned_in_smp = { | |||
770 | .activate_plugin = cedf_activate_plugin, | 767 | .activate_plugin = cedf_activate_plugin, |
771 | }; | 768 | }; |
772 | 769 | ||
773 | |||
774 | /* proc file interface to configure the cluster size */ | ||
775 | |||
776 | static int proc_read_cluster_size(char *page, char **start, | ||
777 | off_t off, int count, | ||
778 | int *eof, void *data) | ||
779 | { | ||
780 | int len; | ||
781 | switch (cluster_config) { | ||
782 | case GLOBAL_CLUSTER: | ||
783 | len = snprintf(page, PAGE_SIZE, "ALL\n"); | ||
784 | break; | ||
785 | case L1_CLUSTER: | ||
786 | case L2_CLUSTER: | ||
787 | case L3_CLUSTER: | ||
788 | len = snprintf(page, PAGE_SIZE, "L%d\n", cluster_config); | ||
789 | break; | ||
790 | default: | ||
791 | /* This should be impossible, but let's be paranoid. */ | ||
792 | len = snprintf(page, PAGE_SIZE, "INVALID (%d)\n", | ||
793 | cluster_config); | ||
794 | break; | ||
795 | } | ||
796 | return len; | ||
797 | } | ||
798 | |||
799 | static int proc_write_cluster_size(struct file *file, | ||
800 | const char *buffer, | ||
801 | unsigned long count, | ||
802 | void *data) | ||
803 | { | ||
804 | int len; | ||
805 | /* L2, L3 */ | ||
806 | char cache_name[33]; | ||
807 | |||
808 | if(count > 32) | ||
809 | len = 32; | ||
810 | else | ||
811 | len = count; | ||
812 | |||
813 | if(copy_from_user(cache_name, buffer, len)) | ||
814 | return -EFAULT; | ||
815 | |||
816 | cache_name[len] = '\0'; | ||
817 | /* chomp name */ | ||
818 | if (len > 1 && cache_name[len - 1] == '\n') | ||
819 | cache_name[len - 1] = '\0'; | ||
820 | |||
821 | /* do a quick and dirty comparison to find the cluster size */ | ||
822 | if (!strcmp(cache_name, "L2")) | ||
823 | cluster_config = L2_CLUSTER; | ||
824 | else if (!strcmp(cache_name, "L3")) | ||
825 | cluster_config = L3_CLUSTER; | ||
826 | else if (!strcmp(cache_name, "L1")) | ||
827 | cluster_config = L1_CLUSTER; | ||
828 | else if (!strcmp(cache_name, "ALL")) | ||
829 | cluster_config = GLOBAL_CLUSTER; | ||
830 | else | ||
831 | printk(KERN_INFO "Cluster '%s' is unknown.\n", cache_name); | ||
832 | |||
833 | return len; | ||
834 | } | ||
835 | |||
836 | |||
837 | static struct proc_dir_entry *cluster_file = NULL, *cedf_dir = NULL; | 770 | static struct proc_dir_entry *cluster_file = NULL, *cedf_dir = NULL; |
838 | 771 | ||
839 | |||
840 | static int __init init_cedf(void) | 772 | static int __init init_cedf(void) |
841 | { | 773 | { |
842 | int err, fs; | 774 | int err, fs; |
@@ -844,18 +776,10 @@ static int __init init_cedf(void) | |||
844 | err = register_sched_plugin(&cedf_plugin); | 776 | err = register_sched_plugin(&cedf_plugin); |
845 | if (!err) { | 777 | if (!err) { |
846 | fs = make_plugin_proc_dir(&cedf_plugin, &cedf_dir); | 778 | fs = make_plugin_proc_dir(&cedf_plugin, &cedf_dir); |
847 | if (!fs) { | 779 | if (!fs) |
848 | cluster_file = create_proc_entry("cluster", 0644, cedf_dir); | 780 | cluster_file = create_cluster_file(cedf_dir, &cluster_config); |
849 | if (!cluster_file) { | 781 | else |
850 | printk(KERN_ERR "Could not allocate C-EDF/cluster " | ||
851 | "procfs entry.\n"); | ||
852 | } else { | ||
853 | cluster_file->read_proc = proc_read_cluster_size; | ||
854 | cluster_file->write_proc = proc_write_cluster_size; | ||
855 | } | ||
856 | } else { | ||
857 | printk(KERN_ERR "Could not allocate C-EDF procfs dir.\n"); | 782 | printk(KERN_ERR "Could not allocate C-EDF procfs dir.\n"); |
858 | } | ||
859 | } | 783 | } |
860 | return err; | 784 | return err; |
861 | } | 785 | } |