aboutsummaryrefslogtreecommitdiffstats
path: root/litmus/gpu_affinity.c
diff options
context:
space:
mode:
authorGlenn Elliott <gelliott@cs.unc.edu>2013-10-31 14:34:59 -0400
committerGlenn Elliott <gelliott@cs.unc.edu>2014-03-03 10:12:28 -0500
commit35a855f55eeeda1946294c3fc27e0927b6055da2 (patch)
treed6eb04bc0f28d93926bd5eec914f137971c47c16 /litmus/gpu_affinity.c
parent63a87f4eca47a185eb8e73cb6f34071864c02297 (diff)
Add GPU affinity tracking.
Adds GPU affinity tracking/prediction routines. Tracking uses a process-chart method whereby observations over two standard deviations below or above the average are discarded.
Diffstat (limited to 'litmus/gpu_affinity.c')
-rw-r--r--litmus/gpu_affinity.c163
1 files changed, 163 insertions, 0 deletions
diff --git a/litmus/gpu_affinity.c b/litmus/gpu_affinity.c
new file mode 100644
index 000000000000..85fa0ffb7328
--- /dev/null
+++ b/litmus/gpu_affinity.c
@@ -0,0 +1,163 @@
1#include <linux/sched.h>
2#include <litmus/litmus.h>
3#include <litmus/gpu_affinity.h>
4
5#include <litmus/sched_trace.h>
6#include <litmus/trace.h>
7
8/* two second cap on crazy observations */
9#define OBSERVATION_CAP ((lt_t)(2e9))
10
11#define NUM_STDEV_NUM 2
12#define NUM_STDEV_DENOM 1
13
14#define MIN(a, b) ((a < b) ? a : b)
15
16#if 0
17/* PID feedback controller */
18static fp_t update_estimate(feedback_est_t* fb, fp_t a, fp_t b, lt_t observed)
19{
20 fp_t relative_err;
21 fp_t err, new;
22 fp_t actual = _integer_to_fp(observed);
23
24 err = _sub(actual, fb->est);
25 new = _add(_mul(a, err), _mul(b, fb->accum_err));
26
27 relative_err = _div(err, actual);
28
29 fb->est = new;
30 fb->accum_err = _add(fb->accum_err, err);
31
32 return relative_err;
33}
34#endif
35
36static lt_t varience(lt_t nums[], const lt_t avg, const uint32_t count)
37{
38 /* brute force: takes about as much time as incremental running methods
39 * when count < 50 (on Bonham). Brute force also less prone to overflow.
40 */
41 lt_t sqdeviations = 0;
42 uint32_t i;
43 for(i = 0; i < count; ++i) {
44 lt_t temp = (int64_t)nums[i] - (int64_t)avg;
45 sqdeviations += temp * temp;
46 }
47 return sqdeviations/count;
48}
49
50static lt_t isqrt(lt_t n)
51{
52 /* integer square root using babylonian method
53 * (algo taken from wikipedia */
54 lt_t res = 0;
55 lt_t bit = ((lt_t)1) << (sizeof(n)*8-2);
56 while (bit > n)
57 bit >>= 2;
58
59 while (bit != 0) {
60 if (n >= res + bit) {
61 n -= res + bit;
62 res = (res >> 1) + bit;
63 }
64 else {
65 res >>= 1;
66 }
67 bit >>= 2;
68 }
69 return res;
70}
71
72void update_gpu_estimate(struct task_struct *t, lt_t observed)
73{
74 avg_est_t *est;
75 struct migration_info mig_info;
76
77 BUG_ON(tsk_rt(t)->gpu_migration > MIG_LAST);
78
79 est = &(tsk_rt(t)->gpu_migration_est[tsk_rt(t)->gpu_migration]);
80
81 /* log the migration event */
82 mig_info.observed = observed;
83 mig_info.estimated = est->avg;
84 mig_info.distance = tsk_rt(t)->gpu_migration;
85 sched_trace_migration(t, &mig_info);
86
87 if (unlikely(observed > OBSERVATION_CAP)) {
88 TRACE_TASK(t,
89 "Crazy observation greater than was dropped: %llu > %llu\n",
90 observed,
91 OBSERVATION_CAP);
92 return;
93 }
94
95 /* filter values outside NUM_STDEVx the standard deviation,
96 but only filter if enough samples have been taken. */
97 if (likely((est->count > MIN(10, AVG_EST_WINDOW_SIZE/2)))) {
98 lt_t lower, upper;
99
100 lt_t range = (est->std*NUM_STDEV_NUM)/NUM_STDEV_DENOM;
101 lower = est->avg - MIN(range, est->avg); // no underflow.
102
103 if (unlikely(observed < lower)) {
104 TRACE_TASK(t,
105 "Observation is too small: %llu < %llu (avg: %llu)\n",
106 observed, lower, est->avg);
107 return;
108 }
109
110 upper = est->avg + range;
111 if (unlikely(observed > upper)) {
112 TRACE_TASK(t,
113 "Observation is too large: %llu > %llu (avg: %llu)\n",
114 observed, upper, est->avg);
115 return;
116 }
117 }
118
119 if (unlikely(est->count < AVG_EST_WINDOW_SIZE))
120 ++est->count;
121 else
122 est->sum -= est->history[est->idx];
123
124 TS_UPDATE_GPU_EST_START;
125 est->history[est->idx] = observed;
126 est->sum += observed;
127 est->avg = est->sum/est->count;
128 est->std = isqrt(varience(est->history, est->avg, est->count));
129 est->idx = (est->idx + 1) % AVG_EST_WINDOW_SIZE;
130 TS_UPDATE_GPU_EST_END;
131
132 TRACE_TASK(t,
133 "GPU est update after (dist = %d, obs = %llu): %llu\n",
134 tsk_rt(t)->gpu_migration,
135 observed,
136 est->avg);
137}
138
139gpu_migration_dist_t gpu_migration_distance(int a, int b)
140{
141 /* GPUs organized in a binary hierarchy, no more than 2^MIG_FAR GPUs */
142 int i;
143 int dist;
144
145 if(likely(a >= 0 && b >= 0)) {
146 for(i = 0; i <= MIG_FAR; ++i) {
147 if(a>>i == b>>i) {
148 dist = i;
149 goto out;
150 }
151 }
152 dist = MIG_NONE; /* hopefully never reached. */
153 TRACE_CUR("WARNING: GPU distance too far! %d -> %d\n", a, b);
154 }
155 else {
156 dist = MIG_NONE;
157 }
158
159out:
160 TRACE_CUR("Distance %d -> %d is %d\n", a, b, dist);
161
162 return dist;
163}