diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-04-16 20:09:15 -0400 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-04-16 20:09:15 -0400 |
commit | 8675824ed85d6e83a24e77dabaf3a5c02c91ef6f (patch) | |
tree | 29e19fb32cacb062abca434fc921636d600ce77b | |
parent | 0b865246946a97dc03a81ccf55bf84acce923c4b (diff) |
Implement GPU-affinity-aware kfmlp (untested)
-rw-r--r-- | include/litmus/fdso.h | 7 | ||||
-rw-r--r-- | include/litmus/fpmath.h | 134 | ||||
-rw-r--r-- | include/litmus/gpu_affinity.h | 40 | ||||
-rw-r--r-- | include/litmus/kfmlp_lock.h | 56 | ||||
-rw-r--r-- | include/litmus/rt_param.h | 37 | ||||
-rw-r--r-- | litmus/Makefile | 2 | ||||
-rw-r--r-- | litmus/gpu_affinity.c | 72 | ||||
-rw-r--r-- | litmus/kfmlp_lock.c | 660 | ||||
-rw-r--r-- | litmus/litmus.c | 7 | ||||
-rw-r--r-- | litmus/locking.c | 13 | ||||
-rw-r--r-- | litmus/rsm_lock.c | 14 | ||||
-rw-r--r-- | litmus/sched_gsn_edf.c | 69 |
12 files changed, 1006 insertions, 105 deletions
diff --git a/include/litmus/fdso.h b/include/litmus/fdso.h index baf28c47e95d..b92c1a3f004f 100644 --- a/include/litmus/fdso.h +++ b/include/litmus/fdso.h | |||
@@ -24,10 +24,11 @@ typedef enum { | |||
24 | IKGLP_SEM = 3, | 24 | IKGLP_SEM = 3, |
25 | KFMLP_SEM = 4, | 25 | KFMLP_SEM = 4, |
26 | 26 | ||
27 | IKGLP_AFF_OBS = 5, | 27 | IKGLP_GPU_AFF_OBS = 5, |
28 | KFMLP_AFF_OBS = 6, | 28 | KFMLP_SIMPLE_GPU_AFF_OBS = 6, |
29 | KFMLP_GPU_AFF_OBS = 7, | ||
29 | 30 | ||
30 | MAX_OBJ_TYPE = 6 | 31 | MAX_OBJ_TYPE = 7 |
31 | } obj_type_t; | 32 | } obj_type_t; |
32 | 33 | ||
33 | struct inode_obj_id { | 34 | struct inode_obj_id { |
diff --git a/include/litmus/fpmath.h b/include/litmus/fpmath.h new file mode 100644 index 000000000000..35f81683d6ab --- /dev/null +++ b/include/litmus/fpmath.h | |||
@@ -0,0 +1,134 @@ | |||
1 | #ifndef __FP_MATH_H__ | ||
2 | #define __FP_MATH_H__ | ||
3 | |||
4 | // Use 64-bit because we want to track things at the nanosecond scale. | ||
5 | // This can lead to very large numbers. | ||
6 | typedef int64_t fpbuf_t; | ||
7 | typedef struct | ||
8 | { | ||
9 | fpbuf_t val; | ||
10 | } fp_t; | ||
11 | |||
12 | #define FP_SHIFT 10 | ||
13 | #define ROUND_BIT (FP_SHIFT - 1) | ||
14 | #define ONE FP(1) | ||
15 | |||
16 | #define _fp(x) ((fp_t) {x}) | ||
17 | |||
18 | static const fp_t LITMUS_FP_ZERO = {.val = 0}; | ||
19 | static const fp_t LITMUS_FP_ONE = {.val = (1 << FP_SHIFT)}; | ||
20 | |||
21 | static inline fp_t FP(fpbuf_t x) | ||
22 | { | ||
23 | return _fp(((fpbuf_t) x) << FP_SHIFT); | ||
24 | } | ||
25 | |||
26 | /* divide two integers to obtain a fixed point value */ | ||
27 | static inline fp_t _frac(fpbuf_t a, fpbuf_t b) | ||
28 | { | ||
29 | return _fp(FP(a).val / (b)); | ||
30 | } | ||
31 | |||
32 | #ifdef __KERNEL__ | ||
33 | |||
34 | static inline fpbuf_t _point(fp_t x) | ||
35 | { | ||
36 | return (x.val % (1 << FP_SHIFT)); | ||
37 | |||
38 | } | ||
39 | |||
40 | #define fp2str(x) x.val | ||
41 | /*(x.val >> FP_SHIFT), (x.val % (1 << FP_SHIFT)) */ | ||
42 | #define _FP_ "%ld/1024" | ||
43 | |||
44 | static inline fpbuf_t _floor(fp_t x) | ||
45 | { | ||
46 | return x.val >> FP_SHIFT; | ||
47 | } | ||
48 | |||
49 | /* FIXME: negative rounding */ | ||
50 | static inline fpbuf_t _round(fp_t x) | ||
51 | { | ||
52 | return _floor(x) + ((x.val >> ROUND_BIT) & 1); | ||
53 | } | ||
54 | |||
55 | /* multiply two fixed point values */ | ||
56 | static inline fp_t _mul(fp_t a, fp_t b) | ||
57 | { | ||
58 | return _fp((a.val * b.val) >> FP_SHIFT); | ||
59 | } | ||
60 | |||
61 | static inline fp_t _div(fp_t a, fp_t b) | ||
62 | { | ||
63 | /* try not to overflow */ | ||
64 | if (unlikely( a.val > (2l << (BITS_PER_LONG - FP_SHIFT)) )) | ||
65 | return _fp((a.val / b.val) << FP_SHIFT); | ||
66 | else | ||
67 | return _fp((a.val << FP_SHIFT) / b.val); | ||
68 | } | ||
69 | |||
70 | static inline fp_t _add(fp_t a, fp_t b) | ||
71 | { | ||
72 | return _fp(a.val + b.val); | ||
73 | } | ||
74 | |||
75 | static inline fp_t _sub(fp_t a, fp_t b) | ||
76 | { | ||
77 | return _fp(a.val - b.val); | ||
78 | } | ||
79 | |||
80 | static inline fp_t _neg(fp_t x) | ||
81 | { | ||
82 | return _fp(-x.val); | ||
83 | } | ||
84 | |||
85 | static inline fp_t _abs(fp_t x) | ||
86 | { | ||
87 | return _fp(abs(x.val)); | ||
88 | } | ||
89 | |||
90 | /* works the same as casting float/double to integer */ | ||
91 | static inline fpbuf_t _fp_to_integer(fp_t x) | ||
92 | { | ||
93 | return _floor(_abs(x)) * ((x.val > 0) ? 1 : -1); | ||
94 | } | ||
95 | |||
96 | static inline fp_t _integer_to_fp(fpbuf_t x) | ||
97 | { | ||
98 | return _frac(x,1); | ||
99 | } | ||
100 | |||
101 | static inline int _leq(fp_t a, fp_t b) | ||
102 | { | ||
103 | return a.val <= b.val; | ||
104 | } | ||
105 | |||
106 | static inline int _geq(fp_t a, fp_t b) | ||
107 | { | ||
108 | return a.val >= b.val; | ||
109 | } | ||
110 | |||
111 | static inline int _lt(fp_t a, fp_t b) | ||
112 | { | ||
113 | return a.val < b.val; | ||
114 | } | ||
115 | |||
116 | static inline int _gt(fp_t a, fp_t b) | ||
117 | { | ||
118 | return a.val > b.val; | ||
119 | } | ||
120 | |||
121 | static inline int _eq(fp_t a, fp_t b) | ||
122 | { | ||
123 | return a.val == b.val; | ||
124 | } | ||
125 | |||
126 | static inline fp_t _max(fp_t a, fp_t b) | ||
127 | { | ||
128 | if (a.val < b.val) | ||
129 | return b; | ||
130 | else | ||
131 | return a; | ||
132 | } | ||
133 | #endif | ||
134 | #endif | ||
diff --git a/include/litmus/gpu_affinity.h b/include/litmus/gpu_affinity.h new file mode 100644 index 000000000000..c29ff3de997c --- /dev/null +++ b/include/litmus/gpu_affinity.h | |||
@@ -0,0 +1,40 @@ | |||
1 | #ifndef LITMUS_GPU_AFFINITY_H | ||
2 | #define LITMUS_GPU_AFFINITY_H | ||
3 | |||
4 | #include <litmus/rt_param.h> | ||
5 | #include <litmus/sched_plugin.h> | ||
6 | #include <litmus/litmus.h> | ||
7 | |||
8 | void update_gpu_estimate(struct task_struct* t, lt_t observed); | ||
9 | gpu_migration_dist_t gpu_migration_distance(int a, int b); | ||
10 | |||
11 | static inline void reset_gpu_tracker(struct task_struct* t) | ||
12 | { | ||
13 | t->rt_param.accum_gpu_time = 0; | ||
14 | } | ||
15 | |||
16 | static inline void start_gpu_tracker(struct task_struct* t) | ||
17 | { | ||
18 | t->rt_param.gpu_time_stamp = litmus_clock(); | ||
19 | } | ||
20 | |||
21 | static inline void stop_gpu_tracker(struct task_struct* t) | ||
22 | { | ||
23 | lt_t now = litmus_clock(); | ||
24 | t->rt_param.accum_gpu_time += (now - t->rt_param.gpu_time_stamp); | ||
25 | } | ||
26 | |||
27 | static inline lt_t get_gpu_time(struct task_struct* t) | ||
28 | { | ||
29 | return t->rt_param.accum_gpu_time; | ||
30 | } | ||
31 | |||
32 | static inline lt_t get_gpu_estimate(struct task_struct* t, gpu_migration_dist_t dist) | ||
33 | { | ||
34 | lt_t val = _fp_to_integer(t->rt_param.gpu_migration_est[dist].est); | ||
35 | |||
36 | // minimum value is 1. | ||
37 | return ((val > 0) ? val : 1); | ||
38 | } | ||
39 | |||
40 | #endif \ No newline at end of file | ||
diff --git a/include/litmus/kfmlp_lock.h b/include/litmus/kfmlp_lock.h index 49156a9ba4ea..614cccad5307 100644 --- a/include/litmus/kfmlp_lock.h +++ b/include/litmus/kfmlp_lock.h | |||
@@ -4,6 +4,10 @@ | |||
4 | #include <litmus/litmus.h> | 4 | #include <litmus/litmus.h> |
5 | #include <litmus/locking.h> | 5 | #include <litmus/locking.h> |
6 | 6 | ||
7 | #ifdef CONFIG_LITMUS_AFFINITY_LOCKING | ||
8 | #include <litmus/kexclu_affinity.h> | ||
9 | #endif | ||
10 | |||
7 | /* struct for semaphore with priority inheritance */ | 11 | /* struct for semaphore with priority inheritance */ |
8 | struct kfmlp_queue | 12 | struct kfmlp_queue |
9 | { | 13 | { |
@@ -23,6 +27,10 @@ struct kfmlp_semaphore | |||
23 | 27 | ||
24 | struct kfmlp_queue *queues; /* array */ | 28 | struct kfmlp_queue *queues; /* array */ |
25 | struct kfmlp_queue *shortest_queue; /* pointer to shortest queue */ | 29 | struct kfmlp_queue *shortest_queue; /* pointer to shortest queue */ |
30 | |||
31 | #ifdef CONFIG_LITMUS_AFFINITY_LOCKING | ||
32 | struct kfmlp_affinity *aff_obs; | ||
33 | #endif | ||
26 | }; | 34 | }; |
27 | 35 | ||
28 | static inline struct kfmlp_semaphore* kfmlp_from_lock(struct litmus_lock* lock) | 36 | static inline struct kfmlp_semaphore* kfmlp_from_lock(struct litmus_lock* lock) |
@@ -36,4 +44,50 @@ int kfmlp_close(struct litmus_lock* l); | |||
36 | void kfmlp_free(struct litmus_lock* l); | 44 | void kfmlp_free(struct litmus_lock* l); |
37 | struct litmus_lock* kfmlp_new(struct litmus_lock_ops*, void* __user arg); | 45 | struct litmus_lock* kfmlp_new(struct litmus_lock_ops*, void* __user arg); |
38 | 46 | ||
39 | #endif \ No newline at end of file | 47 | #if defined(CONFIG_LITMUS_AFFINITY_LOCKING) && defined(CONFIG_LITMUS_NVIDIA) |
48 | |||
49 | struct kfmlp_queue_info | ||
50 | { | ||
51 | struct kfmlp_queue* q; | ||
52 | lt_t estimated_len; | ||
53 | }; | ||
54 | |||
55 | struct kfmlp_affinity; | ||
56 | |||
57 | struct kfmlp_affinity_ops | ||
58 | { | ||
59 | struct kfmlp_queue* (*advise_enqueue)(struct kfmlp_affinity* aff, struct task_struct* t); | ||
60 | struct task_struct* (*advise_steal)(struct kfmlp_affinity* aff, wait_queue_t** to_steal, struct kfmlp_queue** to_steal_from); | ||
61 | void (*notify_enqueue)(struct kfmlp_affinity* aff, struct kfmlp_queue* fq, struct task_struct* t); | ||
62 | void (*notify_dequeue)(struct kfmlp_affinity* aff, struct kfmlp_queue* fq, struct task_struct* t); | ||
63 | void (*notify_acquired)(struct kfmlp_affinity* aff, struct kfmlp_queue* fq, struct task_struct* t); | ||
64 | void (*notify_freed)(struct kfmlp_affinity* aff, struct kfmlp_queue* fq, struct task_struct* t); | ||
65 | }; | ||
66 | |||
67 | struct kfmlp_affinity | ||
68 | { | ||
69 | struct affinity_observer obs; | ||
70 | struct kfmlp_affinity_ops *ops; | ||
71 | struct kfmlp_queue_info *q_info; | ||
72 | struct kfmlp_queue_info *shortest_queue; | ||
73 | int offset; | ||
74 | }; | ||
75 | |||
76 | static inline struct kfmlp_affinity* kfmlp_aff_obs_from_aff_obs(struct affinity_observer* aff_obs) | ||
77 | { | ||
78 | return container_of(aff_obs, struct kfmlp_affinity, obs); | ||
79 | } | ||
80 | |||
81 | int kfmlp_aff_obs_close(struct affinity_observer*); | ||
82 | void kfmlp_aff_obs_free(struct affinity_observer*); | ||
83 | struct affinity_observer* kfmlp_gpu_aff_obs_new(struct affinity_observer_ops*, | ||
84 | void* __user arg); | ||
85 | struct affinity_observer* kfmlp_simple_gpu_aff_obs_new(struct affinity_observer_ops*, | ||
86 | void* __user arg); | ||
87 | |||
88 | |||
89 | #endif | ||
90 | |||
91 | #endif | ||
92 | |||
93 | |||
diff --git a/include/litmus/rt_param.h b/include/litmus/rt_param.h index cc638e9c55d1..ad46ab4c64cc 100644 --- a/include/litmus/rt_param.h +++ b/include/litmus/rt_param.h | |||
@@ -5,6 +5,8 @@ | |||
5 | #ifndef _LINUX_RT_PARAM_H_ | 5 | #ifndef _LINUX_RT_PARAM_H_ |
6 | #define _LINUX_RT_PARAM_H_ | 6 | #define _LINUX_RT_PARAM_H_ |
7 | 7 | ||
8 | #include <litmus/fpmath.h> | ||
9 | |||
8 | /* Litmus time type. */ | 10 | /* Litmus time type. */ |
9 | typedef unsigned long long lt_t; | 11 | typedef unsigned long long lt_t; |
10 | 12 | ||
@@ -57,6 +59,12 @@ struct affinity_observer_args | |||
57 | int lock_od; | 59 | int lock_od; |
58 | }; | 60 | }; |
59 | 61 | ||
62 | struct kfmlp_gpu_affinity_observer_args | ||
63 | { | ||
64 | struct affinity_observer_args obs; | ||
65 | int replica_to_gpu_offset; | ||
66 | }; | ||
67 | |||
60 | /* The definition of the data that is shared between the kernel and real-time | 68 | /* The definition of the data that is shared between the kernel and real-time |
61 | * tasks via a shared page (see litmus/ctrldev.c). | 69 | * tasks via a shared page (see litmus/ctrldev.c). |
62 | * | 70 | * |
@@ -116,6 +124,21 @@ enum klitirqd_sem_status | |||
116 | HELD | 124 | HELD |
117 | }; | 125 | }; |
118 | 126 | ||
127 | typedef enum gpu_migration_dist | ||
128 | { | ||
129 | MIG_LOCAL = 0, | ||
130 | MIG_NEAR = 1, | ||
131 | MIG_MED = 2, | ||
132 | MIG_FAR = 3, | ||
133 | |||
134 | MIG_LAST = MIG_FAR | ||
135 | } gpu_migration_dist_t; | ||
136 | |||
137 | typedef struct feedback_est{ | ||
138 | fp_t est; | ||
139 | fp_t accum_err; | ||
140 | } feedback_est_t; | ||
141 | |||
119 | /* RT task parameters for scheduling extensions | 142 | /* RT task parameters for scheduling extensions |
120 | * These parameters are inherited during clone and therefore must | 143 | * These parameters are inherited during clone and therefore must |
121 | * be explicitly set up before the task set is launched. | 144 | * be explicitly set up before the task set is launched. |
@@ -160,6 +183,20 @@ struct rt_param { | |||
160 | /* number of top-half interrupts handled on behalf of current job */ | 183 | /* number of top-half interrupts handled on behalf of current job */ |
161 | atomic_t nv_int_count; | 184 | atomic_t nv_int_count; |
162 | long unsigned int held_gpus; // bitmap of held GPUs. | 185 | long unsigned int held_gpus; // bitmap of held GPUs. |
186 | |||
187 | #ifdef CONFIG_LITMUS_AFFINITY_LOCKING | ||
188 | fp_t gpu_fb_param_a; | ||
189 | fp_t gpu_fb_param_b; | ||
190 | |||
191 | gpu_migration_dist_t gpu_migration; | ||
192 | int last_gpu; | ||
193 | feedback_est_t gpu_migration_est[MIG_LAST]; // local, near, med, far | ||
194 | |||
195 | lt_t accum_gpu_time; | ||
196 | lt_t gpu_time_stamp; | ||
197 | |||
198 | unsigned int suspend_gpu_tracker_on_block:1; | ||
199 | #endif | ||
163 | #endif | 200 | #endif |
164 | 201 | ||
165 | #ifdef CONFIG_LITMUS_LOCKING | 202 | #ifdef CONFIG_LITMUS_LOCKING |
diff --git a/litmus/Makefile b/litmus/Makefile index 1698afb75ec4..080cbf694a41 100644 --- a/litmus/Makefile +++ b/litmus/Makefile | |||
@@ -35,4 +35,4 @@ obj-$(CONFIG_LITMUS_SOFTIRQD) += litmus_softirq.o | |||
35 | obj-$(CONFIG_LITMUS_PAI_SOFTIRQD) += litmus_pai_softirq.o | 35 | obj-$(CONFIG_LITMUS_PAI_SOFTIRQD) += litmus_pai_softirq.o |
36 | obj-$(CONFIG_LITMUS_NVIDIA) += nvidia_info.o sched_trace_external.o | 36 | obj-$(CONFIG_LITMUS_NVIDIA) += nvidia_info.o sched_trace_external.o |
37 | 37 | ||
38 | obj-$(CONFIG_LITMUS_AFFINITY_LOCKING) += kexclu_affinity.o | 38 | obj-$(CONFIG_LITMUS_AFFINITY_LOCKING) += kexclu_affinity.o gpu_affinity.o |
diff --git a/litmus/gpu_affinity.c b/litmus/gpu_affinity.c new file mode 100644 index 000000000000..43171390bed7 --- /dev/null +++ b/litmus/gpu_affinity.c | |||
@@ -0,0 +1,72 @@ | |||
1 | |||
2 | #ifdef CONFIG_LITMUS_NVIDIA | ||
3 | |||
4 | #include <linux/sched.h> | ||
5 | #include <litmus/litmus.h> | ||
6 | #include <litmus/gpu_affinity.h> | ||
7 | |||
8 | static void update_estimate(feedback_est_t* fb, fp_t* a, fp_t* b, lt_t observed) | ||
9 | { | ||
10 | fp_t err, new; | ||
11 | fp_t actual = _frac(observed, 1); // observed is in ns, so beware of overflow! | ||
12 | |||
13 | err = _sub(actual, fb->est); | ||
14 | new = _add(_mul(*a, err), | ||
15 | _mul(*b, fb->accum_err)); | ||
16 | |||
17 | fb->est = new; | ||
18 | fb->accum_err = _add(fb->accum_err, err); | ||
19 | } | ||
20 | |||
21 | void update_gpu_estimate(struct task_struct *t, lt_t observed) | ||
22 | { | ||
23 | feedback_est_t *fb = &(tsk_rt(t)->gpu_migration_est[tsk_rt(t)->gpu_migration]); | ||
24 | |||
25 | TRACE_TASK(t, "GPU est update before (dist = %d): %d.%d\n", | ||
26 | tsk_rt(t)->gpu_migration, | ||
27 | _fp_to_integer(fb->est), | ||
28 | _point(fb->est)); | ||
29 | |||
30 | update_estimate(fb, | ||
31 | &tsk_rt(t)->gpu_fb_param_a, | ||
32 | &tsk_rt(t)->gpu_fb_param_b, | ||
33 | observed); | ||
34 | |||
35 | TRACE_TASK(t, "GPU est update after (dist = %d): %d.%d\n", | ||
36 | tsk_rt(t)->gpu_migration, | ||
37 | _fp_to_integer(fb->est), | ||
38 | _point(fb->est)); | ||
39 | } | ||
40 | |||
41 | gpu_migration_dist_t gpu_migration_distance(int a, int b) | ||
42 | { | ||
43 | // GPUs organized in a binary hierarchy, no more than 2^MIG_LAST GPUs | ||
44 | int i; | ||
45 | int level; | ||
46 | int max_level; | ||
47 | |||
48 | if(unlikely(a < 0 || b < 0)) { | ||
49 | return MIG_LAST; | ||
50 | } | ||
51 | |||
52 | if(a == b) { | ||
53 | return MIG_LOCAL; | ||
54 | } | ||
55 | |||
56 | for(i = 1, level = 2, max_level = 1<<MIG_LAST; | ||
57 | level <= max_level; | ||
58 | ++i, level <<= 1) { | ||
59 | if(a/level == b/level) { | ||
60 | return (gpu_migration_dist_t)(i); | ||
61 | } | ||
62 | } | ||
63 | |||
64 | WARN_ON(1); | ||
65 | return MIG_LAST; | ||
66 | } | ||
67 | |||
68 | |||
69 | |||
70 | |||
71 | #endif | ||
72 | |||
diff --git a/litmus/kfmlp_lock.c b/litmus/kfmlp_lock.c index f7bb17103383..b30e5b589882 100644 --- a/litmus/kfmlp_lock.c +++ b/litmus/kfmlp_lock.c | |||
@@ -3,9 +3,14 @@ | |||
3 | 3 | ||
4 | #include <litmus/trace.h> | 4 | #include <litmus/trace.h> |
5 | #include <litmus/sched_plugin.h> | 5 | #include <litmus/sched_plugin.h> |
6 | #include <litmus/fdso.h> | ||
7 | |||
6 | #include <litmus/kfmlp_lock.h> | 8 | #include <litmus/kfmlp_lock.h> |
7 | 9 | ||
8 | //#include <litmus/edf_common.h> | 10 | #if defined(CONFIG_LITMUS_AFFINITY_LOCKING) && defined(CONFIG_LITMUS_NVIDIA) |
11 | #include <litmus/gpu_affinity.h> | ||
12 | #include <litmus/nvidia_info.h> | ||
13 | #endif | ||
9 | 14 | ||
10 | static inline int kfmlp_get_idx(struct kfmlp_semaphore* sem, | 15 | static inline int kfmlp_get_idx(struct kfmlp_semaphore* sem, |
11 | struct kfmlp_queue* queue) | 16 | struct kfmlp_queue* queue) |
@@ -67,74 +72,177 @@ static inline struct kfmlp_queue* kfmlp_find_shortest(struct kfmlp_semaphore* se | |||
67 | return(shortest); | 72 | return(shortest); |
68 | } | 73 | } |
69 | 74 | ||
70 | static struct task_struct* kfmlp_remove_hp_waiter(struct kfmlp_semaphore* sem) | 75 | |
76 | // TODO: BREAK THIS UP INTO TWO STEPS: | ||
77 | // 1) task to steal (and from what queue) | ||
78 | // 2) update queues | ||
79 | static struct task_struct* kfmlp_select_hp_steal(struct kfmlp_semaphore* sem, wait_queue_t** to_steal, struct kfmlp_queue** to_steal_from) | ||
71 | { | 80 | { |
72 | /* must hold sem->lock */ | 81 | /* must hold sem->lock */ |
73 | |||
74 | struct kfmlp_queue *my_queue = NULL; | ||
75 | struct task_struct *max_hp = NULL; | ||
76 | |||
77 | 82 | ||
78 | struct list_head *pos; | ||
79 | struct task_struct *queued; | ||
80 | int i; | 83 | int i; |
81 | 84 | ||
85 | *to_steal = NULL; | ||
86 | *to_steal_from = NULL; | ||
87 | |||
82 | for(i = 0; i < sem->num_resources; ++i) | 88 | for(i = 0; i < sem->num_resources; ++i) |
83 | { | 89 | { |
84 | if( (sem->queues[i].count > 1) && | 90 | if( (sem->queues[i].count > 1) && |
85 | ((my_queue == NULL) || | 91 | ((*to_steal_from == NULL) || |
86 | //(edf_higher_prio(sem->queues[i].hp_waiter, my_queue->hp_waiter))) ) | 92 | //(edf_higher_prio(sem->queues[i].hp_waiter, my_queue->hp_waiter))) ) |
87 | (litmus->compare(sem->queues[i].hp_waiter, my_queue->hp_waiter))) ) | 93 | (litmus->compare(sem->queues[i].hp_waiter, (*to_steal_from)->hp_waiter))) ) |
88 | { | 94 | { |
89 | my_queue = &sem->queues[i]; | 95 | *to_steal_from = &sem->queues[i]; |
90 | } | 96 | } |
91 | } | 97 | } |
92 | 98 | ||
93 | if(my_queue) | 99 | if(*to_steal_from) |
94 | { | 100 | { |
95 | max_hp = my_queue->hp_waiter; | 101 | struct list_head *pos; |
96 | 102 | list_for_each(pos, &(*to_steal_from)->wait.task_list) | |
97 | BUG_ON(!max_hp); | ||
98 | |||
99 | TRACE_CUR("queue %d: stealing %s/%d from queue %d\n", | ||
100 | kfmlp_get_idx(sem, my_queue), | ||
101 | max_hp->comm, max_hp->pid, | ||
102 | kfmlp_get_idx(sem, my_queue)); | ||
103 | |||
104 | my_queue->hp_waiter = kfmlp_find_hp_waiter(my_queue, max_hp); | ||
105 | |||
106 | if(tsk_rt(my_queue->owner)->inh_task == max_hp) | ||
107 | { | ||
108 | litmus->decrease_prio(my_queue->owner, my_queue->hp_waiter); | ||
109 | } | ||
110 | |||
111 | list_for_each(pos, &my_queue->wait.task_list) | ||
112 | { | 103 | { |
113 | queued = (struct task_struct*) list_entry(pos, wait_queue_t, | 104 | wait_queue_t *node = list_entry(pos, wait_queue_t, task_list); |
114 | task_list)->private; | 105 | struct task_struct *queued = (struct task_struct*) node->private; |
115 | /* Compare task prios, find high prio task. */ | 106 | /* Compare task prios, find high prio task. */ |
116 | if (queued == max_hp) | 107 | if (queued == (*to_steal_from)->hp_waiter) |
117 | { | 108 | { |
118 | /* | 109 | *to_steal = node; |
119 | TRACE_CUR("queue %d: found entry in wait queue. REMOVING!\n", | 110 | |
120 | kfmlp_get_idx(sem, my_queue)); | 111 | TRACE_CUR("steal: selected %s/%d from queue %d\n", |
121 | */ | 112 | queued->comm, queued->pid, |
122 | __remove_wait_queue(&my_queue->wait, | 113 | kfmlp_get_idx(sem, *to_steal_from)); |
123 | list_entry(pos, wait_queue_t, task_list)); | 114 | |
124 | break; | 115 | return queued; |
125 | } | 116 | } |
126 | } | 117 | } |
127 | --(my_queue->count); | ||
128 | } | 118 | } |
129 | 119 | ||
130 | return(max_hp); | 120 | return NULL; |
121 | } | ||
122 | |||
123 | static void kfmlp_steal_node(struct kfmlp_semaphore *sem, | ||
124 | struct kfmlp_queue *dst, | ||
125 | wait_queue_t *wait, | ||
126 | struct kfmlp_queue *src) | ||
127 | { | ||
128 | struct task_struct* t = (struct task_struct*) wait->private; | ||
129 | |||
130 | __remove_wait_queue(&src->wait, wait); | ||
131 | --(src->count); | ||
132 | |||
133 | if(t == src->hp_waiter) { | ||
134 | src->hp_waiter = kfmlp_find_hp_waiter(src, NULL); | ||
135 | |||
136 | if(src->owner && tsk_rt(src->owner)->inh_task == t) { | ||
137 | litmus->decrease_prio(src->owner, src->hp_waiter); | ||
138 | } | ||
139 | } | ||
140 | |||
141 | if(sem->shortest_queue->count > src->count) { | ||
142 | sem->shortest_queue = src; | ||
143 | } | ||
144 | |||
145 | #ifdef CONFIG_LITMUS_AFFINITY_LOCKING | ||
146 | if(sem->aff_obs) { | ||
147 | sem->aff_obs->ops->notify_dequeue(sem->aff_obs, src, t); | ||
148 | } | ||
149 | #endif | ||
150 | |||
151 | init_waitqueue_entry(wait, t); | ||
152 | __add_wait_queue_tail_exclusive(&dst->wait, wait); | ||
153 | ++(dst->count); | ||
154 | |||
155 | if(litmus->compare(t, dst->hp_waiter)) { | ||
156 | dst->hp_waiter = t; | ||
157 | |||
158 | if(dst->owner && litmus->compare(t, dst->owner)) | ||
159 | { | ||
160 | litmus->increase_prio(dst->owner, t); | ||
161 | } | ||
162 | } | ||
163 | |||
164 | #ifdef CONFIG_LITMUS_AFFINITY_LOCKING | ||
165 | if(sem->aff_obs) { | ||
166 | sem->aff_obs->ops->notify_enqueue(sem->aff_obs, dst, t); | ||
167 | } | ||
168 | #endif | ||
131 | } | 169 | } |
170 | //// TODO: BREAK THIS UP INTO TWO STEPS: | ||
171 | //// 1) task to steal (and from what queue) | ||
172 | //// 2) update queues | ||
173 | //static struct task_struct* kfmlp_remove_hp_waiter(struct kfmlp_semaphore* sem) | ||
174 | //{ | ||
175 | // /* must hold sem->lock */ | ||
176 | // | ||
177 | // struct kfmlp_queue *my_queue = NULL; | ||
178 | // struct task_struct *max_hp = NULL; | ||
179 | // | ||
180 | // struct list_head *pos; | ||
181 | // struct task_struct *queued; | ||
182 | // int i; | ||
183 | // | ||
184 | // for(i = 0; i < sem->num_resources; ++i) | ||
185 | // { | ||
186 | // if( (sem->queues[i].count > 1) && | ||
187 | // ((my_queue == NULL) || | ||
188 | // //(edf_higher_prio(sem->queues[i].hp_waiter, my_queue->hp_waiter))) ) | ||
189 | // (litmus->compare(sem->queues[i].hp_waiter, my_queue->hp_waiter))) ) | ||
190 | // { | ||
191 | // my_queue = &sem->queues[i]; | ||
192 | // } | ||
193 | // } | ||
194 | // | ||
195 | // if(my_queue) | ||
196 | // { | ||
197 | // max_hp = my_queue->hp_waiter; | ||
198 | // | ||
199 | // BUG_ON(!max_hp); | ||
200 | // | ||
201 | // TRACE_CUR("queue %d: stealing %s/%d from queue %d\n", | ||
202 | // kfmlp_get_idx(sem, my_queue), | ||
203 | // max_hp->comm, max_hp->pid, | ||
204 | // kfmlp_get_idx(sem, my_queue)); | ||
205 | // | ||
206 | // my_queue->hp_waiter = kfmlp_find_hp_waiter(my_queue, max_hp); | ||
207 | // | ||
208 | // if(tsk_rt(my_queue->owner)->inh_task == max_hp) | ||
209 | // { | ||
210 | // litmus->decrease_prio(my_queue->owner, my_queue->hp_waiter); | ||
211 | // } | ||
212 | // | ||
213 | // list_for_each(pos, &my_queue->wait.task_list) | ||
214 | // { | ||
215 | // queued = (struct task_struct*) list_entry(pos, wait_queue_t, | ||
216 | // task_list)->private; | ||
217 | // /* Compare task prios, find high prio task. */ | ||
218 | // if (queued == max_hp) | ||
219 | // { | ||
220 | // /* | ||
221 | // TRACE_CUR("queue %d: found entry in wait queue. REMOVING!\n", | ||
222 | // kfmlp_get_idx(sem, my_queue)); | ||
223 | // */ | ||
224 | // __remove_wait_queue(&my_queue->wait, | ||
225 | // list_entry(pos, wait_queue_t, task_list)); | ||
226 | // break; | ||
227 | // } | ||
228 | // } | ||
229 | // --(my_queue->count); | ||
230 | // | ||
231 | //#ifdef CONFIG_LITMUS_AFFINITY_LOCKING | ||
232 | // if(sem->aff_obs) { | ||
233 | // sem->aff_obs->ops->notify_dequeue(sem->aff_obs, my_queue, max_hp); | ||
234 | // } | ||
235 | //#endif | ||
236 | // } | ||
237 | // | ||
238 | // return(max_hp); | ||
239 | //} | ||
132 | 240 | ||
133 | int kfmlp_lock(struct litmus_lock* l) | 241 | int kfmlp_lock(struct litmus_lock* l) |
134 | { | 242 | { |
135 | struct task_struct* t = current; | 243 | struct task_struct* t = current; |
136 | struct kfmlp_semaphore *sem = kfmlp_from_lock(l); | 244 | struct kfmlp_semaphore *sem = kfmlp_from_lock(l); |
137 | struct kfmlp_queue* my_queue; | 245 | struct kfmlp_queue* my_queue = NULL; |
138 | wait_queue_t wait; | 246 | wait_queue_t wait; |
139 | unsigned long flags; | 247 | unsigned long flags; |
140 | 248 | ||
@@ -143,7 +251,16 @@ int kfmlp_lock(struct litmus_lock* l) | |||
143 | 251 | ||
144 | spin_lock_irqsave(&sem->lock, flags); | 252 | spin_lock_irqsave(&sem->lock, flags); |
145 | 253 | ||
254 | #ifdef CONFIG_LITMUS_AFFINITY_LOCKING | ||
255 | if(sem->aff_obs) { | ||
256 | my_queue = sem->aff_obs->ops->advise_enqueue(sem->aff_obs, t); | ||
257 | } | ||
258 | if(!my_queue) { | ||
259 | my_queue = sem->shortest_queue; | ||
260 | } | ||
261 | #else | ||
146 | my_queue = sem->shortest_queue; | 262 | my_queue = sem->shortest_queue; |
263 | #endif | ||
147 | 264 | ||
148 | if (my_queue->owner) { | 265 | if (my_queue->owner) { |
149 | /* resource is not free => must suspend and wait */ | 266 | /* resource is not free => must suspend and wait */ |
@@ -170,7 +287,17 @@ int kfmlp_lock(struct litmus_lock* l) | |||
170 | } | 287 | } |
171 | 288 | ||
172 | ++(my_queue->count); | 289 | ++(my_queue->count); |
290 | |||
291 | #ifdef CONFIG_LITMUS_AFFINITY_LOCKING | ||
292 | if(my_queue == sem->shortest_queue) { | ||
293 | sem->shortest_queue = kfmlp_find_shortest(sem, my_queue); | ||
294 | } | ||
295 | if(sem->aff_obs) { | ||
296 | sem->aff_obs->ops->notify_enqueue(sem->aff_obs, my_queue, t); | ||
297 | } | ||
298 | #else | ||
173 | sem->shortest_queue = kfmlp_find_shortest(sem, my_queue); | 299 | sem->shortest_queue = kfmlp_find_shortest(sem, my_queue); |
300 | #endif | ||
174 | 301 | ||
175 | /* release lock before sleeping */ | 302 | /* release lock before sleeping */ |
176 | spin_unlock_irqrestore(&sem->lock, flags); | 303 | spin_unlock_irqrestore(&sem->lock, flags); |
@@ -206,7 +333,18 @@ int kfmlp_lock(struct litmus_lock* l) | |||
206 | my_queue->owner = t; | 333 | my_queue->owner = t; |
207 | 334 | ||
208 | ++(my_queue->count); | 335 | ++(my_queue->count); |
209 | sem->shortest_queue = kfmlp_find_shortest(sem, my_queue); | 336 | |
337 | #ifdef CONFIG_LITMUS_AFFINITY_LOCKING | ||
338 | if(my_queue == sem->shortest_queue) { | ||
339 | sem->shortest_queue = kfmlp_find_shortest(sem, my_queue); | ||
340 | } | ||
341 | if(sem->aff_obs) { | ||
342 | sem->aff_obs->ops->notify_enqueue(sem->aff_obs, my_queue, t); | ||
343 | sem->aff_obs->ops->notify_acquired(sem->aff_obs, my_queue, t); | ||
344 | } | ||
345 | #else | ||
346 | sem->shortest_queue = kfmlp_find_shortest(sem, my_queue); | ||
347 | #endif | ||
210 | 348 | ||
211 | spin_unlock_irqrestore(&sem->lock, flags); | 349 | spin_unlock_irqrestore(&sem->lock, flags); |
212 | } | 350 | } |
@@ -219,7 +357,7 @@ int kfmlp_unlock(struct litmus_lock* l) | |||
219 | { | 357 | { |
220 | struct task_struct *t = current, *next; | 358 | struct task_struct *t = current, *next; |
221 | struct kfmlp_semaphore *sem = kfmlp_from_lock(l); | 359 | struct kfmlp_semaphore *sem = kfmlp_from_lock(l); |
222 | struct kfmlp_queue *my_queue; | 360 | struct kfmlp_queue *my_queue, *to_steal_from; |
223 | unsigned long flags; | 361 | unsigned long flags; |
224 | int err = 0; | 362 | int err = 0; |
225 | 363 | ||
@@ -227,29 +365,43 @@ int kfmlp_unlock(struct litmus_lock* l) | |||
227 | 365 | ||
228 | my_queue = kfmlp_get_queue(sem, t); | 366 | my_queue = kfmlp_get_queue(sem, t); |
229 | 367 | ||
230 | if (!my_queue) { | 368 | if (!my_queue || my_queue->owner != t) { |
231 | err = -EINVAL; | 369 | err = -EINVAL; |
232 | goto out; | 370 | goto out; |
233 | } | 371 | } |
234 | 372 | ||
373 | my_queue->owner = NULL; // clear ownership | ||
374 | --(my_queue->count); | ||
375 | |||
376 | if(my_queue->count < sem->shortest_queue->count) | ||
377 | { | ||
378 | sem->shortest_queue = my_queue; | ||
379 | } | ||
380 | |||
381 | #ifdef CONFIG_LITMUS_AFFINITY_LOCKING | ||
382 | if(sem->aff_obs) { | ||
383 | sem->aff_obs->ops->notify_dequeue(sem->aff_obs, my_queue, t); | ||
384 | sem->aff_obs->ops->notify_freed(sem->aff_obs, my_queue, t); | ||
385 | } | ||
386 | #endif | ||
387 | |||
388 | /* we lose the benefit of priority inheritance (if any) */ | ||
389 | if (tsk_rt(t)->inh_task) | ||
390 | litmus->decrease_prio(t, NULL); | ||
391 | |||
392 | |||
235 | /* check if there are jobs waiting for this resource */ | 393 | /* check if there are jobs waiting for this resource */ |
394 | RETRY: | ||
236 | next = __waitqueue_remove_first(&my_queue->wait); | 395 | next = __waitqueue_remove_first(&my_queue->wait); |
237 | if (next) { | 396 | if (next) { |
238 | /* | ||
239 | TRACE_CUR("queue %d: ASSIGNING %s/%d as owner - next\n", | ||
240 | kfmlp_get_idx(sem, my_queue), | ||
241 | next->comm, next->pid); | ||
242 | */ | ||
243 | /* next becomes the resouce holder */ | 397 | /* next becomes the resouce holder */ |
244 | my_queue->owner = next; | 398 | my_queue->owner = next; |
245 | 399 | ||
246 | --(my_queue->count); | 400 | #ifdef CONFIG_LITMUS_AFFINITY_LOCKING |
247 | // the '=' of '<=' is a dumb method to attempt to build | 401 | if(sem->aff_obs) { |
248 | // affinity until tasks can tell us where they ran last... | 402 | sem->aff_obs->ops->notify_acquired(sem->aff_obs, my_queue, next); |
249 | if(my_queue->count <= sem->shortest_queue->count) | 403 | } |
250 | { | 404 | #endif |
251 | sem->shortest_queue = my_queue; | ||
252 | } | ||
253 | 405 | ||
254 | TRACE_CUR("queue %d: lock ownership passed to %s/%d\n", | 406 | TRACE_CUR("queue %d: lock ownership passed to %s/%d\n", |
255 | kfmlp_get_idx(sem, my_queue), next->comm, next->pid); | 407 | kfmlp_get_idx(sem, my_queue), next->comm, next->pid); |
@@ -257,10 +409,6 @@ int kfmlp_unlock(struct litmus_lock* l) | |||
257 | /* determine new hp_waiter if necessary */ | 409 | /* determine new hp_waiter if necessary */ |
258 | if (next == my_queue->hp_waiter) { | 410 | if (next == my_queue->hp_waiter) { |
259 | TRACE_TASK(next, "was highest-prio waiter\n"); | 411 | TRACE_TASK(next, "was highest-prio waiter\n"); |
260 | /* next has the highest priority --- it doesn't need to | ||
261 | * inherit. However, we need to make sure that the | ||
262 | * next-highest priority in the queue is reflected in | ||
263 | * hp_waiter. */ | ||
264 | my_queue->hp_waiter = kfmlp_find_hp_waiter(my_queue, next); | 412 | my_queue->hp_waiter = kfmlp_find_hp_waiter(my_queue, next); |
265 | if (my_queue->hp_waiter) | 413 | if (my_queue->hp_waiter) |
266 | TRACE_TASK(my_queue->hp_waiter, "queue %d: is new highest-prio waiter\n", kfmlp_get_idx(sem, my_queue)); | 414 | TRACE_TASK(my_queue->hp_waiter, "queue %d: is new highest-prio waiter\n", kfmlp_get_idx(sem, my_queue)); |
@@ -278,46 +426,34 @@ int kfmlp_unlock(struct litmus_lock* l) | |||
278 | } | 426 | } |
279 | else | 427 | else |
280 | { | 428 | { |
281 | TRACE_CUR("queue %d: looking to steal someone...\n", kfmlp_get_idx(sem, my_queue)); | 429 | // TODO: put this stealing logic before we attempt to release |
282 | 430 | // our resource. (simplifies code and gets rid of ugly goto RETRY. | |
283 | next = kfmlp_remove_hp_waiter(sem); /* returns NULL if nothing to steal */ | 431 | wait_queue_t *wait; |
284 | 432 | ||
285 | /* | 433 | TRACE_CUR("queue %d: looking to steal someone...\n", kfmlp_get_idx(sem, my_queue)); |
286 | if(next) | 434 | |
287 | TRACE_CUR("queue %d: ASSIGNING %s/%d as owner - steal\n", | 435 | #ifdef CONFIG_LITMUS_AFFINITY_LOCKING |
288 | kfmlp_get_idx(sem, my_queue), | 436 | next = (sem->aff_obs) ? |
289 | next->comm, next->pid); | 437 | sem->aff_obs->ops->advise_steal(sem->aff_obs, &wait, &to_steal_from) : |
290 | */ | 438 | kfmlp_select_hp_steal(sem, &wait, &to_steal_from); |
291 | 439 | #else | |
292 | my_queue->owner = next; | 440 | next = kfmlp_select_hp_steal(sem, &wait, &to_steal_from); |
441 | #endif | ||
293 | 442 | ||
294 | if(next) | 443 | if(next) { |
295 | { | 444 | kfmlp_steal_node(sem, my_queue, wait, to_steal_from); |
296 | TRACE_CUR("queue %d: lock ownership passed to %s/%d (which was stolen)\n", | ||
297 | kfmlp_get_idx(sem, my_queue), | ||
298 | next->comm, next->pid); | ||
299 | 445 | ||
300 | /* wake up next */ | 446 | TRACE_CUR("queued %d: stole %s/%d from queue %d\n", |
301 | wake_up_process(next); | 447 | next->comm, next->pid, |
448 | kfmlp_get_idx(sem, to_steal_from)); | ||
449 | |||
450 | goto RETRY; // will succeed this time. | ||
302 | } | 451 | } |
303 | else | 452 | else { |
304 | { | ||
305 | TRACE_CUR("queue %d: no one to steal.\n", kfmlp_get_idx(sem, my_queue)); | 453 | TRACE_CUR("queue %d: no one to steal.\n", kfmlp_get_idx(sem, my_queue)); |
306 | |||
307 | --(my_queue->count); | ||
308 | // the '=' of '<=' is a dumb method to attempt to build | ||
309 | // affinity until tasks can tell us where they ran last... | ||
310 | if(my_queue->count <= sem->shortest_queue->count) | ||
311 | { | ||
312 | sem->shortest_queue = my_queue; | ||
313 | } | ||
314 | } | 454 | } |
315 | } | 455 | } |
316 | 456 | ||
317 | /* we lose the benefit of priority inheritance (if any) */ | ||
318 | if (tsk_rt(t)->inh_task) | ||
319 | litmus->decrease_prio(t, NULL); | ||
320 | |||
321 | out: | 457 | out: |
322 | spin_unlock_irqrestore(&sem->lock, flags); | 458 | spin_unlock_irqrestore(&sem->lock, flags); |
323 | 459 | ||
@@ -403,3 +539,337 @@ struct litmus_lock* kfmlp_new(struct litmus_lock_ops* ops, void* __user args) | |||
403 | 539 | ||
404 | return &sem->litmus_lock; | 540 | return &sem->litmus_lock; |
405 | } | 541 | } |
542 | |||
543 | |||
544 | |||
545 | |||
546 | #if defined(CONFIG_LITMUS_AFFINITY_LOCKING) && defined(CONFIG_LITMUS_NVIDIA) | ||
547 | |||
548 | int kfmlp_aff_obs_close(struct affinity_observer* obs) | ||
549 | { | ||
550 | return 0; | ||
551 | } | ||
552 | |||
553 | void kfmlp_aff_obs_free(struct affinity_observer* obs) | ||
554 | { | ||
555 | struct kfmlp_affinity *kfmlp_aff = kfmlp_aff_obs_from_aff_obs(obs); | ||
556 | kfree(kfmlp_aff->q_info); | ||
557 | kfree(kfmlp_aff); | ||
558 | } | ||
559 | |||
560 | static struct affinity_observer* kfmlp_aff_obs_new(struct affinity_observer_ops* ops, | ||
561 | struct kfmlp_affinity_ops* kfmlp_ops, | ||
562 | void* __user args) | ||
563 | { | ||
564 | struct kfmlp_affinity* kfmlp_aff; | ||
565 | struct kfmlp_gpu_affinity_observer_args aff_args; | ||
566 | struct kfmlp_semaphore* sem; | ||
567 | int i; | ||
568 | unsigned long flags; | ||
569 | |||
570 | if(!access_ok(VERIFY_READ, args, sizeof(aff_args))) | ||
571 | { | ||
572 | return(NULL); | ||
573 | } | ||
574 | if(__copy_from_user(&aff_args, args, sizeof(aff_args))) | ||
575 | { | ||
576 | return(NULL); | ||
577 | } | ||
578 | |||
579 | sem = (struct kfmlp_semaphore*) get_lock_from_od(aff_args.obs.lock_od); | ||
580 | |||
581 | if(sem->litmus_lock.type != KFMLP_SEM) | ||
582 | { | ||
583 | TRACE_CUR("Lock type not supported. Type = %d\n", sem->litmus_lock.type); | ||
584 | return(NULL); | ||
585 | } | ||
586 | |||
587 | kfmlp_aff = kmalloc(sizeof(*kfmlp_aff), GFP_KERNEL); | ||
588 | if(!kfmlp_aff) | ||
589 | { | ||
590 | return(NULL); | ||
591 | } | ||
592 | |||
593 | kfmlp_aff->q_info = kmalloc(sizeof(struct kfmlp_queue_info)*sem->num_resources, GFP_KERNEL); | ||
594 | if(!kfmlp_aff->q_info) | ||
595 | { | ||
596 | kfree(kfmlp_aff); | ||
597 | return(NULL); | ||
598 | } | ||
599 | |||
600 | kfmlp_aff->obs.ops = ops; | ||
601 | kfmlp_aff->ops = kfmlp_ops; | ||
602 | kfmlp_aff->offset = aff_args.replica_to_gpu_offset; | ||
603 | |||
604 | for(i = 0; i < sem->num_resources; ++i) | ||
605 | { | ||
606 | kfmlp_aff->q_info[i].q = &sem->queues[i]; | ||
607 | kfmlp_aff->q_info[i].estimated_len = 0; | ||
608 | } | ||
609 | |||
610 | spin_lock_irqsave(&sem->lock, flags); | ||
611 | sem->aff_obs = kfmlp_aff; | ||
612 | kfmlp_aff->shortest_queue = &kfmlp_aff->q_info[kfmlp_get_idx(sem, sem->shortest_queue)]; | ||
613 | spin_unlock_irqrestore(&sem->lock, flags); | ||
614 | |||
615 | return &kfmlp_aff->obs; | ||
616 | } | ||
617 | |||
618 | |||
619 | |||
620 | |||
621 | // Smart KFMLP Affinity | ||
622 | |||
623 | static inline struct kfmlp_queue_info* kfmlp_aff_find_shortest(struct kfmlp_affinity* aff) | ||
624 | { | ||
625 | struct kfmlp_semaphore *sem = kfmlp_from_lock(aff->obs.lock); | ||
626 | struct kfmlp_queue_info *shortest = &aff->q_info[0]; | ||
627 | int i; | ||
628 | |||
629 | for(i = 1; i < sem->num_resources; ++i) { | ||
630 | if(aff->q_info[i].estimated_len < shortest->estimated_len) { | ||
631 | shortest = &aff->q_info[i]; | ||
632 | } | ||
633 | } | ||
634 | |||
635 | return(shortest); | ||
636 | } | ||
637 | |||
638 | struct kfmlp_queue* gpu_kfmlp_advise_enqueue(struct kfmlp_affinity* aff, struct task_struct* t) | ||
639 | { | ||
640 | struct kfmlp_semaphore *sem = kfmlp_from_lock(aff->obs.lock); | ||
641 | lt_t min_len; | ||
642 | struct kfmlp_queue_info *shortest; | ||
643 | struct kfmlp_queue *to_enqueue; | ||
644 | int i; | ||
645 | |||
646 | // simply pick the shortest queue if, we have no affinity, or we have | ||
647 | // affinity with the shortest | ||
648 | if((tsk_rt(t)->last_gpu < 0) || | ||
649 | ((kfmlp_get_idx(sem, aff->shortest_queue->q) + aff->offset) == tsk_rt(t)->last_gpu)) { | ||
650 | // we have affinity with the shorest queue. pick it. | ||
651 | to_enqueue = aff->shortest_queue->q; | ||
652 | |||
653 | TRACE_CUR("special case: no affinity or have affinity with shortest\n"); | ||
654 | |||
655 | goto out; | ||
656 | } | ||
657 | |||
658 | // enqueue where we will have the shortest time to completion | ||
659 | |||
660 | shortest = &aff->q_info[0]; | ||
661 | min_len = shortest->estimated_len + get_gpu_estimate(t, gpu_migration_distance(tsk_rt(t)->last_gpu, 0 + aff->offset)); | ||
662 | |||
663 | for(i = 1; i < sem->num_resources; ++i) { | ||
664 | lt_t est_len = | ||
665 | aff->q_info[i].estimated_len + | ||
666 | get_gpu_estimate(t, gpu_migration_distance(tsk_rt(t)->last_gpu, i + aff->offset)); | ||
667 | |||
668 | if(est_len < min_len) { | ||
669 | shortest = &aff->q_info[i]; | ||
670 | min_len = est_len; | ||
671 | } | ||
672 | } | ||
673 | to_enqueue = shortest->q; | ||
674 | |||
675 | out: | ||
676 | TRACE_CUR("enqueue on fq %d (non-aff wanted fq %d)\n", | ||
677 | kfmlp_get_idx(sem, to_enqueue), | ||
678 | kfmlp_get_idx(sem, sem->shortest_queue)); | ||
679 | |||
680 | return to_enqueue; | ||
681 | } | ||
682 | |||
683 | struct task_struct* gpu_kfmlp_advise_steal(struct kfmlp_affinity* aff, wait_queue_t** to_steal, struct kfmlp_queue** to_steal_from) | ||
684 | { | ||
685 | struct kfmlp_semaphore *sem = kfmlp_from_lock(aff->obs.lock); | ||
686 | |||
687 | // For now, just steal from the shortest (by number) queue. | ||
688 | // TODO: Implement affinity-aware stealing. | ||
689 | |||
690 | return kfmlp_select_hp_steal(sem, to_steal, to_steal_from); | ||
691 | } | ||
692 | |||
693 | |||
694 | void gpu_kfmlp_notify_enqueue(struct kfmlp_affinity* aff, struct kfmlp_queue* fq, struct task_struct* t) | ||
695 | { | ||
696 | struct kfmlp_semaphore *sem = kfmlp_from_lock(aff->obs.lock); | ||
697 | int replica = kfmlp_get_idx(sem, fq); | ||
698 | int gpu = aff->offset + replica; | ||
699 | struct kfmlp_queue_info *info = &aff->q_info[replica]; | ||
700 | lt_t est_time; | ||
701 | |||
702 | if(current == t) { | ||
703 | tsk_rt(t)->suspend_gpu_tracker_on_block = 1; | ||
704 | } | ||
705 | |||
706 | est_time = get_gpu_estimate(t, gpu_migration_distance(tsk_rt(t)->last_gpu, gpu)); | ||
707 | info->estimated_len += est_time; | ||
708 | |||
709 | TRACE_CUR("fq %d est len is now %llu\n", | ||
710 | kfmlp_get_idx(sem, aff->shortest_queue->q), | ||
711 | aff->shortest_queue->estimated_len); | ||
712 | |||
713 | if(aff->shortest_queue == info) { | ||
714 | // we may no longer be the shortest | ||
715 | aff->shortest_queue = kfmlp_aff_find_shortest(aff); | ||
716 | |||
717 | TRACE_CUR("shortest queue is fq %d (with %d in queue) has est len %llu\n", | ||
718 | kfmlp_get_idx(sem, aff->shortest_queue->q), | ||
719 | aff->shortest_queue->q->count, | ||
720 | aff->shortest_queue->estimated_len); | ||
721 | } | ||
722 | } | ||
723 | |||
724 | void gpu_kfmlp_notify_dequeue(struct kfmlp_affinity* aff, struct kfmlp_queue* fq, struct task_struct* t) | ||
725 | { | ||
726 | struct kfmlp_semaphore *sem = kfmlp_from_lock(aff->obs.lock); | ||
727 | int replica = kfmlp_get_idx(sem, fq); | ||
728 | int gpu = aff->offset + replica; | ||
729 | struct kfmlp_queue_info *info = &aff->q_info[replica]; | ||
730 | lt_t est_time = get_gpu_estimate(t, gpu_migration_distance(tsk_rt(t)->last_gpu, gpu)); | ||
731 | |||
732 | if(est_time > info->estimated_len) { | ||
733 | WARN_ON(1); | ||
734 | info->estimated_len = 0; | ||
735 | } | ||
736 | else { | ||
737 | info->estimated_len -= est_time; | ||
738 | } | ||
739 | |||
740 | TRACE_CUR("fq %d est len is now %llu\n", | ||
741 | kfmlp_get_idx(sem, info->q), | ||
742 | info->estimated_len); | ||
743 | |||
744 | // check to see if we're the shortest queue now. | ||
745 | if((aff->shortest_queue != info) && | ||
746 | (aff->shortest_queue->estimated_len > info->estimated_len)) { | ||
747 | |||
748 | aff->shortest_queue = info; | ||
749 | |||
750 | TRACE_CUR("shortest queue is fq %d (with %d in queue) has est len %llu\n", | ||
751 | kfmlp_get_idx(sem, info->q), | ||
752 | info->q->count, | ||
753 | info->estimated_len); | ||
754 | } | ||
755 | } | ||
756 | |||
757 | void gpu_kfmlp_notify_acquired(struct kfmlp_affinity* aff, struct kfmlp_queue* fq, struct task_struct* t) | ||
758 | { | ||
759 | struct kfmlp_semaphore *sem = kfmlp_from_lock(aff->obs.lock); | ||
760 | int gpu = kfmlp_get_idx(sem, fq) + aff->offset; | ||
761 | |||
762 | tsk_rt(t)->gpu_migration = gpu_migration_distance(tsk_rt(t)->last_gpu, gpu); // record the type of migration | ||
763 | |||
764 | TRACE_CUR("%s/%d acquired gpu %d. migration type = %d\n", | ||
765 | t->comm, t->pid, gpu, tsk_rt(t)->gpu_migration); | ||
766 | |||
767 | reg_nv_device(gpu, 1); // register | ||
768 | |||
769 | tsk_rt(t)->suspend_gpu_tracker_on_block = 0; | ||
770 | reset_gpu_tracker(t); | ||
771 | start_gpu_tracker(t); | ||
772 | } | ||
773 | |||
774 | void gpu_kfmlp_notify_freed(struct kfmlp_affinity* aff, struct kfmlp_queue* fq, struct task_struct* t) | ||
775 | { | ||
776 | struct kfmlp_semaphore *sem = kfmlp_from_lock(aff->obs.lock); | ||
777 | int gpu = kfmlp_get_idx(sem, fq) + aff->offset; | ||
778 | lt_t est_time; | ||
779 | |||
780 | stop_gpu_tracker(t); // stop the tracker before we do anything else. | ||
781 | |||
782 | est_time = get_gpu_estimate(t, gpu_migration_distance(tsk_rt(t)->last_gpu, gpu)); | ||
783 | |||
784 | tsk_rt(t)->last_gpu = gpu; | ||
785 | reg_nv_device(gpu, 0); // unregister | ||
786 | |||
787 | // update estimates | ||
788 | update_gpu_estimate(t, get_gpu_time(t)); | ||
789 | |||
790 | TRACE_CUR("%s/%d freed gpu %d. actual time was %llu. estimated was %llu. diff is %d\n", | ||
791 | t->comm, t->pid, gpu, | ||
792 | get_gpu_time(t), | ||
793 | est_time, | ||
794 | (long long)get_gpu_time(t) - (long long)est_time); | ||
795 | } | ||
796 | |||
797 | struct kfmlp_affinity_ops gpu_kfmlp_affinity = | ||
798 | { | ||
799 | .advise_enqueue = gpu_kfmlp_advise_enqueue, | ||
800 | .advise_steal = gpu_kfmlp_advise_steal, | ||
801 | .notify_enqueue = gpu_kfmlp_notify_enqueue, | ||
802 | .notify_dequeue = gpu_kfmlp_notify_dequeue, | ||
803 | .notify_acquired = gpu_kfmlp_notify_acquired, | ||
804 | .notify_freed = gpu_kfmlp_notify_freed | ||
805 | }; | ||
806 | |||
807 | struct affinity_observer* kfmlp_gpu_aff_obs_new(struct affinity_observer_ops* ops, | ||
808 | void* __user args) | ||
809 | { | ||
810 | return kfmlp_aff_obs_new(ops, &gpu_kfmlp_affinity, args); | ||
811 | } | ||
812 | |||
813 | |||
814 | |||
815 | |||
816 | |||
817 | |||
818 | |||
819 | |||
820 | // Simple KFMLP Affinity (standard KFMLP with auto-gpu registration) | ||
821 | |||
822 | struct kfmlp_queue* simple_gpu_kfmlp_advise_enqueue(struct kfmlp_affinity* aff, struct task_struct* t) | ||
823 | { | ||
824 | struct kfmlp_semaphore *sem = kfmlp_from_lock(aff->obs.lock); | ||
825 | return sem->shortest_queue; | ||
826 | } | ||
827 | |||
828 | struct task_struct* simple_gpu_kfmlp_advise_steal(struct kfmlp_affinity* aff, wait_queue_t** to_steal, struct kfmlp_queue** to_steal_from) | ||
829 | { | ||
830 | struct kfmlp_semaphore *sem = kfmlp_from_lock(aff->obs.lock); | ||
831 | return kfmlp_select_hp_steal(sem, to_steal, to_steal_from); | ||
832 | } | ||
833 | |||
834 | void simple_gpu_kfmlp_notify_enqueue(struct kfmlp_affinity* aff, struct kfmlp_queue* fq, struct task_struct* t) | ||
835 | { | ||
836 | } | ||
837 | |||
838 | void simple_gpu_kfmlp_notify_dequeue(struct kfmlp_affinity* aff, struct kfmlp_queue* fq, struct task_struct* t) | ||
839 | { | ||
840 | } | ||
841 | |||
842 | void simple_gpu_kfmlp_notify_acquired(struct kfmlp_affinity* aff, struct kfmlp_queue* fq, struct task_struct* t) | ||
843 | { | ||
844 | struct kfmlp_semaphore *sem = kfmlp_from_lock(aff->obs.lock); | ||
845 | int gpu = kfmlp_get_idx(sem, fq) + aff->offset; | ||
846 | |||
847 | reg_nv_device(gpu, 1); // register | ||
848 | } | ||
849 | |||
850 | void simple_gpu_kfmlp_notify_freed(struct kfmlp_affinity* aff, struct kfmlp_queue* fq, struct task_struct* t) | ||
851 | { | ||
852 | struct kfmlp_semaphore *sem = kfmlp_from_lock(aff->obs.lock); | ||
853 | int gpu = kfmlp_get_idx(sem, fq) + aff->offset; | ||
854 | |||
855 | reg_nv_device(gpu, 0); // unregister | ||
856 | } | ||
857 | |||
858 | struct kfmlp_affinity_ops simple_gpu_kfmlp_affinity = | ||
859 | { | ||
860 | .advise_enqueue = simple_gpu_kfmlp_advise_enqueue, | ||
861 | .advise_steal = simple_gpu_kfmlp_advise_steal, | ||
862 | .notify_enqueue = simple_gpu_kfmlp_notify_enqueue, | ||
863 | .notify_dequeue = simple_gpu_kfmlp_notify_dequeue, | ||
864 | .notify_acquired = simple_gpu_kfmlp_notify_acquired, | ||
865 | .notify_freed = simple_gpu_kfmlp_notify_freed | ||
866 | }; | ||
867 | |||
868 | struct affinity_observer* kfmlp_simple_gpu_aff_obs_new(struct affinity_observer_ops* ops, | ||
869 | void* __user args) | ||
870 | { | ||
871 | return kfmlp_aff_obs_new(ops, &simple_gpu_kfmlp_affinity, args); | ||
872 | } | ||
873 | |||
874 | #endif | ||
875 | |||
diff --git a/litmus/litmus.c b/litmus/litmus.c index 2f9079421ec7..dd8b72e1af08 100644 --- a/litmus/litmus.c +++ b/litmus/litmus.c | |||
@@ -387,6 +387,13 @@ static void reinit_litmus_state(struct task_struct* p, int restore) | |||
387 | p->rt_param.ctrl_page = ctrl_page; | 387 | p->rt_param.ctrl_page = ctrl_page; |
388 | } | 388 | } |
389 | 389 | ||
390 | #if defined(CONFIG_LITMUS_NVIDIA) && defined(CONFIG_LITMUS_AFFINITY_LOCKING) | ||
391 | p->rt_param.gpu_fb_param_a = _frac(14008, 1000); | ||
392 | p->rt_param.gpu_fb_param_b = _frac(16024, 1000); | ||
393 | p->rt_param.gpu_migration = MIG_LAST; | ||
394 | p->rt_param.last_gpu = -1; | ||
395 | #endif | ||
396 | |||
390 | #ifdef CONFIG_LITMUS_NESTED_LOCKING | 397 | #ifdef CONFIG_LITMUS_NESTED_LOCKING |
391 | INIT_BINHEAP_HANDLE(&p->rt_param.hp_blocked_tasks, prio_order); | 398 | INIT_BINHEAP_HANDLE(&p->rt_param.hp_blocked_tasks, prio_order); |
392 | raw_spin_lock_init(&p->rt_param.hp_blocked_tasks_lock); | 399 | raw_spin_lock_init(&p->rt_param.hp_blocked_tasks_lock); |
diff --git a/litmus/locking.c b/litmus/locking.c index 6d28efe97c91..ef13062913ce 100644 --- a/litmus/locking.c +++ b/litmus/locking.c | |||
@@ -10,6 +10,10 @@ | |||
10 | #include <linux/uaccess.h> | 10 | #include <linux/uaccess.h> |
11 | #endif | 11 | #endif |
12 | 12 | ||
13 | #if defined(CONFIG_LITMUS_AFFINITY_LOCKING) && defined(CONFIG_LITMUS_NVIDIA) | ||
14 | #include <litmus/gpu_affinity.h> | ||
15 | #endif | ||
16 | |||
13 | static int create_generic_lock(void** obj_ref, obj_type_t type, void* __user arg); | 17 | static int create_generic_lock(void** obj_ref, obj_type_t type, void* __user arg); |
14 | static int open_generic_lock(struct od_table_entry* entry, void* __user arg); | 18 | static int open_generic_lock(struct od_table_entry* entry, void* __user arg); |
15 | static int close_generic_lock(struct od_table_entry* entry); | 19 | static int close_generic_lock(struct od_table_entry* entry); |
@@ -50,6 +54,7 @@ static int create_generic_lock(void** obj_ref, obj_type_t type, void* __user ar | |||
50 | INIT_BINHEAP_NODE(&lock->nest.hp_binheap_node); | 54 | INIT_BINHEAP_NODE(&lock->nest.hp_binheap_node); |
51 | WARN_ON(!(lock->nest.hp_waiter_ptr)); | 55 | WARN_ON(!(lock->nest.hp_waiter_ptr)); |
52 | #endif | 56 | #endif |
57 | lock->type = type; | ||
53 | lock->ident = atomic_inc_return(&lock_id_gen); | 58 | lock->ident = atomic_inc_return(&lock_id_gen); |
54 | *obj_ref = lock; | 59 | *obj_ref = lock; |
55 | } | 60 | } |
@@ -292,6 +297,14 @@ static long do_litmus_dgl_lock(dgl_wait_state_t *dgl_wait) | |||
292 | 297 | ||
293 | TRACE_CUR("As many as %d locks in DGL are pending. Suspending.\n", | 298 | TRACE_CUR("As many as %d locks in DGL are pending. Suspending.\n", |
294 | dgl_wait->nr_remaining); | 299 | dgl_wait->nr_remaining); |
300 | |||
301 | #if defined(CONFIG_LITMUS_AFFINITY_LOCKING) && defined(CONFIG_LITMUS_NVIDIA) | ||
302 | // KLUDGE: don't count this suspension as time in the critical gpu | ||
303 | // critical section | ||
304 | if(tsk_rt(dgl_wait->task)->held_gpus) { | ||
305 | tsk_rt(dgl_wait->task)->suspend_gpu_tracker_on_block = 1; | ||
306 | } | ||
307 | #endif | ||
295 | 308 | ||
296 | // note reverse order. see comments in select_next_lock for reason. | 309 | // note reverse order. see comments in select_next_lock for reason. |
297 | for(i = dgl_wait->size - 1; i >= 0; --i) { | 310 | for(i = dgl_wait->size - 1; i >= 0; --i) { |
diff --git a/litmus/rsm_lock.c b/litmus/rsm_lock.c index aaca93c1e5d1..0a851cd430a7 100644 --- a/litmus/rsm_lock.c +++ b/litmus/rsm_lock.c | |||
@@ -7,6 +7,10 @@ | |||
7 | 7 | ||
8 | //#include <litmus/edf_common.h> | 8 | //#include <litmus/edf_common.h> |
9 | 9 | ||
10 | #if defined(CONFIG_LITMUS_AFFINITY_LOCKING) && defined(CONFIG_LITMUS_NVIDIA) | ||
11 | #include <litmus/gpu_affinity.h> | ||
12 | #endif | ||
13 | |||
10 | 14 | ||
11 | /* caller is responsible for locking */ | 15 | /* caller is responsible for locking */ |
12 | static struct task_struct* rsm_mutex_find_hp_waiter(struct rsm_mutex *mutex, | 16 | static struct task_struct* rsm_mutex_find_hp_waiter(struct rsm_mutex *mutex, |
@@ -202,7 +206,15 @@ int rsm_mutex_lock(struct litmus_lock* l) | |||
202 | 206 | ||
203 | if (mutex->owner) { | 207 | if (mutex->owner) { |
204 | TRACE_TASK(t, "Blocking on lock %d.\n", l->ident); | 208 | TRACE_TASK(t, "Blocking on lock %d.\n", l->ident); |
205 | 209 | ||
210 | #if defined(CONFIG_LITMUS_AFFINITY_LOCKING) && defined(CONFIG_LITMUS_NVIDIA) | ||
211 | // KLUDGE: don't count this suspension as time in the critical gpu | ||
212 | // critical section | ||
213 | if(tsk_rt(t)->held_gpus) { | ||
214 | tsk_rt(t)->suspend_gpu_tracker_on_block = 1; | ||
215 | } | ||
216 | #endif | ||
217 | |||
206 | /* resource is not free => must suspend and wait */ | 218 | /* resource is not free => must suspend and wait */ |
207 | 219 | ||
208 | owner = mutex->owner; | 220 | owner = mutex->owner; |
diff --git a/litmus/sched_gsn_edf.c b/litmus/sched_gsn_edf.c index 1440372227c6..b4ab2361e37a 100644 --- a/litmus/sched_gsn_edf.c +++ b/litmus/sched_gsn_edf.c | |||
@@ -61,6 +61,9 @@ | |||
61 | #include <litmus/nvidia_info.h> | 61 | #include <litmus/nvidia_info.h> |
62 | #endif | 62 | #endif |
63 | 63 | ||
64 | #if defined(CONFIG_LITMUS_AFFINITY_LOCKING) && defined(CONFIG_LITMUS_NVIDIA) | ||
65 | #include <litmus/gpu_affinity.h> | ||
66 | #endif | ||
64 | 67 | ||
65 | /* Overview of GSN-EDF operations. | 68 | /* Overview of GSN-EDF operations. |
66 | * | 69 | * |
@@ -813,6 +816,14 @@ static struct task_struct* gsnedf_schedule(struct task_struct * prev) | |||
813 | */ | 816 | */ |
814 | if (blocks) | 817 | if (blocks) |
815 | unlink(entry->scheduled); | 818 | unlink(entry->scheduled); |
819 | |||
820 | #if defined(CONFIG_LITMUS_NVIDIA) && defined(CONFIG_LITMUS_AFFINITY_LOCKING) | ||
821 | if(tsk_rt(entry->scheduled)->held_gpus) { | ||
822 | if(!blocks || tsk_rt(entry->scheduled)->suspend_gpu_tracker_on_block) { | ||
823 | stop_gpu_tracker(entry->scheduled); | ||
824 | } | ||
825 | } | ||
826 | #endif | ||
816 | 827 | ||
817 | /* Request a sys_exit_np() call if we would like to preempt but cannot. | 828 | /* Request a sys_exit_np() call if we would like to preempt but cannot. |
818 | * We need to make sure to update the link structure anyway in case | 829 | * We need to make sure to update the link structure anyway in case |
@@ -862,7 +873,7 @@ static struct task_struct* gsnedf_schedule(struct task_struct * prev) | |||
862 | if (exists) | 873 | if (exists) |
863 | next = prev; | 874 | next = prev; |
864 | } | 875 | } |
865 | 876 | ||
866 | sched_state_task_picked(); | 877 | sched_state_task_picked(); |
867 | 878 | ||
868 | raw_spin_unlock(&gsnedf_lock); | 879 | raw_spin_unlock(&gsnedf_lock); |
@@ -1429,9 +1440,6 @@ static struct litmus_lock* gsnedf_new_kfmlp(void* __user arg) | |||
1429 | return kfmlp_new(&gsnedf_kfmlp_lock_ops, arg); | 1440 | return kfmlp_new(&gsnedf_kfmlp_lock_ops, arg); |
1430 | } | 1441 | } |
1431 | 1442 | ||
1432 | |||
1433 | |||
1434 | |||
1435 | /* ******************** FMLP support ********************** */ | 1443 | /* ******************** FMLP support ********************** */ |
1436 | 1444 | ||
1437 | /* struct for semaphore with priority inheritance */ | 1445 | /* struct for semaphore with priority inheritance */ |
@@ -1676,7 +1684,57 @@ UNSUPPORTED_LOCK: | |||
1676 | return err; | 1684 | return err; |
1677 | } | 1685 | } |
1678 | 1686 | ||
1687 | #endif // CONFIG_LITMUS_LOCKING | ||
1688 | |||
1689 | |||
1690 | |||
1691 | |||
1692 | |||
1693 | #ifdef CONFIG_LITMUS_AFFINITY_LOCKING | ||
1694 | static struct affinity_observer_ops gsnedf_kfmlp_affinity_ops = { | ||
1695 | .close = kfmlp_aff_obs_close, | ||
1696 | .deallocate = kfmlp_aff_obs_free, | ||
1697 | }; | ||
1698 | |||
1699 | static long gsnedf_allocate_affinity_observer( | ||
1700 | struct affinity_observer **aff_obs, | ||
1701 | int type, | ||
1702 | void* __user args) | ||
1703 | { | ||
1704 | int err; | ||
1705 | |||
1706 | /* GSN-EDF currently only supports the FMLP for global resources. */ | ||
1707 | switch (type) { | ||
1708 | |||
1709 | case KFMLP_SIMPLE_GPU_AFF_OBS: | ||
1710 | *aff_obs = kfmlp_simple_gpu_aff_obs_new(&gsnedf_kfmlp_affinity_ops, args); | ||
1711 | break; | ||
1712 | case KFMLP_GPU_AFF_OBS: | ||
1713 | *aff_obs = kfmlp_gpu_aff_obs_new(&gsnedf_kfmlp_affinity_ops, args); | ||
1714 | break; | ||
1715 | #ifdef CONFIG_LITMUS_NESTED_LOCKING | ||
1716 | // case IKGLP_GPU_AFF_OBS: | ||
1717 | // *aff_obs = gsnedf_new_ikglp_aff(arg); | ||
1718 | // break; | ||
1679 | #endif | 1719 | #endif |
1720 | default: | ||
1721 | err = -ENXIO; | ||
1722 | goto UNSUPPORTED_AFF_OBS; | ||
1723 | }; | ||
1724 | |||
1725 | if (*aff_obs) | ||
1726 | err = 0; | ||
1727 | else | ||
1728 | err = -ENOMEM; | ||
1729 | |||
1730 | UNSUPPORTED_AFF_OBS: | ||
1731 | return err; | ||
1732 | } | ||
1733 | #endif | ||
1734 | |||
1735 | |||
1736 | |||
1737 | |||
1680 | 1738 | ||
1681 | static long gsnedf_activate_plugin(void) | 1739 | static long gsnedf_activate_plugin(void) |
1682 | { | 1740 | { |
@@ -1746,6 +1804,9 @@ static struct sched_plugin gsn_edf_plugin __cacheline_aligned_in_smp = { | |||
1746 | #ifdef CONFIG_LITMUS_DGL_SUPPORT | 1804 | #ifdef CONFIG_LITMUS_DGL_SUPPORT |
1747 | .get_dgl_spinlock = gsnedf_get_dgl_spinlock, | 1805 | .get_dgl_spinlock = gsnedf_get_dgl_spinlock, |
1748 | #endif | 1806 | #endif |
1807 | #ifdef CONFIG_LITMUS_AFFINITY_LOCKING | ||
1808 | .allocate_aff_obs = gsnedf_allocate_affinity_observer, | ||
1809 | #endif | ||
1749 | #ifdef CONFIG_LITMUS_SOFTIRQD | 1810 | #ifdef CONFIG_LITMUS_SOFTIRQD |
1750 | .increase_prio_klitirqd = increase_priority_inheritance_klitirqd, | 1811 | .increase_prio_klitirqd = increase_priority_inheritance_klitirqd, |
1751 | .decrease_prio_klitirqd = decrease_priority_inheritance_klitirqd, | 1812 | .decrease_prio_klitirqd = decrease_priority_inheritance_klitirqd, |