diff options
Diffstat (limited to 'litmus/clustered.c')
-rw-r--r-- | litmus/clustered.c | 119 |
1 files changed, 119 insertions, 0 deletions
diff --git a/litmus/clustered.c b/litmus/clustered.c new file mode 100644 index 000000000000..de2aca2a271c --- /dev/null +++ b/litmus/clustered.c | |||
@@ -0,0 +1,119 @@ | |||
1 | #include <linux/gfp.h> | ||
2 | #include <linux/cpumask.h> | ||
3 | #include <linux/list.h> | ||
4 | #include <linux/cacheinfo.h> | ||
5 | |||
6 | #include <litmus/debug_trace.h> | ||
7 | #include <litmus/clustered.h> | ||
8 | |||
9 | int get_shared_cpu_map(cpumask_var_t mask, unsigned int cpu, unsigned int index) | ||
10 | { | ||
11 | struct cpu_cacheinfo* info = get_cpu_cacheinfo(cpu); | ||
12 | struct cacheinfo *ci; | ||
13 | |||
14 | if (!info || index >= info->num_leaves) { | ||
15 | TRACE("no shared-cache CPUs: info=%d index=%u\n", | ||
16 | info != NULL, index); | ||
17 | return 1; | ||
18 | } | ||
19 | |||
20 | if (!info->info_list) { | ||
21 | TRACE("no shared-cache CPUs: no info_list (cpu\n"); | ||
22 | } | ||
23 | ci = info->info_list + index; | ||
24 | |||
25 | cpumask_copy(mask, &ci->shared_cpu_map); | ||
26 | |||
27 | TRACE("get_shared: P%u@L%u -> %d siblings\n ", cpu, index, cpumask_weight(mask)); | ||
28 | |||
29 | return 0; | ||
30 | } | ||
31 | |||
32 | int get_cluster_size(enum cache_level level) | ||
33 | { | ||
34 | cpumask_var_t mask; | ||
35 | int ok; | ||
36 | int num_cpus; | ||
37 | |||
38 | if (level == GLOBAL_CLUSTER) | ||
39 | return num_online_cpus(); | ||
40 | else { | ||
41 | if (!zalloc_cpumask_var(&mask, GFP_ATOMIC)) | ||
42 | return -ENOMEM; | ||
43 | /* assumes CPU 0 is representative of all CPUs */ | ||
44 | ok = get_shared_cpu_map(mask, 0, level); | ||
45 | /* ok == 0 means we got the map; otherwise it's an invalid cache level */ | ||
46 | if (ok == 0) | ||
47 | num_cpus = cpumask_weight(mask); | ||
48 | free_cpumask_var(mask); | ||
49 | |||
50 | if (ok == 0) | ||
51 | return num_cpus; | ||
52 | else | ||
53 | return -EINVAL; | ||
54 | } | ||
55 | } | ||
56 | |||
57 | int assign_cpus_to_clusters(enum cache_level level, | ||
58 | struct scheduling_cluster* clusters[], | ||
59 | unsigned int num_clusters, | ||
60 | struct cluster_cpu* cpus[], | ||
61 | unsigned int num_cpus) | ||
62 | { | ||
63 | cpumask_var_t mask; | ||
64 | unsigned int i, free_cluster = 0, low_cpu; | ||
65 | int err = 0; | ||
66 | |||
67 | if (!zalloc_cpumask_var(&mask, GFP_ATOMIC)) | ||
68 | return -ENOMEM; | ||
69 | |||
70 | /* clear cluster pointers */ | ||
71 | for (i = 0; i < num_cpus; i++) { | ||
72 | cpus[i]->id = i; | ||
73 | cpus[i]->cluster = NULL; | ||
74 | } | ||
75 | |||
76 | /* initialize clusters */ | ||
77 | for (i = 0; i < num_clusters; i++) { | ||
78 | clusters[i]->id = i; | ||
79 | INIT_LIST_HEAD(&clusters[i]->cpus); | ||
80 | } | ||
81 | |||
82 | /* Assign each CPU. Two assumtions are made: | ||
83 | * 1) The index of a cpu in cpus corresponds to its processor id (i.e., the index in a cpu mask). | ||
84 | * 2) All cpus that belong to some cluster are online. | ||
85 | */ | ||
86 | for_each_online_cpu(i) { | ||
87 | /* get lowest-id CPU in cluster */ | ||
88 | if (level != GLOBAL_CLUSTER) { | ||
89 | err = get_shared_cpu_map(mask, cpus[i]->id, level); | ||
90 | if (err != 0) { | ||
91 | /* ugh... wrong cache level? Either caller screwed up | ||
92 | * or the CPU topology is weird. */ | ||
93 | printk(KERN_ERR "Could not set up clusters for L%d sharing (max: L%d).\n", | ||
94 | level, err); | ||
95 | err = -EINVAL; | ||
96 | goto out; | ||
97 | } | ||
98 | low_cpu = cpumask_first(mask); | ||
99 | } else | ||
100 | low_cpu = 0; | ||
101 | if (low_cpu == i) { | ||
102 | /* caller must provide an appropriate number of clusters */ | ||
103 | BUG_ON(free_cluster >= num_clusters); | ||
104 | |||
105 | /* create new cluster */ | ||
106 | cpus[i]->cluster = clusters[free_cluster++]; | ||
107 | } else { | ||
108 | /* low_cpu points to the right cluster | ||
109 | * Assumption: low_cpu is actually online and was processed earlier. */ | ||
110 | cpus[i]->cluster = cpus[low_cpu]->cluster; | ||
111 | } | ||
112 | /* enqueue in cpus list */ | ||
113 | list_add_tail(&cpus[i]->cluster_list, &cpus[i]->cluster->cpus); | ||
114 | printk(KERN_INFO "Assigning CPU%u to cluster %u\n.", i, cpus[i]->cluster->id); | ||
115 | } | ||
116 | out: | ||
117 | free_cpumask_var(mask); | ||
118 | return err; | ||
119 | } | ||