aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorztong <ztong@cs.unc.edu>2021-06-12 17:08:01 -0400
committerztong <ztong@cs.unc.edu>2021-06-12 17:08:01 -0400
commitbbaa2b43b6efdd175b26bced3b0d95315b4dcdc1 (patch)
tree69bb17150df6ffc34727df0c5dbb382db8345dbf
parentcd4c9a86e447690fe1b66545b9c141432f017237 (diff)
Added GPU spinning in critical sections for rtspinecrts21
-rw-r--r--Makefile14
-rw-r--r--bin/cuda_loop.cu29
-rw-r--r--bin/gpu-rtspin.c914
-rw-r--r--bin/rtspin.c2
4 files changed, 956 insertions, 3 deletions
diff --git a/Makefile b/Makefile
index 2b615b5..4aa6c3a 100644
--- a/Makefile
+++ b/Makefile
@@ -19,7 +19,7 @@ LITMUS_KERNEL ?= ../litmus-rt
19# Internal configuration. 19# Internal configuration.
20 20
21# compiler flags 21# compiler flags
22flags-debug = -O2 -Wall -Werror -g -Wdeclaration-after-statement 22flags-debug = -O2 -Wall -Wno-error -g -Wdeclaration-after-statement
23flags-api = -D_XOPEN_SOURCE=600 -D_GNU_SOURCE 23flags-api = -D_XOPEN_SOURCE=600 -D_GNU_SOURCE
24 24
25# architecture-specific flags 25# architecture-specific flags
@@ -37,6 +37,7 @@ include-${ARCH} ?= ${ARCH}
37 37
38# by default we use the local version 38# by default we use the local version
39LIBLITMUS ?= . 39LIBLITMUS ?= .
40CUDA ?= /usr/local/cuda/lib64
40 41
41# where to find header files 42# where to find header files
42headers = -I${LIBLITMUS}/include -I${LIBLITMUS}/arch/${include-${ARCH}}/include 43headers = -I${LIBLITMUS}/include -I${LIBLITMUS}/arch/${include-${ARCH}}/include
@@ -50,6 +51,7 @@ LDFLAGS = ${flags-${ARCH}}
50 51
51# how to link against liblitmus 52# how to link against liblitmus
52liblitmus-flags = -L${LIBLITMUS} -llitmus 53liblitmus-flags = -L${LIBLITMUS} -llitmus
54cuda-flags = -L${CUDA} -lcudart
53 55
54# Force gcc instead of cc, but let the user specify a more specific version if 56# Force gcc instead of cc, but let the user specify a more specific version if
55# desired. 57# desired.
@@ -65,7 +67,7 @@ AR := ${CROSS_COMPILE}${AR}
65# ############################################################################## 67# ##############################################################################
66# Targets 68# Targets
67 69
68all = lib ${rt-apps} 70all = lib gpu-rtspin ${rt-apps}
69rt-apps = cycles base_task rt_launch rtspin release_ts measure_syscall \ 71rt-apps = cycles base_task rt_launch rtspin release_ts measure_syscall \
70 base_mt_task uncache runtests resctl 72 base_mt_task uncache runtests resctl
71 73
@@ -115,6 +117,7 @@ doc:
115 117
116clean: 118clean:
117 rm -f ${rt-apps} 119 rm -f ${rt-apps}
120 rm -f gpu-rtspin
118 rm -f *.o *.d *.a test_catalog.inc 121 rm -f *.o *.d *.a test_catalog.inc
119 rm -f ${imported-headers} 122 rm -f ${imported-headers}
120 rm -f inc/config.makefile 123 rm -f inc/config.makefile
@@ -218,6 +221,8 @@ obj-rt_launch = rt_launch.o common.o
218obj-rtspin = rtspin.o common.o 221obj-rtspin = rtspin.o common.o
219lib-rtspin = -lrt 222lib-rtspin = -lrt
220 223
224obj-gpu-rtspin = gpu-rtspin.o common.o cuda_loop.o
225
221obj-uncache = uncache.o 226obj-uncache = uncache.o
222lib-uncache = -lrt 227lib-uncache = -lrt
223 228
@@ -228,6 +233,8 @@ lib-measure_syscall = -lm
228 233
229obj-resctl = resctl.o 234obj-resctl = resctl.o
230 235
236cuda_loop.o: bin/cuda_loop.cu
237 nvcc -c bin/cuda_loop.cu
231 238
232# ############################################################################## 239# ##############################################################################
233# Build everything that depends on liblitmus. 240# Build everything that depends on liblitmus.
@@ -236,6 +243,9 @@ obj-resctl = resctl.o
236${rt-apps}: $${obj-$$@} liblitmus.a 243${rt-apps}: $${obj-$$@} liblitmus.a
237 $(CC) -o $@ $(LDFLAGS) ${ldf-$@} $(filter-out liblitmus.a,$+) $(LOADLIBS) $(LDLIBS) ${liblitmus-flags} ${lib-$@} 244 $(CC) -o $@ $(LDFLAGS) ${ldf-$@} $(filter-out liblitmus.a,$+) $(LOADLIBS) $(LDLIBS) ${liblitmus-flags} ${lib-$@}
238 245
246gpu-rtspin: ${obj-gpu-rtspin} liblitmus.a
247 g++ -o gpu-rtspin $(LDFLAGS) ${ldf-gpu-rtspin} $(filter-out liblitmus.a,$+) $(LOADLIBS) $(LDLIBS) ${liblitmus-flags} ${lib-gpu-rtspin} ${cuda-flags}
248
239# ############################################################################## 249# ##############################################################################
240# Dependency resolution. 250# Dependency resolution.
241 251
diff --git a/bin/cuda_loop.cu b/bin/cuda_loop.cu
new file mode 100644
index 0000000..0ddbf9c
--- /dev/null
+++ b/bin/cuda_loop.cu
@@ -0,0 +1,29 @@
1#include <inttypes.h>
2#include <cuda_runtime_api.h>
3
4__device__ inline uint64_t GlobalTimer64(void) {
5 volatile uint64_t time;
6 asm volatile("mov.u64 %0, %%globaltimer;" : "=l"(time));
7 return time;
8}
9
10__global__ void cuda_loop(int cs_length) {
11 uint64_t start_time = GlobalTimer64();
12 int ms2ns = 1000000;
13 while (GlobalTimer64() - start_time < cs_length * ms2ns) {
14 continue;
15 }
16}
17
18extern "C" void gpu_loop_start(int cs_length) {
19 cuda_loop<<<1, 1>>>(0.95 * cs_length);
20}
21
22extern "C" void wait_for_gpu_loop_end(void) {
23 cudaDeviceSynchronize();
24}
25
26extern "C" void init_gpu_context(int* dev_mem) {
27 cudaSetDeviceFlags(2);
28 cudaMalloc(&dev_mem, 8);
29}
diff --git a/bin/gpu-rtspin.c b/bin/gpu-rtspin.c
new file mode 100644
index 0000000..ed4497e
--- /dev/null
+++ b/bin/gpu-rtspin.c
@@ -0,0 +1,914 @@
1#include <sys/time.h>
2
3#include <fcntl.h>
4#include <stdio.h>
5#include <stdlib.h>
6#include <unistd.h>
7#include <limits.h>
8#include <time.h>
9#include <string.h>
10#include <assert.h>
11#include <inttypes.h>
12#include <sys/mman.h>
13#include <errno.h>
14#include <signal.h>
15
16#include "litmus.h"
17#include "common.h"
18
19const char *usage_msg =
20 "Usage: (1) rtspin OPTIONS WCET PERIOD DURATION\n"
21 " (2) rtspin -S [INPUT] WCET PERIOD DURATION\n"
22 " (3) rtspin OPTIONS -C FILE:COLUMN WCET PERIOD [DURATION]\n"
23 " (4) rtspin -l [-a CYCLES]\n"
24 " (5) rtspin -B -m FOOTPRINT\n"
25 " (6) rtspin -a 0\n"
26 "\n"
27 "Modes: (1) run as periodic task with given WCET and PERIOD\n"
28 " (2) run as sporadic task with given WCET and PERIOD,\n"
29 " using INPUT as a file from which events are received\n"
30 " by means of blocking reads (default: read from STDIN)\n"
31 " (3) as (1) or (2), but load per-job execution times from\n"
32 " the given column of a CSV file\n"
33 " (4) Run calibration loop (how accurately are target\n"
34 " runtimes met?)\n"
35 " (5) Run background, non-real-time cache-thrashing loop.\n"
36 " (6) Run 1 ms workload calibration (estimate cycles for 1ms, 10ms, 100ms workload)\n"
37 "\n"
38 "Required arguments:\n"
39 " WCET, PERIOD reservation parameters (in ms)\n"
40 " DURATION terminate the task after DURATION seconds\n"
41 "\n"
42 "Options:\n"
43 " -a CYCLES number of cycles for 1ms of workload loop chosen after calibration;\n "
44 " pass '0' to run the calibration loop\n"
45 " -B run non-real-time background loop\n"
46 " -c be|srt|hrt task class (best-effort, soft real-time, hard real-time)\n"
47 " -d DEADLINE relative deadline, equal to the period by default (in ms)\n"
48 " -e turn on budget enforcement (off by default)\n"
49 " -h show this help message\n"
50 " -i report interrupts (implies -v)\n"
51 " -l run calibration loop and report error\n"
52 " -m FOOTPRINT specify number of data pages to access\n"
53 " -o OFFSET offset (also known as phase), zero by default (in ms)\n"
54 " -p CPU partition or cluster to assign this task to\n"
55 " -q PRIORITY priority to use (ignored by EDF plugins, highest=1, lowest=511)\n"
56 " -r VCPU virtual CPU or reservation to attach to (irrelevant to most plugins)\n"
57 " -R create sporadic reservation for task (with VCPU=PID)\n"
58 " -s SCALE fraction of WCET to spin for (1.0 means 100%, default 0.95)\n"
59 " -u SLACK randomly under-run WCET by up to SLACK milliseconds\n"
60 " -U SLACK-FRACTION randomly under-run WCET by up to (WCET * SLACK-FRACTION) milliseconds \n"
61 " -v verbose (print per-job statistics)\n"
62 " -w wait for synchronous release\n"
63 "\n"
64 " -C FILE[:COLUMN] load per-job execution times from CSV file;\n"
65 " if COLUMN is given, it specifies the column to read\n"
66 " per-job execution times from (default: 1)\n"
67 " -A FILE[:COLUMN] load sporadic inter-arrival times from CSV file (implies -T);\n"
68 " if COLUMN is given, it specifies the column to read\n"
69 " inter-arrival times from (default: 1)\n"
70 "\n"
71 " -S[FILE] read from FILE to trigger sporadic job releases\n"
72 " default w/o -S: periodic job releases\n"
73 " default if FILE is omitted: read from STDIN\n"
74 " -O[FILE] write to FILE when job completes (this is useful with -S\n"
75 " to create precedence constraints/event chains)\n"
76 " default w/o -O: no output\n"
77 " default if FILE is omitted: write to STDOUT\n"
78 "\n"
79 " -T use clock_nanosleep() instead of sleep_next_period()\n"
80 " -D MAX-DELTA set maximum inter-arrival delay to MAX-DELTA [default: period]\n"
81 " -E MIN-DELTA set minimum inter-arrival delay to MIN-DELTA [default: period]\n"
82 "\n"
83 " -X PROTOCOL access a shared resource protected by a locking protocol\n"
84 " -L CS-LENGTH simulate a critical section length of CS-LENGTH milliseconds\n"
85 " -Q RESOURCE-ID access the resource identified by RESOURCE-ID\n"
86 " -Z enable checking for forbidden zones after locking a resource\n"
87 " -K enable passing worst-case critical-section duration to lock calls\n"
88 "\n"
89 "Units:\n"
90 " WCET and PERIOD are expected in milliseconds.\n"
91 " SLACK is expected in milliseconds.\n"
92 " DURATION is expected in seconds.\n"
93 " CS-LENGTH is expected in milliseconds.\n"
94 " FOOTPRINT is expected in number of pages\n";
95
96
97static void usage(char *error) {
98 if (error)
99 fprintf(stderr, "Error: %s\n\n", error);
100 else {
101 fprintf(stderr, "rtspin: simulate a periodic or sporadic "
102 "CPU-bound real-time task\n\n");
103 }
104 fprintf(stderr, "%s", usage_msg);
105 exit(error ? EXIT_FAILURE : EXIT_SUCCESS);
106}
107
108void default_sig_handler(int sig) {
109 if (sig == SIGSYS)
110 return;
111}
112
113#define NUMS 4096
114static int num[NUMS];
115static char* progname;
116
117static int nr_of_pages = 0;
118static int page_size;
119static void *base = NULL;
120
121static int cycles_ms = 0;
122
123extern void gpu_loop_start(int cs_length);
124extern void wait_for_gpu_loop_end(void);
125extern void init_gpu_context(int* dev_mem);
126
127static noinline int loop(int count)
128{
129 int i, j = 0;
130 /* touch some numbers and do some math */
131 for (i = 0; i < count; i++) {
132 int index = i % NUMS;
133 j += num[index]++;
134 if (j > num[index])
135 num[index] = (j / 2) + 1;
136 }
137 return j;
138}
139
140#define loop_once() loop(NUMS)
141
142static int loop_once_with_mem(void)
143{
144 int i, j = 0;
145 int rand;
146 int *num;
147
148 /* choose a random page */
149 if (nr_of_pages > 1)
150 rand = lrand48() % (nr_of_pages - 1);
151 else
152 rand = 0;
153
154 /* touch the randomly selected page */
155 num = base + (rand * page_size);
156 for (i = 0; i < page_size / sizeof(int); i++) {
157 j += num[i]++;
158 if (j > num[i])
159 num[i] = (j / 2) + 1;
160 }
161
162 return j;
163}
164
165static int loop_for(double exec_time, double emergency_exit)
166{
167 int tmp = 0;
168
169 if (cycles_ms) {
170 double count = cycles_ms * exec_time * 1000;
171 tmp += loop(count);
172 } else {
173 double last_loop = 0, loop_start;
174 double start = cputime();
175 double now = cputime();
176
177 while (now + last_loop < start + exec_time) {
178 loop_start = now;
179 if (nr_of_pages)
180 tmp += loop_once_with_mem();
181 else
182 tmp += loop_once();
183 now = cputime();
184 last_loop = now - loop_start;
185 if (emergency_exit && wctime() > emergency_exit) {
186 /* Oops --- this should only be possible if the
187 * execution time tracking is broken in the LITMUS^RT
188 * kernel or the user specified infeasible parameters.
189 */
190 fprintf(stderr, "!!! rtspin/%d emergency exit!\n",
191 getpid());
192 fprintf(stderr, "Reached experiment timeout while "
193 "spinning.\n");
194 break;
195 }
196 }
197 }
198
199 return tmp;
200}
201
202
203static void debug_delay_loop(void)
204{
205 double start, end, delay;
206
207 while (1) {
208 for (delay = 0.5; delay > 0.01; delay -= 0.01) {
209 start = cputime();
210 loop_for(delay, 0);
211 end = cputime();
212 printf("%6.4fs: looped for %10.8fs, delta=%11.8fs, error=%7.4f%%\n",
213 delay,
214 end - start,
215 end - start - delay,
216 100 * (end - start - delay) / delay);
217 }
218 }
219}
220
221static char input_buf[4096] = "<no input>";
222
223static int calibrate_ms(int ms)
224{
225 int right = NUMS;
226 int left = 0;
227 int middle;
228
229 double start;
230 double now;
231 double dms = 0.001 * ms;
232
233 /*look for initial loop count values for binary search*/
234 for (;;)
235 {
236 printf("Probe %d loops for %d ms:\n", right, ms);
237 start = wctime();
238 loop(right);
239 now = wctime();
240 if ((now - start) >= dms)
241 break;
242 left = right;
243 right += right;
244 }
245
246 middle = (left + right) / 2;
247
248 /*binary search for a loop count value for expected calibration time*/
249 while (left < middle)
250 {
251 start = wctime();
252 loop(middle);
253 now = wctime();
254
255 printf("%d loops elapsed in %4.20f s\n", middle, now - start);
256
257 if ((now - start) < dms)
258 left = middle;
259 else if ((now - start) == dms)
260 return middle;
261 else
262 right = middle;
263 middle = (left + right) / 2;
264 }
265 return middle;
266}
267
268static int wait_for_input(int event_fd)
269{
270 /* We do a blocking read, accepting up to 4KiB of data.
271 * For simplicity, for now, if there's more than 4KiB of data,
272 * we treat this as multiple jobs. Note that this means that
273 * tardiness can result in coalesced jobs. Ideally, there should
274 * be some sort of configurable job boundary marker, but that's
275 * not supported in this basic version yet. Patches welcome.
276 */
277 size_t consumed;
278
279 consumed = read(event_fd, input_buf, sizeof(input_buf) - 1);
280
281 if (consumed == 0)
282 fprintf(stderr, "reached end-of-file on input event stream\n");
283 if (consumed < 0)
284 fprintf(stderr, "error reading input event stream (%m)\n");
285
286 if (consumed > 0) {
287 /* zero-terminate string buffer */
288 input_buf[consumed] = '\0';
289 /* check if we can remove a trailing newline */
290 if (consumed > 1 && input_buf[consumed - 1] == '\n') {
291 input_buf[consumed - 1] = '\0';
292 }
293 }
294
295 return consumed > 0;
296}
297
298static int generate_output(int output_fd)
299{
300 char buf[4096];
301 size_t len, written;
302 unsigned int job_no;
303
304 get_job_no(&job_no);
305 len = snprintf(buf, 4095, "(rtspin/%d:%u completed: %s @ %" PRIu64 "ns)\n",
306 getpid(), job_no, input_buf, (uint64_t) litmus_clock());
307
308 written = write(output_fd, buf, len);
309
310 return written == len;
311}
312
313static void job(double exec_time, double program_end, int lock_od, double cs_length, int check_fz, int pass_cs_len)
314{
315 double chunk1, chunk2;
316 int lock_res;
317 struct sigaction handler;
318 memset(&handler, 0, sizeof(handler));
319 handler.sa_handler = default_sig_handler;
320 sigaction(SIGSYS, &handler, NULL);
321
322 if (lock_od >= 0) {
323 /* simulate critical section somewhere in the middle */
324 chunk1 = drand48() * (exec_time - cs_length);
325 chunk2 = exec_time - cs_length - chunk1;
326
327 /* non-critical section */
328 loop_for(chunk1, program_end + 1);
329
330 /* critical section */
331 if (pass_cs_len == 1)
332 lock_res = litmus_lock_cs(lock_od, cs_length);
333 else
334 lock_res = litmus_lock(lock_od);
335 if (lock_res != 0)
336 printf("Result of lock call: %d\n", lock_res);
337 if (check_fz) {
338 litmus_access_forbidden_zone_check(lock_od, s2ns(cs_length), s2ns(cs_length));
339 gpu_loop_start(cs_length);
340 litmus_set_fz_launch_done(lock_od);
341 wait_for_gpu_loop_end();
342 litmus_exit_forbidden_zone(lock_od);
343 } else {
344 gpu_loop_start(cs_length);
345 wait_for_gpu_loop_end();
346 }
347
348 litmus_unlock(lock_od);
349
350 /* non-critical section */
351 loop_for(chunk2, program_end + 2);
352 } else {
353 loop_for(exec_time, program_end + 1);
354 }
355}
356
357static lt_t choose_inter_arrival_time_ns(
358 double* arrival_times, int num_arrivals, int cur_job,
359 double range_min, double range_max)
360{
361 double iat_ms;
362
363 if (arrival_times)
364 iat_ms = arrival_times[cur_job % num_arrivals];
365 else
366 iat_ms = range_min + drand48() * (range_max - range_min);
367
368 return ms2ns(iat_ms);
369}
370
371#define OPTSTR "p:c:wlveo:s:m:q:r:X:L:Q:ZKiRu:U:Bhd:C:S::O::TD:E:A:a:"
372
373int main(int argc, char** argv)
374{
375 int ret;
376 lt_t wcet;
377 lt_t period, deadline;
378 lt_t phase;
379 lt_t inter_arrival_time;
380 double inter_arrival_min_ms = 0, inter_arrival_max_ms = 0;
381 double wcet_ms, period_ms, underrun_ms = 0;
382 double underrun_frac = 0;
383 double offset_ms = 0, deadline_ms = 0;
384 unsigned int priority = LITMUS_NO_PRIORITY;
385 int migrate = 0;
386 int cluster = 0;
387 int reservation = -1;
388 int create_reservation = 0;
389 int opt;
390 int wait = 0;
391 int test_loop = 0;
392 int caliber_ms = 0;
393 int background_loop = 0;
394
395 int cost_column = 1;
396 const char *cost_csv_file = NULL;
397 int num_jobs = 0;
398 double *exec_times = NULL;
399
400 int arrival_column = 1;
401 const char *arrival_csv_file = NULL;
402 int num_arrival_times = 0;
403 double *arrival_times = NULL;
404
405 int want_enforcement = 0;
406 double duration = 0, start = 0;
407 double scale = 0.95;
408 task_class_t class = RT_CLASS_HARD;
409 int cur_job = 0;
410 struct rt_task param;
411
412 char *after_colon;
413
414 int rss = 0;
415 int idx;
416
417 int sporadic = 0; /* trigger jobs sporadically? */
418 int event_fd = -1; /* file descriptor for sporadic events */
419 int want_output = 0; /* create output at end of job? */
420 int output_fd = -1; /* file descriptor for output */
421
422 int linux_sleep = 0; /* use Linux API for periodic activations? */
423 lt_t next_release;
424
425 int verbose = 0;
426 unsigned int job_no;
427 struct control_page* cp;
428 int report_interrupts = 0;
429 uint64_t last_irq_count = 0;
430
431 /* locking */
432 int lock_od = -1;
433 int resource_id = 0;
434 const char *lock_namespace = "./rtspin-locks";
435 int protocol = -1;
436 double cs_length = 1; /* millisecond */
437 int check_fz = 0;
438 int pass_cs_len = 0;
439
440 /* gpu */
441 int* dev_mem;
442
443 progname = argv[0];
444
445 while ((opt = getopt(argc, argv, OPTSTR)) != -1) {
446 switch (opt) {
447 case 'w':
448 wait = 1;
449 break;
450 case 'p':
451 cluster = want_non_negative_int(optarg, "-p");
452 migrate = 1;
453 break;
454 case 'r':
455 reservation = want_non_negative_int(optarg, "-r");
456 break;
457 case 'R':
458 create_reservation = 1;
459 reservation = getpid();
460 break;
461 case 'q':
462 priority = want_non_negative_int(optarg, "-q");
463 if (!litmus_is_valid_fixed_prio(priority))
464 usage("Invalid priority.");
465 break;
466 case 'c':
467 class = str2class(optarg);
468 if (class == -1)
469 usage("Unknown task class.");
470 break;
471 case 'e':
472 want_enforcement = 1;
473 break;
474 case 'l':
475 test_loop = 1;
476 break;
477 case 'B':
478 background_loop = 1;
479 break;
480 case 'C':
481 after_colon = strsplit(':', optarg);
482 cost_csv_file = optarg;
483 if (after_colon) {
484 cost_column =
485 want_non_negative_int(after_colon, "-C");
486 }
487 break;
488 case 'A':
489 after_colon = strsplit(':', optarg);
490 arrival_csv_file = optarg;
491 if (after_colon) {
492 arrival_column =
493 want_non_negative_int(after_colon, "-A");
494 }
495 linux_sleep = 1;
496 break;
497 case 'S':
498 sporadic = 1;
499 if (!optarg || strcmp(optarg, "-") == 0)
500 event_fd = STDIN_FILENO;
501 else
502 event_fd = open(optarg, O_RDONLY);
503 if (event_fd == -1) {
504 fprintf(stderr, "Could not open file '%s' "
505 "(%m)\n", optarg);
506 usage("-S requires a valid file path or '-' "
507 "for STDIN.");
508 }
509 break;
510
511 case 'O':
512 want_output = 1;
513 if (!optarg || strcmp(optarg, "-") == 0)
514 output_fd = STDOUT_FILENO;
515 else
516 output_fd = open(optarg, O_WRONLY | O_APPEND);
517 if (output_fd == -1) {
518 fprintf(stderr, "Could not open file '%s' "
519 "(%m)\n", optarg);
520 usage("-O requires a valid file path or '-' "
521 "for STDOUT.");
522 }
523 break;
524
525 case 'T':
526 linux_sleep = 1;
527 break;
528 case 'D':
529 linux_sleep = 1;
530 inter_arrival_max_ms =
531 want_non_negative_double(optarg, "-D");
532 break;
533 case 'E':
534 linux_sleep = 1;
535 inter_arrival_min_ms =
536 want_non_negative_double(optarg, "-E");
537 break;
538 case 'm':
539 nr_of_pages = want_non_negative_int(optarg, "-m");
540 break;
541 case 's':
542 scale = want_non_negative_double(optarg, "-s");
543 break;
544 case 'o':
545 offset_ms = want_non_negative_double(optarg, "-o");
546 break;
547 case 'd':
548 deadline_ms = want_non_negative_double(optarg, "-d");
549 break;
550 case 'u':
551 underrun_ms = want_positive_double(optarg, "-u");
552 break;
553 case 'U':
554 underrun_frac = want_positive_double(optarg, "-U");
555 if (underrun_frac > 1)
556 usage("-U: argument must be in the range (0, 1]");
557 break;
558 case 'X':
559 protocol = lock_protocol_for_name(optarg);
560 if (protocol < 0)
561 usage("Unknown locking protocol specified.");
562 break;
563 case 'L':
564 cs_length = want_positive_double(optarg, "-L");
565 break;
566 case 'Q':
567 resource_id = want_non_negative_int(optarg, "-Q");
568
569 break;
570 case 'Z':
571 check_fz = 1;
572 break;
573 case 'K':
574 pass_cs_len = 1;
575 break;
576 case 'v':
577 verbose = 1;
578 break;
579 case 'h':
580 usage(NULL);
581 break;
582 case 'i':
583 verbose = 1;
584 report_interrupts = 1;
585 break;
586 case 'a':
587 cycles_ms = want_non_negative_int(optarg, "-a");
588 if (!cycles_ms)
589 caliber_ms = 1;
590 break;
591 case ':':
592 usage("Argument missing.");
593 break;
594 case '?':
595 default:
596 usage("Bad argument.");
597 break;
598 }
599 }
600
601 init_gpu_context(dev_mem);
602
603 if (nr_of_pages) {
604 page_size = getpagesize();
605 rss = page_size * nr_of_pages;
606 base = mmap(NULL, rss, PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
607 if(base == MAP_FAILED) {
608 fprintf(stderr,"mmap failed: %s\n",strerror(errno));
609 exit(EXIT_FAILURE);
610 }
611
612 /* pin frames to prevent swapping */
613 ret = mlock(base,rss);
614 if (ret) {
615 fprintf(stderr,"mlock failed: %s\n",strerror(errno));
616 }
617
618 /* touch every allocated page */
619 for(idx = 0; idx < nr_of_pages; idx++)
620 memset(base + (idx * page_size), 1, page_size);
621 }
622
623 srand(getpid());
624
625 if (test_loop) {
626 if (cycles_ms > 0)
627 printf("Evaluating loop with %d cycles:\n", cycles_ms);
628
629 debug_delay_loop();
630 return 0;
631 }
632
633 if (caliber_ms) {
634 printf("In 1 ms %d loops.\n", calibrate_ms(1));
635 printf("In 10 ms %d loops.\n", calibrate_ms(10));
636 printf("In 100 ms %d loops.\n", calibrate_ms(100));
637 printf("In 1 s %d loops.\n", calibrate_ms(1000));
638 return 0;
639 }
640
641 if (background_loop) {
642 while (1) {
643 if (nr_of_pages)
644 loop_once_with_mem();
645 else
646 loop_once();
647 }
648 return 0;
649 }
650
651 if (argc - optind < 3 || (argc - optind < 2 && !cost_csv_file))
652 usage("Arguments missing.");
653
654 wcet_ms = want_positive_double(argv[optind + 0], "WCET");
655 period_ms = want_positive_double(argv[optind + 1], "PERIOD");
656
657 wcet = ms2ns(wcet_ms);
658 period = ms2ns(period_ms);
659 phase = ms2ns(offset_ms);
660 deadline = ms2ns(deadline_ms);
661 if (wcet <= 0)
662 usage("The worst-case execution time must be a "
663 "positive number.");
664 if (offset_ms < 0)
665 usage("The synchronous release delay must be a "
666 "non-negative number.");
667
668 if (period <= 0)
669 usage("The period must be a positive number.");
670 if (!cost_csv_file && wcet > period) {
671 usage("The worst-case execution time must not "
672 "exceed the period.");
673 }
674
675 if (cost_csv_file)
676 exec_times = csv_read_column(cost_csv_file, cost_column,
677 &num_jobs);
678
679 if (arrival_csv_file)
680 arrival_times = csv_read_column(arrival_csv_file,
681 arrival_column, &num_arrival_times);
682
683
684 if (argc - optind < 3 && cost_csv_file)
685 /* If duration is not given explicitly,
686 * take duration from file. */
687 duration = num_jobs * period_ms * 0.001;
688 else
689 duration = want_positive_double(argv[optind + 2], "DURATION");
690
691 if (underrun_frac) {
692 underrun_ms = underrun_frac * wcet_ms;
693 }
694
695 if (migrate) {
696 ret = be_migrate_to_domain(cluster);
697 if (ret < 0)
698 bail_out("could not migrate to target partition or cluster.");
699 }
700
701
702 init_rt_task_param(&param);
703 param.exec_cost = wcet;
704 param.period = period;
705 param.phase = phase;
706 param.relative_deadline = deadline;
707 param.priority = priority == LITMUS_NO_PRIORITY ? LITMUS_LOWEST_PRIORITY : priority;
708 param.cls = class;
709 param.budget_policy = (want_enforcement) ?
710 PRECISE_ENFORCEMENT : NO_ENFORCEMENT;
711 if (migrate) {
712 if (reservation >= 0)
713 param.cpu = reservation;
714 else
715 param.cpu = domain_to_first_cpu(cluster);
716 }
717 ret = set_rt_task_param(gettid(), &param);
718 if (ret < 0)
719 bail_out("could not setup rt task params");
720
721 if (create_reservation) {
722 struct reservation_config config;
723 memset(&config, 0, sizeof(config));
724 config.id = gettid();
725 config.cpu = domain_to_first_cpu(cluster);
726 config.priority = priority;
727 config.polling_params.budget = wcet;
728 config.polling_params.period = period;
729 config.polling_params.offset = phase;
730 config.polling_params.relative_deadline = deadline;
731 ret = reservation_create(SPORADIC_POLLING, &config);
732 if (ret < 0)
733 bail_out("failed to create reservation");
734 }
735
736 srand48(time(NULL));
737
738
739 init_litmus();
740
741 start = wctime();
742 ret = task_mode(LITMUS_RT_TASK);
743 if (ret != 0)
744 bail_out("could not become RT task");
745
746 cp = get_ctrl_page();
747
748 if (protocol >= 0) {
749 /* open reference to semaphore */
750 lock_od = litmus_open_lock(protocol, resource_id, lock_namespace, &cluster);
751 if (lock_od < 0) {
752 perror("litmus_open_lock");
753 usage("Could not open lock.");
754 }
755 }
756
757
758 if (wait) {
759 ret = wait_for_ts_release();
760 if (ret != 0)
761 bail_out("wait_for_ts_release()");
762 start = wctime();
763 }
764
765
766 next_release = cp ? cp->release : litmus_clock();
767
768 /* default: periodic releases */
769 if (!inter_arrival_min_ms)
770 inter_arrival_min_ms = period_ms;
771 if (!inter_arrival_max_ms)
772 inter_arrival_max_ms = period_ms;
773
774 if (inter_arrival_min_ms > inter_arrival_max_ms)
775 inter_arrival_max_ms = inter_arrival_min_ms;
776 inter_arrival_time = period;
777
778 /* main job loop */
779 cur_job = 0;
780 while (1) {
781 double acet; /* actual execution time */
782
783 if (sporadic) {
784 /* sporadic job activations, sleep until
785 * we receive an "event" (= any data) from
786 * our input event channel */
787 if (!wait_for_input(event_fd))
788 /* error out of something goes wrong */
789 break;
790 }
791
792 /* first, check if we have reached the end of the run */
793 if (wctime() > start + duration)
794 break;
795
796 if (verbose) {
797 get_job_no(&job_no);
798 fprintf(stderr, "rtspin/%d:%u @ %.4fms\n", gettid(),
799 job_no, (wctime() - start) * 1000);
800 if (cp) {
801 double deadline, current, release;
802 lt_t now = litmus_clock();
803 deadline = ns2s((double) cp->deadline);
804 current = ns2s((double) now);
805 release = ns2s((double) cp->release);
806 fprintf(stderr,
807 "\trelease: %" PRIu64 "ns (=%.2fs)\n",
808 (uint64_t) cp->release, release);
809 fprintf(stderr,
810 "\tdeadline: %" PRIu64 "ns (=%.2fs)\n",
811 (uint64_t) cp->deadline, deadline);
812 fprintf(stderr,
813 "\tcur time: %" PRIu64 "ns (=%.2fs)\n",
814 (uint64_t) now, current);
815 fprintf(stderr,
816 "\ttime until deadline: %.2fms\n",
817 (deadline - current) * 1000);
818 }
819 if (report_interrupts && cp) {
820 uint64_t irq = cp->irq_count;
821
822 fprintf(stderr,
823 "\ttotal interrupts: %" PRIu64
824 "; delta: %" PRIu64 "\n",
825 irq, irq - last_irq_count);
826 last_irq_count = irq;
827 }
828 }
829
830 /* figure out for how long this job should use the CPU */
831
832 if (cost_csv_file) {
833 /* read from provided CSV file and convert to seconds */
834 acet = exec_times[cur_job % num_jobs] * 0.001;
835 } else {
836 /* randomize and convert to seconds */
837 acet = (wcet_ms - drand48() * underrun_ms) * 0.001;
838 if (acet < 0)
839 acet = 0;
840 }
841 /* scale exec time */
842 acet *= scale;
843
844 if (verbose)
845 fprintf(stderr,
846 "\ttarget exec. time: %6.2fms (%.2f%% of WCET)\n",
847 acet * 1000,
848 (acet * 1000 / wcet_ms) * 100);
849
850 /* burn cycles */
851 job(acet, start + duration, lock_od, cs_length * 0.001, check_fz, pass_cs_len);
852
853 if (want_output) {
854 /* generate some output at end of job */
855 generate_output(output_fd);
856 }
857
858 /* wait for periodic job activation (unless sporadic) */
859 if (!sporadic) {
860 /* periodic job activations */
861 if (linux_sleep) {
862 /* Use vanilla Linux API. This looks to the
863 * active LITMUS^RT plugin like a
864 * self-suspension. */
865
866 inter_arrival_time =
867 choose_inter_arrival_time_ns(
868 arrival_times,
869 num_arrival_times,
870 cur_job,
871 inter_arrival_min_ms,
872 inter_arrival_max_ms);
873
874 next_release += inter_arrival_time;
875
876 if (verbose)
877 fprintf(stderr,
878 "\tclock_nanosleep() until %"
879 PRIu64 "ns (=%.2fs), "
880 "delta %" PRIu64 "ns (=%.2fms)\n",
881 (uint64_t) next_release,
882 ns2s((double) next_release),
883 (uint64_t) inter_arrival_time,
884 ns2ms((double) inter_arrival_time));
885
886 lt_sleep_until(next_release);
887
888 } else {
889 /* Use LITMUS^RT API: some plugins optimize
890 * this by not actually suspending the task. */
891 if (verbose && cp)
892 fprintf(stderr,
893 "\tsleep_next_period() until %"
894 PRIu64 "ns (=%.2fs)\n",
895 (uint64_t) (cp->release + period),
896 ns2s((double) (cp->release + period)));
897 sleep_next_period();
898 }
899 }
900 cur_job++;
901 }
902
903 ret = task_mode(BACKGROUND_TASK);
904 if (ret != 0)
905 bail_out("could not become regular task (huh?)");
906
907 if (cost_csv_file)
908 free(exec_times);
909
910 if (base != MAP_FAILED)
911 munlock(base, rss);
912
913 return 0;
914}
diff --git a/bin/rtspin.c b/bin/rtspin.c
index a47e3e7..a0deea8 100644
--- a/bin/rtspin.c
+++ b/bin/rtspin.c
@@ -331,7 +331,7 @@ static void job(double exec_time, double program_end, int lock_od, double cs_len
331 if (lock_res != 0) 331 if (lock_res != 0)
332 printf("Result of lock call: %d\n", lock_res); 332 printf("Result of lock call: %d\n", lock_res);
333 if (check_fz) 333 if (check_fz)
334 litmus_access_forbidden_zone_check(lock_od, s2ns(cs_length), s2ns(cs_length)); 334 litmus_access_forbidden_zone_check(lock_od, s2ns(1.1*cs_length), s2ns(1.1*cs_length));
335 loop_for(cs_length, program_end + 1); 335 loop_for(cs_length, program_end + 1);
336 if (check_fz) 336 if (check_fz)
337 { 337 {