aboutsummaryrefslogtreecommitdiffstats
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
parent9bb3596f972cb89ff43554d6d69153f8fde835ca (diff)
Test tool budget enforcement methods.
-rw-r--r--Makefile32
-rw-r--r--gpu/budget.cpp235
2 files changed, 263 insertions, 4 deletions
diff --git a/Makefile b/Makefile
index 3489de6..a8e528e 100644
--- a/Makefile
+++ b/Makefile
@@ -20,6 +20,7 @@ LITMUS_KERNEL ?= ../litmus-rt
20 20
21# compiler flags 21# compiler flags
22flags-debug = -O2 -Wall -Werror -g -Wdeclaration-after-statement 22flags-debug = -O2 -Wall -Werror -g -Wdeclaration-after-statement
23flags-debug-cpp = -O2 -Wall -Werror -g
23flags-api = -D_XOPEN_SOURCE=600 -D_GNU_SOURCE 24flags-api = -D_XOPEN_SOURCE=600 -D_GNU_SOURCE
24flags-misc = -fasynchronous-unwind-tables -fnon-call-exceptions 25flags-misc = -fasynchronous-unwind-tables -fnon-call-exceptions
25 26
@@ -49,7 +50,7 @@ LIBLITMUS ?= .
49headers = -I${LIBLITMUS}/include -I${LIBLITMUS}/arch/${include-${ARCH}}/include 50headers = -I${LIBLITMUS}/include -I${LIBLITMUS}/arch/${include-${ARCH}}/include
50 51
51# combine options 52# combine options
52CPPFLAGS = ${flags-api} ${flags-misc} ${flags-${ARCH}} -DARCH=${ARCH} ${headers} 53CPPFLAGS = ${flags-api} ${flags-debug-cpp} ${flags-misc} ${flags-${ARCH}} -DARCH=${ARCH} ${headers}
53CFLAGS = ${flags-debug} ${flags-misc} 54CFLAGS = ${flags-debug} ${flags-misc}
54LDFLAGS = ${flags-${ARCH}} 55LDFLAGS = ${flags-${ARCH}}
55 56
@@ -62,18 +63,24 @@ ifeq (${CC},cc)
62CC = gcc 63CC = gcc
63endif 64endif
64 65
66#ifeq (${CPP},cpp)
67CPP = g++
68#endif
69
65# incorporate cross-compiler (if any) 70# incorporate cross-compiler (if any)
66CC := ${CROSS_COMPILE}${CC} 71CC := ${CROSS_COMPILE}${CC}
72CPP := ${CROSS_COMPILE}${CPP}
67LD := ${CROSS_COMPILE}${LD} 73LD := ${CROSS_COMPILE}${LD}
68AR := ${CROSS_COMPILE}${AR} 74AR := ${CROSS_COMPILE}${AR}
69 75
70# ############################################################################## 76# ##############################################################################
71# Targets 77# Targets
72 78
73all = lib ${rt-apps} 79all = lib ${rt-apps} ${rt-cppapps}
74rt-apps = cycles base_task rt_launch rtspin release_ts measure_syscall \ 80rt-apps = cycles base_task rt_launch rtspin release_ts measure_syscall \
75 base_mt_task uncache runtests \ 81 base_mt_task uncache runtests \
76 nested locktest ikglptest dgl aux_threads normal_task 82 nested locktest ikglptest dgl aux_threads normal_task
83rt-cppapps = budget
77 84
78.PHONY: all lib clean dump-config TAGS tags cscope help 85.PHONY: all lib clean dump-config TAGS tags cscope help
79 86
@@ -118,6 +125,7 @@ help:
118 125
119clean: 126clean:
120 rm -f ${rt-apps} 127 rm -f ${rt-apps}
128 rm -f ${rt-cppapps}
121 rm -f *.o *.d *.a test_catalog.inc 129 rm -f *.o *.d *.a test_catalog.inc
122 rm -f ${imported-headers} 130 rm -f ${imported-headers}
123 rm -f inc/config.makefile 131 rm -f inc/config.makefile
@@ -179,8 +187,7 @@ lib: liblitmus.a
179 187
180# all .c file in src/ are linked into liblitmus 188# all .c file in src/ are linked into liblitmus
181vpath %.c src/ 189vpath %.c src/
182vpath %.c gpu/ 190obj-lib = $(patsubst src/%.c,%.o,$(wildcard src/*.c))
183obj-lib = $(patsubst src/%.c,%.o,$(wildcard src/*.c)) $(patsubst gpu/%.c,%.o,$(wildcard gpu/*.c))
184 191
185liblitmus.a: ${obj-lib} 192liblitmus.a: ${obj-lib}
186 ${AR} rcs $@ $+ 193 ${AR} rcs $@ $+
@@ -246,6 +253,12 @@ obj-release_ts = release_ts.o
246obj-measure_syscall = null_call.o 253obj-measure_syscall = null_call.o
247lib-measure_syscall = -lm 254lib-measure_syscall = -lm
248 255
256
257vpath %.cpp gpu/
258
259objcpp-budget = budget.o common.o
260lib-budget = -lrt -lm -pthread
261
249# ############################################################################## 262# ##############################################################################
250# Build everything that depends on liblitmus. 263# Build everything that depends on liblitmus.
251 264
@@ -253,12 +266,17 @@ lib-measure_syscall = -lm
253${rt-apps}: $${obj-$$@} liblitmus.a 266${rt-apps}: $${obj-$$@} liblitmus.a
254 $(CC) -o $@ $(LDFLAGS) ${ldf-$@} $(filter-out liblitmus.a,$+) $(LOADLIBS) $(LDLIBS) ${liblitmus-flags} ${lib-$@} 267 $(CC) -o $@ $(LDFLAGS) ${ldf-$@} $(filter-out liblitmus.a,$+) $(LOADLIBS) $(LDLIBS) ${liblitmus-flags} ${lib-$@}
255 268
269${rt-cppapps}: $${objcpp-$$@} liblitmus.a
270 $(CPP) -o $@ $(LDFLAGS) ${ldf-$@} $(filter-out liblitmus.a,$+) $(LOADLIBS) $(LDLIBS) ${liblitmus-flags} ${lib-$@}
271
256# ############################################################################## 272# ##############################################################################
257# Dependency resolution. 273# Dependency resolution.
258 274
259vpath %.c bin/ src/ gpu/ tests/ 275vpath %.c bin/ src/ gpu/ tests/
276vpath %.cpp gpu/
260 277
261obj-all = ${sort ${foreach target,${all},${obj-${target}}}} 278obj-all = ${sort ${foreach target,${all},${obj-${target}}}}
279obj-all += ${sort ${foreach target,${all},${objcpp-${target}}}}
262 280
263# rule to generate dependency files 281# rule to generate dependency files
264%.d: %.c ${imported-headers} 282%.d: %.c ${imported-headers}
@@ -267,6 +285,12 @@ obj-all = ${sort ${foreach target,${all},${obj-${target}}}}
267 sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \ 285 sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
268 rm -f $@.$$$$ 286 rm -f $@.$$$$
269 287
288%.d: %.cpp ${imported-headers}
289 @set -e; rm -f $@; \
290 $(CPP) -MM $(CPPFLAGS) $< > $@.$$$$; \
291 sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
292 rm -f $@.$$$$
293
270ifeq ($(MAKECMDGOALS),) 294ifeq ($(MAKECMDGOALS),)
271MAKECMDGOALS += all 295MAKECMDGOALS += all
272endif 296endif
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}