aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGlenn Elliott <gelliott@cs.unc.edu>2012-04-16 20:09:15 -0400
committerGlenn Elliott <gelliott@cs.unc.edu>2012-04-16 20:09:15 -0400
commit8675824ed85d6e83a24e77dabaf3a5c02c91ef6f (patch)
tree29e19fb32cacb062abca434fc921636d600ce77b
parent0b865246946a97dc03a81ccf55bf84acce923c4b (diff)
Implement GPU-affinity-aware kfmlp (untested)
-rw-r--r--include/litmus/fdso.h7
-rw-r--r--include/litmus/fpmath.h134
-rw-r--r--include/litmus/gpu_affinity.h40
-rw-r--r--include/litmus/kfmlp_lock.h56
-rw-r--r--include/litmus/rt_param.h37
-rw-r--r--litmus/Makefile2
-rw-r--r--litmus/gpu_affinity.c72
-rw-r--r--litmus/kfmlp_lock.c660
-rw-r--r--litmus/litmus.c7
-rw-r--r--litmus/locking.c13
-rw-r--r--litmus/rsm_lock.c14
-rw-r--r--litmus/sched_gsn_edf.c69
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
33struct inode_obj_id { 34struct 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.
6typedef int64_t fpbuf_t;
7typedef 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
18static const fp_t LITMUS_FP_ZERO = {.val = 0};
19static const fp_t LITMUS_FP_ONE = {.val = (1 << FP_SHIFT)};
20
21static 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 */
27static inline fp_t _frac(fpbuf_t a, fpbuf_t b)
28{
29 return _fp(FP(a).val / (b));
30}
31
32#ifdef __KERNEL__
33
34static 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
44static inline fpbuf_t _floor(fp_t x)
45{
46 return x.val >> FP_SHIFT;
47}
48
49/* FIXME: negative rounding */
50static 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 */
56static inline fp_t _mul(fp_t a, fp_t b)
57{
58 return _fp((a.val * b.val) >> FP_SHIFT);
59}
60
61static 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
70static inline fp_t _add(fp_t a, fp_t b)
71{
72 return _fp(a.val + b.val);
73}
74
75static inline fp_t _sub(fp_t a, fp_t b)
76{
77 return _fp(a.val - b.val);
78}
79
80static inline fp_t _neg(fp_t x)
81{
82 return _fp(-x.val);
83}
84
85static 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 */
91static inline fpbuf_t _fp_to_integer(fp_t x)
92{
93 return _floor(_abs(x)) * ((x.val > 0) ? 1 : -1);
94}
95
96static inline fp_t _integer_to_fp(fpbuf_t x)
97{
98 return _frac(x,1);
99}
100
101static inline int _leq(fp_t a, fp_t b)
102{
103 return a.val <= b.val;
104}
105
106static inline int _geq(fp_t a, fp_t b)
107{
108 return a.val >= b.val;
109}
110
111static inline int _lt(fp_t a, fp_t b)
112{
113 return a.val < b.val;
114}
115
116static inline int _gt(fp_t a, fp_t b)
117{
118 return a.val > b.val;
119}
120
121static inline int _eq(fp_t a, fp_t b)
122{
123 return a.val == b.val;
124}
125
126static 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
8void update_gpu_estimate(struct task_struct* t, lt_t observed);
9gpu_migration_dist_t gpu_migration_distance(int a, int b);
10
11static inline void reset_gpu_tracker(struct task_struct* t)
12{
13 t->rt_param.accum_gpu_time = 0;
14}
15
16static inline void start_gpu_tracker(struct task_struct* t)
17{
18 t->rt_param.gpu_time_stamp = litmus_clock();
19}
20
21static 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
27static inline lt_t get_gpu_time(struct task_struct* t)
28{
29 return t->rt_param.accum_gpu_time;
30}
31
32static 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 */
8struct kfmlp_queue 12struct 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
28static inline struct kfmlp_semaphore* kfmlp_from_lock(struct litmus_lock* lock) 36static inline struct kfmlp_semaphore* kfmlp_from_lock(struct litmus_lock* lock)
@@ -36,4 +44,50 @@ int kfmlp_close(struct litmus_lock* l);
36void kfmlp_free(struct litmus_lock* l); 44void kfmlp_free(struct litmus_lock* l);
37struct litmus_lock* kfmlp_new(struct litmus_lock_ops*, void* __user arg); 45struct 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
49struct kfmlp_queue_info
50{
51 struct kfmlp_queue* q;
52 lt_t estimated_len;
53};
54
55struct kfmlp_affinity;
56
57struct 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
67struct 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
76static 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
81int kfmlp_aff_obs_close(struct affinity_observer*);
82void kfmlp_aff_obs_free(struct affinity_observer*);
83struct affinity_observer* kfmlp_gpu_aff_obs_new(struct affinity_observer_ops*,
84 void* __user arg);
85struct 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. */
9typedef unsigned long long lt_t; 11typedef 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
62struct 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
127typedef 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
137typedef 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
35obj-$(CONFIG_LITMUS_PAI_SOFTIRQD) += litmus_pai_softirq.o 35obj-$(CONFIG_LITMUS_PAI_SOFTIRQD) += litmus_pai_softirq.o
36obj-$(CONFIG_LITMUS_NVIDIA) += nvidia_info.o sched_trace_external.o 36obj-$(CONFIG_LITMUS_NVIDIA) += nvidia_info.o sched_trace_external.o
37 37
38obj-$(CONFIG_LITMUS_AFFINITY_LOCKING) += kexclu_affinity.o 38obj-$(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
8static 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
21void 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
41gpu_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
10static inline int kfmlp_get_idx(struct kfmlp_semaphore* sem, 15static 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
70static 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
79static 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
123static 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
133int kfmlp_lock(struct litmus_lock* l) 241int 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 */
394RETRY:
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
321out: 457out:
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
548int kfmlp_aff_obs_close(struct affinity_observer* obs)
549{
550 return 0;
551}
552
553void 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
560static 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
623static 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
638struct 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
675out:
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
683struct 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
694void 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
724void 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
757void 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
774void 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
797struct 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
807struct 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
822struct 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
828struct 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
834void simple_gpu_kfmlp_notify_enqueue(struct kfmlp_affinity* aff, struct kfmlp_queue* fq, struct task_struct* t)
835{
836}
837
838void simple_gpu_kfmlp_notify_dequeue(struct kfmlp_affinity* aff, struct kfmlp_queue* fq, struct task_struct* t)
839{
840}
841
842void 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
850void 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
858struct 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
868struct 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
13static int create_generic_lock(void** obj_ref, obj_type_t type, void* __user arg); 17static int create_generic_lock(void** obj_ref, obj_type_t type, void* __user arg);
14static int open_generic_lock(struct od_table_entry* entry, void* __user arg); 18static int open_generic_lock(struct od_table_entry* entry, void* __user arg);
15static int close_generic_lock(struct od_table_entry* entry); 19static 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 */
12static struct task_struct* rsm_mutex_find_hp_waiter(struct rsm_mutex *mutex, 16static 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
1694static struct affinity_observer_ops gsnedf_kfmlp_affinity_ops = {
1695 .close = kfmlp_aff_obs_close,
1696 .deallocate = kfmlp_aff_obs_free,
1697};
1698
1699static 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
1730UNSUPPORTED_AFF_OBS:
1731 return err;
1732}
1733#endif
1734
1735
1736
1737
1680 1738
1681static long gsnedf_activate_plugin(void) 1739static 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,