diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2013-03-21 18:58:15 -0400 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2013-03-21 18:58:15 -0400 |
commit | 209f1961ea2d5863d6f2d2e9d2323446ee5e53c4 (patch) | |
tree | d0ba9bc3a057f76755083fb410df16393046ebef | |
parent | 9bb3596f972cb89ff43554d6d69153f8fde835ca (diff) |
Test tool budget enforcement methods.
-rw-r--r-- | Makefile | 32 | ||||
-rw-r--r-- | gpu/budget.cpp | 235 |
2 files changed, 263 insertions, 4 deletions
@@ -20,6 +20,7 @@ LITMUS_KERNEL ?= ../litmus-rt | |||
20 | 20 | ||
21 | # compiler flags | 21 | # compiler flags |
22 | flags-debug = -O2 -Wall -Werror -g -Wdeclaration-after-statement | 22 | flags-debug = -O2 -Wall -Werror -g -Wdeclaration-after-statement |
23 | flags-debug-cpp = -O2 -Wall -Werror -g | ||
23 | flags-api = -D_XOPEN_SOURCE=600 -D_GNU_SOURCE | 24 | flags-api = -D_XOPEN_SOURCE=600 -D_GNU_SOURCE |
24 | flags-misc = -fasynchronous-unwind-tables -fnon-call-exceptions | 25 | flags-misc = -fasynchronous-unwind-tables -fnon-call-exceptions |
25 | 26 | ||
@@ -49,7 +50,7 @@ LIBLITMUS ?= . | |||
49 | headers = -I${LIBLITMUS}/include -I${LIBLITMUS}/arch/${include-${ARCH}}/include | 50 | headers = -I${LIBLITMUS}/include -I${LIBLITMUS}/arch/${include-${ARCH}}/include |
50 | 51 | ||
51 | # combine options | 52 | # combine options |
52 | CPPFLAGS = ${flags-api} ${flags-misc} ${flags-${ARCH}} -DARCH=${ARCH} ${headers} | 53 | CPPFLAGS = ${flags-api} ${flags-debug-cpp} ${flags-misc} ${flags-${ARCH}} -DARCH=${ARCH} ${headers} |
53 | CFLAGS = ${flags-debug} ${flags-misc} | 54 | CFLAGS = ${flags-debug} ${flags-misc} |
54 | LDFLAGS = ${flags-${ARCH}} | 55 | LDFLAGS = ${flags-${ARCH}} |
55 | 56 | ||
@@ -62,18 +63,24 @@ ifeq (${CC},cc) | |||
62 | CC = gcc | 63 | CC = gcc |
63 | endif | 64 | endif |
64 | 65 | ||
66 | #ifeq (${CPP},cpp) | ||
67 | CPP = g++ | ||
68 | #endif | ||
69 | |||
65 | # incorporate cross-compiler (if any) | 70 | # incorporate cross-compiler (if any) |
66 | CC := ${CROSS_COMPILE}${CC} | 71 | CC := ${CROSS_COMPILE}${CC} |
72 | CPP := ${CROSS_COMPILE}${CPP} | ||
67 | LD := ${CROSS_COMPILE}${LD} | 73 | LD := ${CROSS_COMPILE}${LD} |
68 | AR := ${CROSS_COMPILE}${AR} | 74 | AR := ${CROSS_COMPILE}${AR} |
69 | 75 | ||
70 | # ############################################################################## | 76 | # ############################################################################## |
71 | # Targets | 77 | # Targets |
72 | 78 | ||
73 | all = lib ${rt-apps} | 79 | all = lib ${rt-apps} ${rt-cppapps} |
74 | rt-apps = cycles base_task rt_launch rtspin release_ts measure_syscall \ | 80 | rt-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 |
83 | rt-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 | ||
119 | clean: | 126 | clean: |
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 |
181 | vpath %.c src/ | 189 | vpath %.c src/ |
182 | vpath %.c gpu/ | 190 | obj-lib = $(patsubst src/%.c,%.o,$(wildcard src/*.c)) |
183 | obj-lib = $(patsubst src/%.c,%.o,$(wildcard src/*.c)) $(patsubst gpu/%.c,%.o,$(wildcard gpu/*.c)) | ||
184 | 191 | ||
185 | liblitmus.a: ${obj-lib} | 192 | liblitmus.a: ${obj-lib} |
186 | ${AR} rcs $@ $+ | 193 | ${AR} rcs $@ $+ |
@@ -246,6 +253,12 @@ obj-release_ts = release_ts.o | |||
246 | obj-measure_syscall = null_call.o | 253 | obj-measure_syscall = null_call.o |
247 | lib-measure_syscall = -lm | 254 | lib-measure_syscall = -lm |
248 | 255 | ||
256 | |||
257 | vpath %.cpp gpu/ | ||
258 | |||
259 | objcpp-budget = budget.o common.o | ||
260 | lib-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 | ||
259 | vpath %.c bin/ src/ gpu/ tests/ | 275 | vpath %.c bin/ src/ gpu/ tests/ |
276 | vpath %.cpp gpu/ | ||
260 | 277 | ||
261 | obj-all = ${sort ${foreach target,${all},${obj-${target}}}} | 278 | obj-all = ${sort ${foreach target,${all},${obj-${target}}}} |
279 | obj-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 | |||
270 | ifeq ($(MAKECMDGOALS),) | 294 | ifeq ($(MAKECMDGOALS),) |
271 | MAKECMDGOALS += all | 295 | MAKECMDGOALS += all |
272 | endif | 296 | endif |
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 | ||
22 | static int nums[NUMS]; | ||
23 | |||
24 | inline 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 | |||
36 | inline 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 | |||
48 | static 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 | |||
56 | int 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 | |||
78 | int OVERRUN = 0; | ||
79 | int SIGNALS = 0; | ||
80 | int BLOCK_SIGNALS_ON_SLEEP = 0; | ||
81 | int OVERRUN_RATE = 1; /* default: every job overruns */ | ||
82 | |||
83 | int NUM_JOBS = 0; | ||
84 | int NUM_COMPLETED_JOBS = 0; | ||
85 | int NUM_OVERRUNS = 0; | ||
86 | |||
87 | lt_t overrun_extra = 0; | ||
88 | |||
89 | int 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 | |||
125 | int 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(¶m); | ||
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(), ¶m); | ||
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 | } | ||