diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2013-10-31 14:34:59 -0400 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2014-03-03 10:12:28 -0500 |
commit | 35a855f55eeeda1946294c3fc27e0927b6055da2 (patch) | |
tree | d6eb04bc0f28d93926bd5eec914f137971c47c16 /litmus/gpu_affinity.c | |
parent | 63a87f4eca47a185eb8e73cb6f34071864c02297 (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.c | 163 |
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 */ | ||
18 | static 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 | |||
36 | static 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 | |||
50 | static 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 | |||
72 | void 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 | |||
139 | gpu_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 | |||
159 | out: | ||
160 | TRACE_CUR("Distance %d -> %d is %d\n", a, b, dist); | ||
161 | |||
162 | return dist; | ||
163 | } | ||