aboutsummaryrefslogtreecommitdiffstats
path: root/gpu
diff options
context:
space:
mode:
authorGlenn Elliott <gelliott@cs.unc.edu>2013-03-21 18:58:15 -0400
committerGlenn Elliott <gelliott@cs.unc.edu>2013-03-21 18:58:15 -0400
commit209f1961ea2d5863d6f2d2e9d2323446ee5e53c4 (patch)
treed0ba9bc3a057f76755083fb410df16393046ebef /gpu
parent9bb3596f972cb89ff43554d6d69153f8fde835ca (diff)
Test tool budget enforcement methods.
Diffstat (limited to 'gpu')
-rw-r--r--gpu/budget.cpp235
1 files changed, 235 insertions, 0 deletions
diff --git a/gpu/budget.cpp b/gpu/budget.cpp
new file mode 100644
index 0000000..f62c515
--- /dev/null
+++ b/gpu/budget.cpp
@@ -0,0 +1,235 @@
1#include <stdio.h>
2#include <stdlib.h>
3#include <stdint.h>
4#include <math.h>
5#include <unistd.h>
6#include <assert.h>
7#include <errno.h>
8#include <sys/types.h>
9#include <sys/stat.h>
10#include <fcntl.h>
11
12/* Include gettid() */
13#include <sys/types.h>
14
15/* Include threading support. */
16#include <pthread.h>
17
18/* Include the LITMUS^RT API.*/
19#include "litmus.h"
20
21#define NUMS 4096
22static int nums[NUMS];
23
24inline static lt_t cputime_ns(void)
25{
26 struct timespec ts;
27 lt_t time;
28 clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts);
29
30 // safe, as long as sizeof(ls_t) >= 8
31 time = s2ns(ts.tv_sec) + ts.tv_nsec;
32
33 return time;
34}
35
36inline static lt_t wtime_ns(void)
37{
38 struct timespec ts;
39 lt_t time;
40 clock_gettime(CLOCK_MONOTONIC, &ts);
41
42 // safe, as long as sizeof(ls_t) >= 8
43 time = s2ns(ts.tv_sec) + ts.tv_nsec;
44
45 return time;
46}
47
48static int loop_once(void)
49{
50 int i, j = 0;
51 for (i = 0; i < NUMS; ++i)
52 j += nums[i]++;
53 return j;
54}
55
56int loop_for(lt_t time)
57{
58 lt_t end, now;
59 lt_t last_loop = 0, loop_start;
60 int dummy = 0;
61
62 last_loop = 0;
63
64 now = cputime_ns();
65 end = now + time;
66
67 /* '+ last_loop' attempts to avoid overrun */
68 while (now + last_loop < end) {
69 loop_start = now;
70 dummy += loop_once();
71 now = cputime_ns();
72 last_loop = now - loop_start;
73 }
74
75 return dummy;
76}
77
78int OVERRUN = 0;
79int SIGNALS = 0;
80int BLOCK_SIGNALS_ON_SLEEP = 0;
81int OVERRUN_RATE = 1; /* default: every job overruns */
82
83int NUM_JOBS = 0;
84int NUM_COMPLETED_JOBS = 0;
85int NUM_OVERRUNS = 0;
86
87lt_t overrun_extra = 0;
88
89int job(lt_t exec_ns, lt_t budget_ns)
90{
91 ++NUM_JOBS;
92
93 try{
94 lt_t approx_remaining = budget_ns;
95 lt_t now = cputime_ns();
96 loop_for(lt_t(exec_ns * 0.9)); /* fudge it a bit to account for overheads */
97
98 if (OVERRUN) {
99 // do we want to overrun this job?
100 if ((NUM_JOBS % OVERRUN_RATE) == 0) {
101 approx_remaining -= (cputime_ns() - now);
102
103 if (SIGNALS && BLOCK_SIGNALS_ON_SLEEP)
104 block_litmus_signals(SIG_BUDGET);
105
106 // intentionally overrun via suspension
107 lt_sleep(approx_remaining + overrun_extra);
108
109 if (SIGNALS && BLOCK_SIGNALS_ON_SLEEP)
110 unblock_litmus_signals(SIG_BUDGET);
111 }
112 }
113 ++NUM_COMPLETED_JOBS;
114 }
115 catch (const litmus::sigbudget& e) {
116 ++NUM_OVERRUNS;
117 }
118
119 sleep_next_period();
120 return 1;
121}
122
123#define OPTSTR "sboOva"
124
125int main(int argc, char** argv)
126{
127 int ret;
128 lt_t e_ns = ms2ns(10);
129 lt_t p_ns = ms2ns(100);
130 lt_t budget_ns = p_ns/2;
131 lt_t duration = s2ns(10);
132 lt_t terminate_time;
133 unsigned int first_job, last_job;
134 int opt;
135 struct rt_task param;
136 budget_drain_policy_t drain_policy = DRAIN_SIMPLE;
137 int compute_overrun_rate = 0;
138 int once = 1;
139
140
141 while ((opt = getopt(argc, argv, OPTSTR)) != -1) {
142 switch(opt) {
143 case 's':
144 SIGNALS = 1;
145 break;
146 case 'b':
147 BLOCK_SIGNALS_ON_SLEEP = 1;
148 break;
149 case 'o':
150 OVERRUN = 1;
151 overrun_extra = budget_ns/2;
152 break;
153 case 'O':
154 OVERRUN = 1;
155 overrun_extra = 4*p_ns;
156 break;
157 case 'a':
158 /* select an overrun rate such that a task should be caught
159 * up from a backlog caused by an overrun before the next
160 * overrun occurs.
161 */
162 compute_overrun_rate = 1;
163 break;
164 case 'v':
165 drain_policy = DRAIN_SOBLIV;
166 break;
167 case ':':
168 printf("missing argument\n");
169 assert(false);
170 break;
171 default:
172 printf("unknown option\n");
173 assert(false);
174 break;
175 }
176 }
177
178 assert(!BLOCK_SIGNALS_ON_SLEEP || (BLOCK_SIGNALS_ON_SLEEP && SIGNALS));
179
180 if (compute_overrun_rate) {
181 int backlog = (int)ceil((overrun_extra + budget_ns)/(double)budget_ns);
182 OVERRUN_RATE = backlog + 2; /* some padding */
183 }
184
185 init_rt_task_param(&param);
186 param.exec_cost = budget_ns;
187 param.period = p_ns;
188 param.release_policy = PERIODIC;
189 param.drain_policy = drain_policy;
190 if (!SIGNALS)
191 param.budget_policy = PRECISE_ENFORCEMENT;
192 else
193 param.budget_signal_policy = PRECISE_SIGNALS;
194
195 init_litmus();
196
197 ret = set_rt_task_param(gettid(), &param);
198 assert(ret == 0);
199
200 ret = task_mode(LITMUS_RT_TASK);
201 assert(ret == 0);
202
203 sleep_next_period();
204
205 ret = get_job_no(&first_job);
206 assert(ret == 0);
207
208 terminate_time = duration + wtime_ns();
209
210 while (wtime_ns() < terminate_time) {
211 try{
212 if(once) {
213 activate_litmus_signals(SIG_BUDGET, litmus::throw_on_litmus_signal);
214 once = 0;
215 }
216 job(e_ns, budget_ns);
217 }
218 catch(const litmus::sigbudget &e) {
219 /* drop silently */
220 }
221 }
222
223 ret = get_job_no(&last_job);
224 assert(ret == 0);
225
226 ret = task_mode(BACKGROUND_TASK);
227 assert(ret == 0);
228
229 printf("# Kernel Jobs: %d\n", last_job - first_job + 1);
230 printf("# User Started Jobs: %d\n", NUM_JOBS);
231 printf("# User Jobs Completed: %d\n", NUM_COMPLETED_JOBS);
232 printf("# Overruns: %d\n", NUM_OVERRUNS);
233
234 return 0;
235}