diff options
-rw-r--r-- | Makefile | 26 | ||||
-rw-r--r-- | bin/bespin.c | 400 | ||||
-rw-r--r-- | bin/common.c | 41 | ||||
-rw-r--r-- | bin/locktest.c | 206 | ||||
-rw-r--r-- | bin/rtspin.beta.c | 283 | ||||
-rw-r--r-- | bin/rtspin.c | 17 | ||||
-rw-r--r-- | bin/rtspin.ovh.c | 239 | ||||
-rw-r--r-- | include/common.h | 3 | ||||
-rw-r--r-- | include/litmus.h | 3 | ||||
-rw-r--r-- | src/kernel_iface.c | 7 | ||||
-rw-r--r-- | src/litmus.c | 1 |
11 files changed, 1214 insertions, 12 deletions
@@ -12,14 +12,15 @@ host-arch := $(shell uname -m | \ | |||
12 | ARCH ?= ${host-arch} | 12 | ARCH ?= ${host-arch} |
13 | 13 | ||
14 | # LITMUS_KERNEL -- where to find the litmus kernel? | 14 | # LITMUS_KERNEL -- where to find the litmus kernel? |
15 | LITMUS_KERNEL ?= ../litmus-rt | 15 | LITMUS_KERNEL ?= ../backup-litmus-rt |
16 | 16 | ||
17 | 17 | ||
18 | # ############################################################################## | 18 | # ############################################################################## |
19 | # Internal configuration. | 19 | # Internal configuration. |
20 | 20 | ||
21 | # compiler flags | 21 | # compiler flags |
22 | flags-debug = -Wall -Werror -g -Wdeclaration-after-statement | 22 | # flags-debug = -Wall -Werror -g -Wdeclaration-after-statement |
23 | flags-debug = -Wall -g -Wdeclaration-after-statement | ||
23 | flags-api = -D_XOPEN_SOURCE=600 -D_GNU_SOURCE | 24 | flags-api = -D_XOPEN_SOURCE=600 -D_GNU_SOURCE |
24 | 25 | ||
25 | # architecture-specific flags | 26 | # architecture-specific flags |
@@ -71,7 +72,7 @@ AR := ${CROSS_COMPILE}${AR} | |||
71 | 72 | ||
72 | all = lib ${rt-apps} | 73 | all = lib ${rt-apps} |
73 | rt-apps = cycles base_task rt_launch rtspin release_ts measure_syscall \ | 74 | rt-apps = cycles base_task rt_launch rtspin release_ts measure_syscall \ |
74 | base_mt_task runtests colortest colorbench testcounters | 75 | base_mt_task runtests colortest colorbench testcounters bespin |
75 | 76 | ||
76 | .PHONY: all lib clean dump-config TAGS tags cscope help | 77 | .PHONY: all lib clean dump-config TAGS tags cscope help |
77 | 78 | ||
@@ -154,7 +155,7 @@ arch/${include-${ARCH}}/include/asm/%.h: \ | |||
154 | cp $< $@ | 155 | cp $< $@ |
155 | 156 | ||
156 | litmus-headers = include/litmus/rt_param.h include/litmus/unistd_32.h \ | 157 | litmus-headers = include/litmus/rt_param.h include/litmus/unistd_32.h \ |
157 | include/litmus/unistd_64.h | 158 | include/litmus/unistd_64.h include/litmus/color.h |
158 | 159 | ||
159 | unistd-headers = \ | 160 | unistd-headers = \ |
160 | $(foreach file,${unistd-${ARCH}},arch/${include-${ARCH}}/include/asm/$(file)) | 161 | $(foreach file,${unistd-${ARCH}},arch/${include-${ARCH}}/include/asm/$(file)) |
@@ -207,12 +208,25 @@ obj-base_mt_task = base_mt_task.o | |||
207 | ldf-base_mt_task = -pthread | 208 | ldf-base_mt_task = -pthread |
208 | 209 | ||
209 | obj-rt_launch = rt_launch.o common.o | 210 | obj-rt_launch = rt_launch.o common.o |
211 | lib-rt_launch = -lgsl -lgslcblas | ||
210 | 212 | ||
211 | obj-rtspin = rtspin.o common.o | 213 | obj-rtspin = rtspin.o common.o |
212 | lib-rtspin = -lrt | 214 | lib-rtspin = -lrt -lgsl -lgslcblas |
215 | |||
216 | obj-rtspin.ovh = rtspin.ovh.o common.o | ||
217 | lib-rtspin.ovh = -lrt -lgsl -lgslcblas | ||
218 | |||
219 | obj-rtspin.beta = rtspin.beta.o common.o | ||
220 | lib-rtspin.beta = -lrt $(shell gsl-config --libs) | ||
221 | |||
222 | obj-bespin = bespin.o common.o | ||
223 | lib-bespin = -lrt -lgsl -lgslcblas | ||
213 | 224 | ||
214 | obj-release_ts = release_ts.o | 225 | obj-release_ts = release_ts.o |
215 | 226 | ||
227 | obj-locktest = locktest.o | ||
228 | lib-locktest = -lrt -pthread | ||
229 | |||
216 | obj-measure_syscall = null_call.o | 230 | obj-measure_syscall = null_call.o |
217 | lib-measure_syscall = -lm | 231 | lib-measure_syscall = -lm |
218 | 232 | ||
@@ -220,7 +234,7 @@ obj-colortest = colortest.o color.o | |||
220 | lib-colortest = -static | 234 | lib-colortest = -static |
221 | 235 | ||
222 | obj-colorbench = colorbench.o color.o perfcounters.o common.o | 236 | obj-colorbench = colorbench.o color.o perfcounters.o common.o |
223 | lib-colorbench = -lpthread -lrt | 237 | lib-colorbench = -lpthread -lrt -lgsl -lgslcblas |
224 | 238 | ||
225 | obj-testcounters = testcounters.o | 239 | obj-testcounters = testcounters.o |
226 | lib-testcounters = | 240 | lib-testcounters = |
diff --git a/bin/bespin.c b/bin/bespin.c new file mode 100644 index 0000000..4495721 --- /dev/null +++ b/bin/bespin.c | |||
@@ -0,0 +1,400 @@ | |||
1 | #include <sys/time.h> | ||
2 | |||
3 | #include <stdio.h> | ||
4 | #include <stdlib.h> | ||
5 | #include <unistd.h> | ||
6 | #include <time.h> | ||
7 | #include <assert.h> | ||
8 | #include <string.h> | ||
9 | #include <limits.h> | ||
10 | |||
11 | #include <sched.h> | ||
12 | #include <sys/time.h> | ||
13 | #include <sys/resource.h> | ||
14 | |||
15 | #include <gsl/gsl_rng.h> | ||
16 | #include <gsl/gsl_randist.h> | ||
17 | |||
18 | #include "litmus.h" | ||
19 | #include "common.h" | ||
20 | |||
21 | #define UINT_WANT 4294967295 | ||
22 | #if UINT_MAX < UINT_WANT | ||
23 | #error Unsigned int not big enough. | ||
24 | #endif | ||
25 | |||
26 | /* | ||
27 | * Limit the execution times. | ||
28 | */ | ||
29 | #define EXEC_MIN (2 * __NS_PER_MS) | ||
30 | #define EXEC_MAX (100 * __NS_PER_MS) | ||
31 | |||
32 | /* | ||
33 | * Limit interarrival times. | ||
34 | */ | ||
35 | #define IA_MIN (0 * __NS_PER_MS) | ||
36 | #define IA_MAX (200 * __NS_PER_MS) | ||
37 | |||
38 | |||
39 | static void usage(char *error) { | ||
40 | fprintf(stderr, "Error: %s\n", error); | ||
41 | fprintf(stderr, | ||
42 | "Usage:\n" | ||
43 | " bespin [-w] [-o] [-n] [-p partition] " | ||
44 | "[-s seed] [-f res-time file] OS_TYPE DURATION\n" | ||
45 | "OS_TYPE is litmus or linux\n" | ||
46 | "DURATION is milliseconds.\n"); | ||
47 | exit(EXIT_FAILURE); | ||
48 | } | ||
49 | |||
50 | #define NUMS 4096 | ||
51 | static int num[NUMS]; | ||
52 | static char* progname; | ||
53 | |||
54 | static int task_colors, avg_ways; | ||
55 | |||
56 | static gsl_rng *exec_rng; | ||
57 | static gsl_rng *ia_rng; | ||
58 | static struct timespec sleep_ts = { .tv_sec = 0 }; | ||
59 | |||
60 | static void setup_rng(unsigned long seed) | ||
61 | { | ||
62 | exec_rng = gsl_rng_alloc(gsl_rng_taus); | ||
63 | ia_rng = gsl_rng_alloc(gsl_rng_taus); | ||
64 | if (!exec_rng || !ia_rng) | ||
65 | bail_out("Could not initialize RNG"); | ||
66 | gsl_rng_set(exec_rng, seed); | ||
67 | gsl_rng_set(ia_rng, seed + 1); | ||
68 | } | ||
69 | |||
70 | static lt_t round_double_lt(const double d) | ||
71 | { | ||
72 | /* if needed, add one so round up */ | ||
73 | if (d - ((lt_t)d) > 0.0) | ||
74 | return ((lt_t)(d + 1.0)); | ||
75 | else | ||
76 | return ((lt_t)d); | ||
77 | } | ||
78 | |||
79 | static lt_t get_exec_time(const lt_t exec_mean) | ||
80 | { | ||
81 | double e = gsl_ran_exponential(exec_rng, exec_mean); | ||
82 | e = (e < EXEC_MIN) ? EXEC_MIN : e; | ||
83 | e = (e > EXEC_MAX) ? EXEC_MAX : e; | ||
84 | return (round_double_lt(e)); | ||
85 | } | ||
86 | |||
87 | static lt_t get_ia_time(const lt_t ia_mean) | ||
88 | { | ||
89 | double ia = gsl_ran_exponential(ia_rng, ia_mean); | ||
90 | ia = (ia < IA_MIN) ? IA_MIN : ia; | ||
91 | ia = (ia > IA_MAX) ? IA_MAX : ia; | ||
92 | return (round_double_lt(ia)); | ||
93 | } | ||
94 | |||
95 | #define LITMUS_STR "litmus" | ||
96 | #define LINUX_STR "linux" | ||
97 | static int using_os(const char *const os, const char *const test) | ||
98 | { | ||
99 | /* LITMUS_STR > LINUX_STR */ | ||
100 | return (0 == strncasecmp(os, test, sizeof(LITMUS_STR))); | ||
101 | } | ||
102 | |||
103 | static int valid_os(char *os) | ||
104 | { | ||
105 | return (using_os(LITMUS_STR, os) || using_os(LINUX_STR, os)); | ||
106 | } | ||
107 | |||
108 | static inline lt_t ts_to_ns(const struct timespec *ts) | ||
109 | { | ||
110 | return ( (((lt_t)ts->tv_sec) * 1e9) + ts->tv_nsec ); | ||
111 | } | ||
112 | |||
113 | static void mono_time_ts(struct timespec *ts) | ||
114 | { | ||
115 | int ret = clock_gettime(CLOCK_MONOTONIC, ts); | ||
116 | if (ret) | ||
117 | bail_out("could not get monotonic time"); | ||
118 | } | ||
119 | |||
120 | static lt_t mono_time(void) | ||
121 | { | ||
122 | struct timespec ts; | ||
123 | mono_time_ts(&ts); | ||
124 | return (ts_to_ns(&ts)); | ||
125 | } | ||
126 | |||
127 | static void add_to_ts(struct timespec *ts, const lt_t t) | ||
128 | { | ||
129 | /* convert the lt_t to seconds and nanoseconds */ | ||
130 | const lt_t sec = t / 1e9; | ||
131 | long nsec = t - sec; | ||
132 | |||
133 | /* figure out carry for nsec field */ | ||
134 | const long nsec_sum_large = ts->tv_nsec + nsec; | ||
135 | const time_t sec_carry = nsec_sum_large / 1e9; | ||
136 | |||
137 | ts->tv_sec += sec + sec_carry; | ||
138 | ts->tv_nsec = nsec_sum_large - sec_carry * 1e9; | ||
139 | assert(ts->tv_nsec < 1e9); | ||
140 | } | ||
141 | |||
142 | static lt_t etime(void) | ||
143 | { | ||
144 | struct timespec ts; | ||
145 | int err; | ||
146 | err = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts); | ||
147 | if (err) | ||
148 | bail_out("could not get thread CPU time"); | ||
149 | return (ts_to_ns(&ts)); | ||
150 | } | ||
151 | |||
152 | static int loop_once(void) | ||
153 | { | ||
154 | int i, j = 0; | ||
155 | for (i = 0; i < NUMS; i++) | ||
156 | j += num[i]++; | ||
157 | return j; | ||
158 | } | ||
159 | |||
160 | static int loop_for(lt_t exec_time, lt_t emergency_exit) | ||
161 | { | ||
162 | double last_loop = 0, loop_start; | ||
163 | int job_finished = 1; | ||
164 | int tmp = 0; | ||
165 | |||
166 | lt_t start = etime(); | ||
167 | lt_t now = etime(); | ||
168 | |||
169 | while (now + last_loop < start + exec_time) { | ||
170 | loop_start = now; | ||
171 | tmp += loop_once(); | ||
172 | now = etime(); | ||
173 | last_loop = now - loop_start; | ||
174 | if (emergency_exit && mono_time() > emergency_exit) | ||
175 | job_finished = 0; | ||
176 | } | ||
177 | |||
178 | return job_finished; | ||
179 | } | ||
180 | |||
181 | static void do_sleep(const lt_t ia_mean) | ||
182 | { | ||
183 | const lt_t ia = get_ia_time(ia_mean); | ||
184 | int err; | ||
185 | |||
186 | add_to_ts(&sleep_ts, ia); | ||
187 | err = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, | ||
188 | &sleep_ts, NULL); | ||
189 | |||
190 | /* | ||
191 | * For some reason, nanosleep returns non-zero even when things are | ||
192 | * okay the last time. */ | ||
193 | if (err) | ||
194 | bail_out("could not nanosleep!"); | ||
195 | } | ||
196 | |||
197 | static int job(const lt_t exec_mean, const lt_t ia_mean, FILE *out_f, | ||
198 | const lt_t program_end) | ||
199 | { | ||
200 | const lt_t now = mono_time(); | ||
201 | const lt_t exec = get_exec_time(exec_mean); | ||
202 | int job_finished; | ||
203 | lt_t end_time; | ||
204 | |||
205 | if (now > program_end || now + exec > program_end) | ||
206 | { | ||
207 | /* this job is either after we want to stop, or would be, | ||
208 | * so just quit now */ | ||
209 | return 0; | ||
210 | } else { | ||
211 | /* add NS per MS as an error margin */ | ||
212 | job_finished = loop_for(exec, program_end + __NS_PER_MS); | ||
213 | end_time = mono_time(); | ||
214 | |||
215 | /* record response time if wanted and the job finished */ | ||
216 | if (out_f && job_finished) | ||
217 | { | ||
218 | /* print start time, end time, exec time */ | ||
219 | fprintf(out_f, "%llu, %llu, %llu\n", | ||
220 | ts_to_ns(&sleep_ts), end_time, exec); | ||
221 | } | ||
222 | |||
223 | if (end_time < program_end) { | ||
224 | /* we can go to sleep some time */ | ||
225 | do_sleep(ia_mean); | ||
226 | return 1; | ||
227 | } else { | ||
228 | /* that was the last job */ | ||
229 | return 0; | ||
230 | } | ||
231 | } | ||
232 | } | ||
233 | |||
234 | static void setup_litmus_task(const double phase_ms, const int cpu) | ||
235 | { | ||
236 | const lt_t phase = phase_ms * __NS_PER_MS; | ||
237 | int ret; | ||
238 | |||
239 | /* Best-Effort task has no WCET or period, just use one */ | ||
240 | ret = sporadic_task_ns(1, 1, phase, cpu, RT_CLASS_BEST_EFFORT, | ||
241 | NO_ENFORCEMENT, 0); | ||
242 | if (ret < 0) | ||
243 | bail_out("could not setup rt task params"); | ||
244 | |||
245 | request_resources(task_colors, avg_ways); | ||
246 | |||
247 | init_litmus(); | ||
248 | |||
249 | ret = task_mode(LITMUS_RT_TASK); | ||
250 | if (ret != 0) | ||
251 | bail_out("could not become RT task"); | ||
252 | } | ||
253 | |||
254 | #define OPTSTR "p:wl:r:nos:f:h:" | ||
255 | |||
256 | int main(int argc, char** argv) | ||
257 | { | ||
258 | unsigned long seed = 1; | ||
259 | double duration_ms; | ||
260 | double exec_mean_ms = 10.0, ia_mean_ms = 100.0, phase_ms = 0.0; | ||
261 | lt_t duration, start, exec_mean, ia_mean; | ||
262 | char *os_type, *out_fname = NULL; | ||
263 | FILE *out_f = NULL; | ||
264 | int opt; | ||
265 | int ret; | ||
266 | int wait = 0; | ||
267 | int nice = 0; | ||
268 | int fifo = 0; | ||
269 | int cpu = 0; | ||
270 | int migrate = 0; | ||
271 | struct sched_param param; | ||
272 | |||
273 | progname = argv[0]; | ||
274 | |||
275 | while ((opt = getopt(argc, argv, OPTSTR)) != -1) { | ||
276 | switch (opt) { | ||
277 | case 'w': | ||
278 | wait = 1; | ||
279 | break; | ||
280 | case 'p': | ||
281 | cpu = atoi(optarg); | ||
282 | migrate = 1; | ||
283 | break; | ||
284 | case 'n': | ||
285 | nice = 1; | ||
286 | break; | ||
287 | case 'o': | ||
288 | fifo = 1; | ||
289 | break; | ||
290 | case 's': | ||
291 | seed = atoi(optarg); | ||
292 | break; | ||
293 | /* case 'h': */ | ||
294 | /* phase_ms = atof(optarg); */ | ||
295 | /* break; */ | ||
296 | case 'e': | ||
297 | exec_mean_ms = atof(optarg); | ||
298 | break; | ||
299 | case 'i': | ||
300 | ia_mean_ms = atof(optarg); | ||
301 | break; | ||
302 | case 'f': | ||
303 | out_fname = optarg; | ||
304 | break; | ||
305 | case 'h': | ||
306 | sscanf(optarg, "%d,%d", &task_colors, &avg_ways); | ||
307 | break; | ||
308 | case ':': | ||
309 | usage("Argument missing."); | ||
310 | break; | ||
311 | case '?': | ||
312 | default: | ||
313 | usage("Bad argument."); | ||
314 | break; | ||
315 | } | ||
316 | } | ||
317 | |||
318 | if (argc - optind != 2) | ||
319 | usage("Arguments missing."); | ||
320 | |||
321 | os_type = argv[optind + 0]; | ||
322 | duration_ms = atof(argv[optind + 1]); | ||
323 | |||
324 | if (!valid_os(os_type)) | ||
325 | bail_out("Invalid OS type"); | ||
326 | |||
327 | if (duration_ms < 0) | ||
328 | bail_out("duration < 0 not allowed"); | ||
329 | |||
330 | if (exec_mean_ms < 0) | ||
331 | bail_out("execution time mean < 0 not allowed"); | ||
332 | |||
333 | if (ia_mean_ms < 0) | ||
334 | bail_out("IA time mean < 0 not allowed"); | ||
335 | |||
336 | if (exec_mean_ms * __NS_PER_MS > UINT_MAX >> 1) | ||
337 | bail_out("Exec time too big"); | ||
338 | |||
339 | if (seed < 1) | ||
340 | bail_out("seed < 1 not allowed"); | ||
341 | |||
342 | if (phase_ms < 0) | ||
343 | bail_out("phase < 0 not allowed"); | ||
344 | |||
345 | if (wait && using_os(LINUX_STR, os_type)) | ||
346 | bail_out("Linux cannot use the wait flag"); | ||
347 | |||
348 | duration = duration_ms * __NS_PER_MS; | ||
349 | exec_mean = exec_mean_ms * __NS_PER_MS; | ||
350 | ia_mean = ia_mean_ms * __NS_PER_MS; | ||
351 | |||
352 | if (out_fname) | ||
353 | { | ||
354 | out_f = fopen(out_fname, "w"); | ||
355 | if (!out_f) | ||
356 | bail_out("Could not open response-time file"); | ||
357 | } | ||
358 | |||
359 | setup_rng(seed); | ||
360 | |||
361 | if (using_os(LITMUS_STR, os_type)) { | ||
362 | |||
363 | if (migrate) { | ||
364 | ret = be_migrate_to(cpu); | ||
365 | if (ret < 0) | ||
366 | bail_out("could not migrate to target partition"); | ||
367 | } | ||
368 | |||
369 | setup_litmus_task(phase_ms, cpu); | ||
370 | |||
371 | if (wait) { | ||
372 | ret = wait_for_ts_release(); | ||
373 | if (ret != 0) | ||
374 | bail_out("wait_for_ts_release()"); | ||
375 | } | ||
376 | } else if (fifo) { | ||
377 | param.sched_priority = sched_get_priority_max(SCHED_FIFO) - 2; | ||
378 | ret = sched_setscheduler(0, SCHED_FIFO, ¶m); | ||
379 | if (ret) | ||
380 | bail_out("Could not switch to FIFO scheduler"); | ||
381 | } else if (nice) { | ||
382 | ret = setpriority(PRIO_PROCESS, 0, 5); | ||
383 | if (ret) | ||
384 | bail_out("Could not set task priority"); | ||
385 | } | ||
386 | |||
387 | /* initialize the start time */ | ||
388 | mono_time_ts(&sleep_ts); | ||
389 | start = ts_to_ns(&sleep_ts); | ||
390 | |||
391 | while (job(exec_mean, ia_mean, out_f, start + duration)); | ||
392 | |||
393 | if (using_os(LITMUS_STR, os_type)) { | ||
394 | ret = task_mode(BACKGROUND_TASK); | ||
395 | if (ret != 0) | ||
396 | bail_out("could not become regular task (huh?)"); | ||
397 | } | ||
398 | |||
399 | return 0; | ||
400 | } | ||
diff --git a/bin/common.c b/bin/common.c index 452b882..2aa9a7c 100644 --- a/bin/common.c +++ b/bin/common.c | |||
@@ -3,9 +3,50 @@ | |||
3 | #include <errno.h> | 3 | #include <errno.h> |
4 | 4 | ||
5 | #include "common.h" | 5 | #include "common.h" |
6 | #include "litmus.h" | ||
7 | #include <litmus/color.h> | ||
8 | |||
9 | #include <gsl/gsl_rng.h> | ||
10 | #include <gsl/gsl_randist.h> | ||
6 | 11 | ||
7 | void bail_out(const char* msg) | 12 | void bail_out(const char* msg) |
8 | { | 13 | { |
9 | perror(msg); | 14 | perror(msg); |
10 | exit(-1 * errno); | 15 | exit(-1 * errno); |
11 | } | 16 | } |
17 | |||
18 | void request_resources(int task_colors, int avg_ways) | ||
19 | { | ||
20 | const gsl_rng *way_rng = gsl_rng_alloc(gsl_rng_taus); | ||
21 | struct control_page *page = get_ctrl_page(); | ||
22 | int color, ways, rem = task_colors; | ||
23 | float random; | ||
24 | char taken[NUM_COLORS]; | ||
25 | |||
26 | memset(page->requests, 0, NUM_COLORS*sizeof(*page->requests)); | ||
27 | |||
28 | gsl_rng_set(way_rng, rand()); | ||
29 | memset(taken, 0, NUM_COLORS); | ||
30 | |||
31 | srand(getpid()); | ||
32 | gsl_rng_set(way_rng, getpid()); | ||
33 | |||
34 | while (rem) { | ||
35 | /* select a random unchosen color */ | ||
36 | do { | ||
37 | color = rand() % NUM_COLORS; | ||
38 | } while (taken[color]); | ||
39 | |||
40 | if (rand() % NUM_COLORS <= task_colors) { | ||
41 | taken[color] = 1; | ||
42 | rem --; | ||
43 | |||
44 | random = gsl_ran_exponential(way_rng, avg_ways + 1); | ||
45 | ways = 1 + (int)random; | ||
46 | ways = (ways < 1) ? 1 : ways; | ||
47 | ways = (ways > NUM_WAYS) ? NUM_WAYS : ways; | ||
48 | |||
49 | page->requests[color] = ways; | ||
50 | } | ||
51 | } | ||
52 | } | ||
diff --git a/bin/locktest.c b/bin/locktest.c new file mode 100644 index 0000000..a0f8948 --- /dev/null +++ b/bin/locktest.c | |||
@@ -0,0 +1,206 @@ | |||
1 | #include <stdio.h> | ||
2 | #include <stdlib.h> | ||
3 | #include <stdint.h> | ||
4 | #include <unistd.h> | ||
5 | #include <assert.h> | ||
6 | #include <errno.h> | ||
7 | #include <sys/types.h> | ||
8 | #include <sys/stat.h> | ||
9 | #include <fcntl.h> | ||
10 | |||
11 | /* Include gettid() */ | ||
12 | #include <sys/types.h> | ||
13 | |||
14 | /* Include threading support. */ | ||
15 | #include <pthread.h> | ||
16 | |||
17 | /* Include the LITMUS^RT API.*/ | ||
18 | #include "litmus.h" | ||
19 | |||
20 | /* Catch errors. | ||
21 | */ | ||
22 | #define CALL( exp ) do { \ | ||
23 | int ret; \ | ||
24 | ret = exp; \ | ||
25 | if (ret != 0) \ | ||
26 | fprintf(stderr, "%s failed: %m\n", #exp);\ | ||
27 | else \ | ||
28 | fprintf(stderr, "%s ok.\n", #exp); \ | ||
29 | } while (0) | ||
30 | |||
31 | #define TH_CALL( exp ) do { \ | ||
32 | int ret; \ | ||
33 | ret = exp; \ | ||
34 | if (ret != 0) \ | ||
35 | fprintf(stderr, "[%d] %s failed: %m\n", ctx->id, #exp); \ | ||
36 | else \ | ||
37 | fprintf(stderr, "[%d] %s ok.\n", ctx->id, #exp); \ | ||
38 | } while (0) | ||
39 | |||
40 | #define TH_SAFE_CALL( exp ) do { \ | ||
41 | int ret; \ | ||
42 | fprintf(stderr, "[%d] calling %s...\n", ctx->id, #exp); \ | ||
43 | ret = exp; \ | ||
44 | if (ret != 0) \ | ||
45 | fprintf(stderr, "\t...[%d] %s failed: %m\n", ctx->id, #exp); \ | ||
46 | else \ | ||
47 | fprintf(stderr, "\t...[%d] %s ok.\n", ctx->id, #exp); \ | ||
48 | } while (0) | ||
49 | |||
50 | |||
51 | /* these are only default values */ | ||
52 | int NUM_THREADS=3; | ||
53 | int NUM_SEMS=10; | ||
54 | |||
55 | #define MAX_SEMS 1000 | ||
56 | |||
57 | #define EXEC_COST 10 | ||
58 | #define PERIOD 100 | ||
59 | |||
60 | /* The information passed to each thread. Could be anything. */ | ||
61 | struct thread_context { | ||
62 | int id; | ||
63 | int fd; | ||
64 | int od[MAX_SEMS]; | ||
65 | int count; | ||
66 | unsigned int rand; | ||
67 | }; | ||
68 | |||
69 | void* rt_thread(void* _ctx); | ||
70 | int nested_job(struct thread_context* ctx, int *count, int *next); | ||
71 | int job(struct thread_context*); | ||
72 | |||
73 | #define OPTSTR "t:s:" | ||
74 | |||
75 | int main(int argc, char** argv) | ||
76 | { | ||
77 | int i; | ||
78 | struct thread_context* ctx; | ||
79 | pthread_t* task; | ||
80 | int fd; | ||
81 | |||
82 | int opt; | ||
83 | while((opt = getopt(argc, argv, OPTSTR)) != -1) { | ||
84 | switch(opt) { | ||
85 | case 't': | ||
86 | NUM_THREADS = atoi(optarg); | ||
87 | break; | ||
88 | case 's': | ||
89 | NUM_SEMS = atoi(optarg); | ||
90 | assert(NUM_SEMS <= MAX_SEMS); | ||
91 | break; | ||
92 | default: | ||
93 | fprintf(stderr, "Unknown option: %c\n", opt); | ||
94 | exit(-1); | ||
95 | break; | ||
96 | } | ||
97 | } | ||
98 | |||
99 | ctx = (struct thread_context*) calloc(NUM_THREADS, sizeof(struct thread_context)); | ||
100 | task = (pthread_t*) calloc(NUM_THREADS, sizeof(pthread_t)); | ||
101 | |||
102 | srand(0); /* something repeatable for now */ | ||
103 | |||
104 | fd = open("semaphores", O_RDONLY | O_CREAT, S_IRUSR | S_IWUSR); | ||
105 | |||
106 | CALL( init_litmus() ); | ||
107 | |||
108 | for (i = 0; i < NUM_THREADS; i++) { | ||
109 | ctx[i].id = i; | ||
110 | ctx[i].fd = fd; | ||
111 | ctx[i].rand = rand(); | ||
112 | CALL( pthread_create(task + i, NULL, rt_thread, ctx + i) ); | ||
113 | } | ||
114 | |||
115 | |||
116 | for (i = 0; i < NUM_THREADS; i++) | ||
117 | pthread_join(task[i], NULL); | ||
118 | |||
119 | |||
120 | return 0; | ||
121 | } | ||
122 | |||
123 | void* rt_thread(void* _ctx) | ||
124 | { | ||
125 | int i; | ||
126 | int do_exit = 0; | ||
127 | |||
128 | struct thread_context *ctx = (struct thread_context*)_ctx; | ||
129 | |||
130 | TH_CALL( init_rt_thread() ); | ||
131 | |||
132 | /* Vary period a little bit. */ | ||
133 | TH_CALL( sporadic_global(EXEC_COST, PERIOD + 10*ctx->id) ); | ||
134 | |||
135 | for (i = 0; i < NUM_SEMS; i++) { | ||
136 | ctx->od[i] = open_fmlp_sem(ctx->fd, i); | ||
137 | if(ctx->od[i] < 0) | ||
138 | perror("open_fmlp_sem"); | ||
139 | } | ||
140 | |||
141 | TH_CALL( task_mode(LITMUS_RT_TASK) ); | ||
142 | |||
143 | |||
144 | printf("[%d] Waiting for TS release.\n ", ctx->id); | ||
145 | wait_for_ts_release(); | ||
146 | ctx->count = 0; | ||
147 | |||
148 | do { | ||
149 | int which_sem = (int)(NUM_SEMS * (rand_r(&(ctx->rand)) / (RAND_MAX + 1.0))); | ||
150 | |||
151 | printf("[%d]: trying to get semaphore %d.\n", ctx->id, which_sem); | ||
152 | fflush(stdout); | ||
153 | |||
154 | TH_SAFE_CALL ( litmus_lock(which_sem) ); | ||
155 | |||
156 | printf("[%d] got semaphore %d.\n", ctx->id, which_sem); | ||
157 | fflush(stdout); | ||
158 | |||
159 | do_exit = job(ctx); | ||
160 | |||
161 | printf("[%d]: freeing semaphore %d.\n", ctx->id, which_sem); | ||
162 | fflush(stdout); | ||
163 | |||
164 | TH_SAFE_CALL ( litmus_unlock(which_sem) ); | ||
165 | |||
166 | if(!do_exit) { | ||
167 | sleep_next_period(); | ||
168 | } | ||
169 | } while(!do_exit); | ||
170 | |||
171 | /***** | ||
172 | * 4) Transition to background mode. | ||
173 | */ | ||
174 | TH_CALL( task_mode(BACKGROUND_TASK) ); | ||
175 | |||
176 | |||
177 | return NULL; | ||
178 | } | ||
179 | |||
180 | void dirty_kb(int kb) | ||
181 | { | ||
182 | int32_t one_kb[256]; | ||
183 | int32_t sum = 0; | ||
184 | int32_t i; | ||
185 | |||
186 | for (i = 0; i < 256; i++) | ||
187 | sum += one_kb[i]; | ||
188 | kb--; | ||
189 | /* prevent tail recursion */ | ||
190 | if (kb) | ||
191 | dirty_kb(kb); | ||
192 | for (i = 0; i < 256; i++) | ||
193 | sum += one_kb[i]; | ||
194 | } | ||
195 | |||
196 | int job(struct thread_context* ctx) | ||
197 | { | ||
198 | /* Do real-time calculation. */ | ||
199 | dirty_kb(8); | ||
200 | |||
201 | /* Don't exit. */ | ||
202 | //return ctx->count++ > 100; | ||
203 | //return ctx->count++ > 12000; | ||
204 | //return ctx->count++ > 120000; | ||
205 | return ctx->count++ > 30000; // controls number of jobs per task | ||
206 | } | ||
diff --git a/bin/rtspin.beta.c b/bin/rtspin.beta.c new file mode 100644 index 0000000..556660e --- /dev/null +++ b/bin/rtspin.beta.c | |||
@@ -0,0 +1,283 @@ | |||
1 | #include <sys/time.h> | ||
2 | |||
3 | #include <stdio.h> | ||
4 | #include <stdlib.h> | ||
5 | #include <unistd.h> | ||
6 | #include <time.h> | ||
7 | #include <assert.h> | ||
8 | #include <strings.h> | ||
9 | |||
10 | #include <gsl/gsl_rng.h> | ||
11 | #include <gsl/gsl_randist.h> | ||
12 | |||
13 | #include "litmus.h" | ||
14 | #include "common.h" | ||
15 | |||
16 | #include <litmus/sched_mc.h> | ||
17 | |||
18 | |||
19 | static void usage(char *error) { | ||
20 | fprintf(stderr, "Error: %s\n", error); | ||
21 | fprintf(stderr, | ||
22 | "Usage:\n" | ||
23 | " rt_spin [COMMON-OPTS] LVL_C_TIME WCET PERIOD DURATION\n" | ||
24 | " rt_spin -l\n" | ||
25 | "\n" | ||
26 | "COMMON-OPTS = [-w] [-p PARTITION] [-c CLASS] [-s SCALE]\n" | ||
27 | " [-r CRITICALITY = [a|b|c|d]] [-i MC-LVL-A-ID]\n" | ||
28 | " [-a ALPHA] [-b BETA] [-d SEED]\n" | ||
29 | "\n" | ||
30 | "WCET and PERIOD are nanoseconds, DURATION is seconds.\n"); | ||
31 | exit(EXIT_FAILURE); | ||
32 | } | ||
33 | |||
34 | #define NUMS 4096 | ||
35 | static int num[NUMS]; | ||
36 | static char* progname; | ||
37 | |||
38 | static gsl_rng *beta_rng; | ||
39 | static gsl_rng *coin_rng; | ||
40 | |||
41 | static void setup_rng(unsigned long seed) | ||
42 | { | ||
43 | beta_rng = gsl_rng_alloc(gsl_rng_taus); | ||
44 | coin_rng = gsl_rng_alloc(gsl_rng_taus); | ||
45 | if (!beta_rng || !coin_rng) | ||
46 | bail_out("Could not initialize RNG"); | ||
47 | gsl_rng_set(beta_rng, seed); | ||
48 | gsl_rng_set(coin_rng, seed); | ||
49 | } | ||
50 | |||
51 | static int loop_once(void) | ||
52 | { | ||
53 | int i, j = 0; | ||
54 | for (i = 0; i < NUMS; i++) | ||
55 | j += num[i]++; | ||
56 | return j; | ||
57 | } | ||
58 | |||
59 | static int loop_for(double exec_time, double emergency_exit) | ||
60 | { | ||
61 | double last_loop = 0, loop_start; | ||
62 | int tmp = 0; | ||
63 | |||
64 | double start = cputime(); | ||
65 | double now = cputime(); | ||
66 | |||
67 | while (now + last_loop < start + exec_time) { | ||
68 | loop_start = now; | ||
69 | tmp += loop_once(); | ||
70 | now = cputime(); | ||
71 | last_loop = now - loop_start; | ||
72 | if (emergency_exit && wctime() > emergency_exit) { | ||
73 | /* Oops --- this should only be possible if the execution time tracking | ||
74 | * is broken in the LITMUS^RT kernel. */ | ||
75 | fprintf(stderr, "!!! rtspin/%d emergency exit!\n", getpid()); | ||
76 | fprintf(stderr, "Something is seriously wrong! Do not ignore this.\n"); | ||
77 | break; | ||
78 | } | ||
79 | } | ||
80 | |||
81 | return tmp; | ||
82 | } | ||
83 | |||
84 | |||
85 | static void debug_delay_loop(void) | ||
86 | { | ||
87 | double start, end, delay; | ||
88 | |||
89 | while (1) { | ||
90 | for (delay = 0.5; delay > 0.01; delay -= 0.01) { | ||
91 | start = wctime(); | ||
92 | loop_for(delay, 0); | ||
93 | end = wctime(); | ||
94 | printf("%6.4fs: looped for %10.8fs, delta=%11.8fs, error=%7.4f%%\n", | ||
95 | delay, | ||
96 | end - start, | ||
97 | end - start - delay, | ||
98 | 100 * (end - start - delay) / delay); | ||
99 | } | ||
100 | } | ||
101 | } | ||
102 | |||
103 | static int job(double exec_time, double program_end) | ||
104 | { | ||
105 | if (wctime() > program_end) | ||
106 | return 0; | ||
107 | else { | ||
108 | loop_for(exec_time, program_end + 1); | ||
109 | sleep_next_period(); | ||
110 | return 1; | ||
111 | } | ||
112 | } | ||
113 | |||
114 | enum crit_level str2crit(const char* str) | ||
115 | { | ||
116 | if (0 == strncasecmp("a", str, 1)) | ||
117 | return CRIT_LEVEL_A; | ||
118 | else if (0 == strncasecmp("b", str, 1)) | ||
119 | return CRIT_LEVEL_B; | ||
120 | else if (0 == strncasecmp("c", str, 1)) | ||
121 | return CRIT_LEVEL_C; | ||
122 | /* failure */ | ||
123 | return NUM_CRIT_LEVELS; | ||
124 | } | ||
125 | |||
126 | #define OPTSTR "a:b:d:p:c:wlves:r:i:" | ||
127 | |||
128 | #define COIN_PROB 0.5 | ||
129 | |||
130 | int main(int argc, char** argv) | ||
131 | { | ||
132 | int ret; | ||
133 | lt_t wcet; | ||
134 | lt_t period; | ||
135 | lt_t lvl_c_time; | ||
136 | int migrate = 0; | ||
137 | int cpu = 0; | ||
138 | int opt; | ||
139 | int wait = 0; | ||
140 | int test_loop = 0; | ||
141 | int want_enforcement = 0; | ||
142 | unsigned long seed = 1; | ||
143 | double duration = 0, start; | ||
144 | double scale = 1.0; | ||
145 | double alpha = -1, beta = -1, beta_sample, exec_time; | ||
146 | task_class_t class = RT_CLASS_HARD; | ||
147 | struct mc_task mc_task = { .crit = NUM_CRIT_LEVELS, .lvl_a_id = -1 }; | ||
148 | |||
149 | progname = argv[0]; | ||
150 | |||
151 | while ((opt = getopt(argc, argv, OPTSTR)) != -1) { | ||
152 | switch (opt) { | ||
153 | case 'a': | ||
154 | alpha = atof(optarg); | ||
155 | break; | ||
156 | case 'b': | ||
157 | beta = atof(optarg); | ||
158 | break; | ||
159 | case 'd': | ||
160 | seed = atoi(optarg); | ||
161 | break; | ||
162 | case 'w': | ||
163 | wait = 1; | ||
164 | break; | ||
165 | case 'p': | ||
166 | cpu = atoi(optarg); | ||
167 | migrate = 1; | ||
168 | break; | ||
169 | case 'c': | ||
170 | class = str2class(optarg); | ||
171 | if (class == -1) | ||
172 | usage("Unknown task class."); | ||
173 | break; | ||
174 | case 'e': | ||
175 | want_enforcement = 1; | ||
176 | break; | ||
177 | case 'l': | ||
178 | test_loop = 1; | ||
179 | break; | ||
180 | case 's': | ||
181 | scale = atof(optarg); | ||
182 | break; | ||
183 | case 'r': | ||
184 | mc_task.crit = str2crit(optarg); | ||
185 | if (NUM_CRIT_LEVELS == mc_task.crit) | ||
186 | usage("Bad crit level."); | ||
187 | break; | ||
188 | case 'i': | ||
189 | mc_task.lvl_a_id = atoi(optarg); | ||
190 | break; | ||
191 | case ':': | ||
192 | usage("Argument missing."); | ||
193 | break; | ||
194 | case '?': | ||
195 | default: | ||
196 | usage("Bad argument."); | ||
197 | break; | ||
198 | } | ||
199 | } | ||
200 | |||
201 | if (test_loop) { | ||
202 | debug_delay_loop(); | ||
203 | return 0; | ||
204 | } | ||
205 | |||
206 | if (argc - optind < 4) | ||
207 | usage("Arguments missing."); | ||
208 | |||
209 | lvl_c_time = atoi(argv[optind + 0]); | ||
210 | wcet = atoi(argv[optind + 1]); | ||
211 | period = atoi(argv[optind + 2]); | ||
212 | |||
213 | if (seed < 1) | ||
214 | usage("Seed < 1 not allowed."); | ||
215 | if (alpha <= 0 || beta <= 0) | ||
216 | usage("Need positive alpha and beta."); | ||
217 | if (wcet <= 0) | ||
218 | usage("The worst-case execution time must be a " | ||
219 | "positive number."); | ||
220 | if (period <= 0) | ||
221 | usage("The period must be a positive number."); | ||
222 | if (wcet > period) { | ||
223 | usage("The worst-case execution time must not " | ||
224 | "exceed the period."); | ||
225 | } | ||
226 | |||
227 | duration = atof(argv[optind + 3]); | ||
228 | |||
229 | setup_rng(seed); | ||
230 | |||
231 | if (migrate) { | ||
232 | ret = be_migrate_to(cpu); | ||
233 | if (ret < 0) | ||
234 | bail_out("could not migrate to target partition"); | ||
235 | } | ||
236 | |||
237 | ret = sporadic_task_ns(wcet, period, 0, cpu, class, | ||
238 | want_enforcement ? PRECISE_ENFORCEMENT | ||
239 | : NO_ENFORCEMENT, | ||
240 | migrate); | ||
241 | if (ret < 0) | ||
242 | bail_out("could not setup rt task params"); | ||
243 | |||
244 | if (NUM_CRIT_LEVELS != mc_task.crit) { | ||
245 | ret = set_rt_task_mc_param(gettid(), &mc_task); | ||
246 | if (ret < 0) | ||
247 | bail_out("could not setup rt mixed criticality params"); | ||
248 | } | ||
249 | |||
250 | init_litmus(); | ||
251 | |||
252 | ret = task_mode(LITMUS_RT_TASK); | ||
253 | if (ret != 0) | ||
254 | bail_out("could not become RT task"); | ||
255 | |||
256 | if (wait) { | ||
257 | ret = wait_for_ts_release(); | ||
258 | if (ret != 0) | ||
259 | bail_out("wait_for_ts_release()"); | ||
260 | } | ||
261 | |||
262 | start = wctime(); | ||
263 | |||
264 | do { | ||
265 | double coin_flip = gsl_rng_uniform(coin_rng); | ||
266 | if (coin_flip < COIN_PROB) { | ||
267 | beta_sample = gsl_ran_beta(beta_rng, alpha, beta); | ||
268 | exec_time = lvl_c_time * 20.0 * beta_sample * scale; | ||
269 | } else | ||
270 | exec_time = lvl_c_time; | ||
271 | /* convert to seconds */ | ||
272 | exec_time = exec_time * 0.000000001; | ||
273 | } while(job(exec_time, start + duration)); | ||
274 | |||
275 | ret = task_mode(BACKGROUND_TASK); | ||
276 | if (ret != 0) | ||
277 | bail_out("could not become regular task (huh?)"); | ||
278 | |||
279 | gsl_rng_free(beta_rng); | ||
280 | gsl_rng_free(coin_rng); | ||
281 | |||
282 | return 0; | ||
283 | } | ||
diff --git a/bin/rtspin.c b/bin/rtspin.c index a6a8ac6..a19637c 100644 --- a/bin/rtspin.c +++ b/bin/rtspin.c | |||
@@ -5,13 +5,12 @@ | |||
5 | #include <unistd.h> | 5 | #include <unistd.h> |
6 | #include <time.h> | 6 | #include <time.h> |
7 | #include <assert.h> | 7 | #include <assert.h> |
8 | 8 | #include <strings.h> | |
9 | #include <string.h> | ||
9 | 10 | ||
10 | #include "litmus.h" | 11 | #include "litmus.h" |
11 | #include "common.h" | 12 | #include "common.h" |
12 | 13 | ||
13 | |||
14 | |||
15 | static void usage(char *error) { | 14 | static void usage(char *error) { |
16 | fprintf(stderr, "Error: %s\n", error); | 15 | fprintf(stderr, "Error: %s\n", error); |
17 | fprintf(stderr, | 16 | fprintf(stderr, |
@@ -21,6 +20,7 @@ static void usage(char *error) { | |||
21 | " rt_spin -l\n" | 20 | " rt_spin -l\n" |
22 | "\n" | 21 | "\n" |
23 | "COMMON-OPTS = [-w] [-p PARTITION] [-c CLASS] [-s SCALE]\n" | 22 | "COMMON-OPTS = [-w] [-p PARTITION] [-c CLASS] [-s SCALE]\n" |
23 | " [-h NUM-COLORS,AVG-WAYS]\n" | ||
24 | "\n" | 24 | "\n" |
25 | "WCET and PERIOD are milliseconds, DURATION is seconds.\n"); | 25 | "WCET and PERIOD are milliseconds, DURATION is seconds.\n"); |
26 | exit(EXIT_FAILURE); | 26 | exit(EXIT_FAILURE); |
@@ -161,7 +161,7 @@ static int job(double exec_time, double program_end) | |||
161 | } | 161 | } |
162 | } | 162 | } |
163 | 163 | ||
164 | #define OPTSTR "p:c:wlveo:f:s:" | 164 | #define OPTSTR "p:c:wlveo:f:s:h:" |
165 | 165 | ||
166 | int main(int argc, char** argv) | 166 | int main(int argc, char** argv) |
167 | { | 167 | { |
@@ -181,7 +181,9 @@ int main(int argc, char** argv) | |||
181 | double *exec_times = NULL; | 181 | double *exec_times = NULL; |
182 | double scale = 1.0; | 182 | double scale = 1.0; |
183 | task_class_t class = RT_CLASS_HARD; | 183 | task_class_t class = RT_CLASS_HARD; |
184 | int cur_job, num_jobs = 0; | 184 | int cur_job, num_jobs; |
185 | int task_colors = 0; | ||
186 | int avg_ways = 0; | ||
185 | 187 | ||
186 | progname = argv[0]; | 188 | progname = argv[0]; |
187 | 189 | ||
@@ -214,6 +216,9 @@ int main(int argc, char** argv) | |||
214 | case 's': | 216 | case 's': |
215 | scale = atof(optarg); | 217 | scale = atof(optarg); |
216 | break; | 218 | break; |
219 | case 'h': | ||
220 | sscanf(optarg, "%d,%d", &task_colors, &avg_ways); | ||
221 | break; | ||
217 | case ':': | 222 | case ':': |
218 | usage("Argument missing."); | 223 | usage("Argument missing."); |
219 | break; | 224 | break; |
@@ -283,6 +288,8 @@ int main(int argc, char** argv) | |||
283 | 288 | ||
284 | init_litmus(); | 289 | init_litmus(); |
285 | 290 | ||
291 | request_resources(task_colors, avg_ways); | ||
292 | |||
286 | ret = task_mode(LITMUS_RT_TASK); | 293 | ret = task_mode(LITMUS_RT_TASK); |
287 | if (ret != 0) | 294 | if (ret != 0) |
288 | bail_out("could not become RT task"); | 295 | bail_out("could not become RT task"); |
diff --git a/bin/rtspin.ovh.c b/bin/rtspin.ovh.c new file mode 100644 index 0000000..d130eac --- /dev/null +++ b/bin/rtspin.ovh.c | |||
@@ -0,0 +1,239 @@ | |||
1 | #include <sys/time.h> | ||
2 | |||
3 | #include <stdio.h> | ||
4 | #include <stdlib.h> | ||
5 | #include <unistd.h> | ||
6 | #include <time.h> | ||
7 | #include <assert.h> | ||
8 | #include <strings.h> | ||
9 | |||
10 | |||
11 | #include "litmus.h" | ||
12 | #include "common.h" | ||
13 | |||
14 | #include <litmus/sched_mc.h> | ||
15 | |||
16 | |||
17 | static void usage(char *error) { | ||
18 | fprintf(stderr, "Error: %s\n", error); | ||
19 | fprintf(stderr, | ||
20 | "Usage:\n" | ||
21 | " rt_spin [COMMON-OPTS] EXEC_TIME WCET PERIOD DURATION\n" | ||
22 | " rt_spin -l\n" | ||
23 | "\n" | ||
24 | "COMMON-OPTS = [-w] [-p PARTITION] [-c CLASS] [-s SCALE]\n" | ||
25 | " [-r CRITICALITY = [a|b|c|d]] [-i MC-LVL-A-ID]\n" | ||
26 | "\n" | ||
27 | "WCET and PERIOD are nanoseconds, DURATION is seconds.\n"); | ||
28 | exit(EXIT_FAILURE); | ||
29 | } | ||
30 | |||
31 | #define NUMS 4096 | ||
32 | static int num[NUMS]; | ||
33 | static char* progname; | ||
34 | |||
35 | static int loop_once(void) | ||
36 | { | ||
37 | int i, j = 0; | ||
38 | for (i = 0; i < NUMS; i++) | ||
39 | j += num[i]++; | ||
40 | return j; | ||
41 | } | ||
42 | |||
43 | static int loop_for(double exec_time, double emergency_exit) | ||
44 | { | ||
45 | double last_loop = 0, loop_start; | ||
46 | int tmp = 0; | ||
47 | |||
48 | double start = cputime(); | ||
49 | double now = cputime(); | ||
50 | |||
51 | while (now + last_loop < start + exec_time) { | ||
52 | loop_start = now; | ||
53 | tmp += loop_once(); | ||
54 | now = cputime(); | ||
55 | last_loop = now - loop_start; | ||
56 | if (emergency_exit && wctime() > emergency_exit) { | ||
57 | /* Oops --- this should only be possible if the execution time tracking | ||
58 | * is broken in the LITMUS^RT kernel. */ | ||
59 | fprintf(stderr, "!!! rtspin/%d emergency exit!\n", getpid()); | ||
60 | fprintf(stderr, "Something is seriously wrong! Do not ignore this.\n"); | ||
61 | break; | ||
62 | } | ||
63 | } | ||
64 | |||
65 | return tmp; | ||
66 | } | ||
67 | |||
68 | |||
69 | static void debug_delay_loop(void) | ||
70 | { | ||
71 | double start, end, delay; | ||
72 | |||
73 | while (1) { | ||
74 | for (delay = 0.5; delay > 0.01; delay -= 0.01) { | ||
75 | start = wctime(); | ||
76 | loop_for(delay, 0); | ||
77 | end = wctime(); | ||
78 | printf("%6.4fs: looped for %10.8fs, delta=%11.8fs, error=%7.4f%%\n", | ||
79 | delay, | ||
80 | end - start, | ||
81 | end - start - delay, | ||
82 | 100 * (end - start - delay) / delay); | ||
83 | } | ||
84 | } | ||
85 | } | ||
86 | |||
87 | static int job(double exec_time, double program_end) | ||
88 | { | ||
89 | if (wctime() > program_end) | ||
90 | return 0; | ||
91 | else { | ||
92 | loop_for(exec_time, program_end + 1); | ||
93 | sleep_next_period(); | ||
94 | return 1; | ||
95 | } | ||
96 | } | ||
97 | |||
98 | enum crit_level str2crit(const char* str) | ||
99 | { | ||
100 | if (0 == strncasecmp("a", str, 1)) | ||
101 | return CRIT_LEVEL_A; | ||
102 | else if (0 == strncasecmp("b", str, 1)) | ||
103 | return CRIT_LEVEL_B; | ||
104 | else if (0 == strncasecmp("c", str, 1)) | ||
105 | return CRIT_LEVEL_C; | ||
106 | /* failure */ | ||
107 | return NUM_CRIT_LEVELS; | ||
108 | } | ||
109 | |||
110 | #define OPTSTR "p:c:wlves:r:i:" | ||
111 | |||
112 | int main(int argc, char** argv) | ||
113 | { | ||
114 | int ret; | ||
115 | lt_t exec_time; | ||
116 | lt_t wcet; | ||
117 | lt_t period; | ||
118 | int migrate = 0; | ||
119 | int cpu = 0; | ||
120 | int opt; | ||
121 | int wait = 0; | ||
122 | int test_loop = 0; | ||
123 | int want_enforcement = 0; | ||
124 | double duration = 0, start; | ||
125 | double scale = 1.0; | ||
126 | task_class_t class = RT_CLASS_HARD; | ||
127 | struct mc_task mc_task = { .crit = NUM_CRIT_LEVELS, .lvl_a_id = -1 }; | ||
128 | |||
129 | progname = argv[0]; | ||
130 | |||
131 | while ((opt = getopt(argc, argv, OPTSTR)) != -1) { | ||
132 | switch (opt) { | ||
133 | case 'w': | ||
134 | wait = 1; | ||
135 | break; | ||
136 | case 'p': | ||
137 | cpu = atoi(optarg); | ||
138 | migrate = 1; | ||
139 | break; | ||
140 | case 'c': | ||
141 | class = str2class(optarg); | ||
142 | if (class == -1) | ||
143 | usage("Unknown task class."); | ||
144 | break; | ||
145 | case 'e': | ||
146 | want_enforcement = 1; | ||
147 | break; | ||
148 | case 'l': | ||
149 | test_loop = 1; | ||
150 | break; | ||
151 | case 's': | ||
152 | scale = atof(optarg); | ||
153 | break; | ||
154 | case 'r': | ||
155 | mc_task.crit = str2crit(optarg); | ||
156 | if (NUM_CRIT_LEVELS == mc_task.crit) | ||
157 | usage("Bad crit level."); | ||
158 | break; | ||
159 | case 'i': | ||
160 | mc_task.lvl_a_id = atoi(optarg); | ||
161 | break; | ||
162 | case ':': | ||
163 | usage("Argument missing."); | ||
164 | break; | ||
165 | case '?': | ||
166 | default: | ||
167 | usage("Bad argument."); | ||
168 | break; | ||
169 | } | ||
170 | } | ||
171 | |||
172 | if (test_loop) { | ||
173 | debug_delay_loop(); | ||
174 | return 0; | ||
175 | } | ||
176 | |||
177 | if (argc - optind < 4) | ||
178 | usage("Arguments missing."); | ||
179 | |||
180 | exec_time = atoi(argv[optind + 0]); | ||
181 | wcet = atoi(argv[optind + 1]); | ||
182 | period = atoi(argv[optind + 2]); | ||
183 | |||
184 | if (exec_time <= 0 || exec_time > period) | ||
185 | usage("bad execution time"); | ||
186 | if (wcet <= 0) | ||
187 | usage("The worst-case execution time must be a " | ||
188 | "positive number."); | ||
189 | if (period <= 0) | ||
190 | usage("The period must be a positive number."); | ||
191 | if (wcet > period) { | ||
192 | usage("The worst-case execution time must not " | ||
193 | "exceed the period."); | ||
194 | } | ||
195 | |||
196 | duration = atof(argv[optind + 3]); | ||
197 | |||
198 | if (migrate) { | ||
199 | ret = be_migrate_to(cpu); | ||
200 | if (ret < 0) | ||
201 | bail_out("could not migrate to target partition"); | ||
202 | } | ||
203 | |||
204 | ret = sporadic_task_ns(wcet, period, 0, cpu, class, | ||
205 | want_enforcement ? PRECISE_ENFORCEMENT | ||
206 | : NO_ENFORCEMENT, | ||
207 | migrate); | ||
208 | if (ret < 0) | ||
209 | bail_out("could not setup rt task params"); | ||
210 | |||
211 | if (NUM_CRIT_LEVELS != mc_task.crit) { | ||
212 | ret = set_rt_task_mc_param(gettid(), &mc_task); | ||
213 | if (ret < 0) | ||
214 | bail_out("could not setup rt mixed criticality params"); | ||
215 | } | ||
216 | |||
217 | init_litmus(); | ||
218 | |||
219 | ret = task_mode(LITMUS_RT_TASK); | ||
220 | if (ret != 0) | ||
221 | bail_out("could not become RT task"); | ||
222 | |||
223 | if (wait) { | ||
224 | ret = wait_for_ts_release(); | ||
225 | if (ret != 0) | ||
226 | bail_out("wait_for_ts_release()"); | ||
227 | } | ||
228 | |||
229 | start = wctime(); | ||
230 | |||
231 | /* conver to seconds and scale */ | ||
232 | while (job(exec_time * 0.000000001 * scale, start + duration)); | ||
233 | |||
234 | ret = task_mode(BACKGROUND_TASK); | ||
235 | if (ret != 0) | ||
236 | bail_out("could not become regular task (huh?)"); | ||
237 | |||
238 | return 0; | ||
239 | } | ||
diff --git a/include/common.h b/include/common.h index d1234ba..5c7ed68 100644 --- a/include/common.h +++ b/include/common.h | |||
@@ -1,7 +1,8 @@ | |||
1 | #ifndef COMMON_H | 1 | #ifndef COMMON_H |
2 | #define COMMON_H | 2 | #define COMMON_H |
3 | 3 | ||
4 | |||
5 | void bail_out(const char* msg); | 4 | void bail_out(const char* msg); |
6 | 5 | ||
6 | void request_resources(int task_colors, int avg_ways); | ||
7 | |||
7 | #endif | 8 | #endif |
diff --git a/include/litmus.h b/include/litmus.h index 4c85d28..82e2ba2 100644 --- a/include/litmus.h +++ b/include/litmus.h | |||
@@ -27,6 +27,9 @@ int be_migrate_to(int target_cpu); | |||
27 | int set_rt_task_param(pid_t pid, struct rt_task* param); | 27 | int set_rt_task_param(pid_t pid, struct rt_task* param); |
28 | int get_rt_task_param(pid_t pid, struct rt_task* param); | 28 | int get_rt_task_param(pid_t pid, struct rt_task* param); |
29 | 29 | ||
30 | struct mc_task; | ||
31 | int set_rt_task_mc_param(pid_t pid, struct mc_task *param); | ||
32 | |||
30 | /* setup helper */ | 33 | /* setup helper */ |
31 | 34 | ||
32 | /* times are given in ms */ | 35 | /* times are given in ms */ |
diff --git a/src/kernel_iface.c b/src/kernel_iface.c index 33d56df..bd47d5c 100644 --- a/src/kernel_iface.c +++ b/src/kernel_iface.c | |||
@@ -75,6 +75,13 @@ void exit_np(void) | |||
75 | } | 75 | } |
76 | } | 76 | } |
77 | 77 | ||
78 | void request_resource(int resource, int replicas) | ||
79 | { | ||
80 | if (likely(ctrl_page != NULL)) { | ||
81 | ctrl_page->requests[resource] = replicas; | ||
82 | } | ||
83 | } | ||
84 | |||
78 | int requested_to_preempt(void) | 85 | int requested_to_preempt(void) |
79 | { | 86 | { |
80 | return (likely(ctrl_page != NULL) && ctrl_page->sched.np.preempt); | 87 | return (likely(ctrl_page != NULL) && ctrl_page->sched.np.preempt); |
diff --git a/src/litmus.c b/src/litmus.c index d3cc6bb..d8a6b96 100644 --- a/src/litmus.c +++ b/src/litmus.c | |||
@@ -72,6 +72,7 @@ int sporadic_task_ns(lt_t e, lt_t p, lt_t phase, | |||
72 | ret = be_migrate_to(cpu); | 72 | ret = be_migrate_to(cpu); |
73 | check("migrate to cpu"); | 73 | check("migrate to cpu"); |
74 | } | 74 | } |
75 | |||
75 | return set_rt_task_param(gettid(), ¶m); | 76 | return set_rt_task_param(gettid(), ¶m); |
76 | } | 77 | } |
77 | 78 | ||