diff options
| author | ztong <ztong@cs.unc.edu> | 2021-06-12 17:08:01 -0400 |
|---|---|---|
| committer | ztong <ztong@cs.unc.edu> | 2021-06-12 17:08:01 -0400 |
| commit | bbaa2b43b6efdd175b26bced3b0d95315b4dcdc1 (patch) | |
| tree | 69bb17150df6ffc34727df0c5dbb382db8345dbf | |
| parent | cd4c9a86e447690fe1b66545b9c141432f017237 (diff) | |
Added GPU spinning in critical sections for rtspinecrts21
| -rw-r--r-- | Makefile | 14 | ||||
| -rw-r--r-- | bin/cuda_loop.cu | 29 | ||||
| -rw-r--r-- | bin/gpu-rtspin.c | 914 | ||||
| -rw-r--r-- | bin/rtspin.c | 2 |
4 files changed, 956 insertions, 3 deletions
| @@ -19,7 +19,7 @@ LITMUS_KERNEL ?= ../litmus-rt | |||
| 19 | # Internal configuration. | 19 | # Internal configuration. |
| 20 | 20 | ||
| 21 | # compiler flags | 21 | # compiler flags |
| 22 | flags-debug = -O2 -Wall -Werror -g -Wdeclaration-after-statement | 22 | flags-debug = -O2 -Wall -Wno-error -g -Wdeclaration-after-statement |
| 23 | flags-api = -D_XOPEN_SOURCE=600 -D_GNU_SOURCE | 23 | flags-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 |
| 39 | LIBLITMUS ?= . | 39 | LIBLITMUS ?= . |
| 40 | CUDA ?= /usr/local/cuda/lib64 | ||
| 40 | 41 | ||
| 41 | # where to find header files | 42 | # where to find header files |
| 42 | headers = -I${LIBLITMUS}/include -I${LIBLITMUS}/arch/${include-${ARCH}}/include | 43 | headers = -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 |
| 52 | liblitmus-flags = -L${LIBLITMUS} -llitmus | 53 | liblitmus-flags = -L${LIBLITMUS} -llitmus |
| 54 | cuda-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 | ||
| 68 | all = lib ${rt-apps} | 70 | all = lib gpu-rtspin ${rt-apps} |
| 69 | rt-apps = cycles base_task rt_launch rtspin release_ts measure_syscall \ | 71 | rt-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 | ||
| 116 | clean: | 118 | clean: |
| 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 | |||
| 218 | obj-rtspin = rtspin.o common.o | 221 | obj-rtspin = rtspin.o common.o |
| 219 | lib-rtspin = -lrt | 222 | lib-rtspin = -lrt |
| 220 | 223 | ||
| 224 | obj-gpu-rtspin = gpu-rtspin.o common.o cuda_loop.o | ||
| 225 | |||
| 221 | obj-uncache = uncache.o | 226 | obj-uncache = uncache.o |
| 222 | lib-uncache = -lrt | 227 | lib-uncache = -lrt |
| 223 | 228 | ||
| @@ -228,6 +233,8 @@ lib-measure_syscall = -lm | |||
| 228 | 233 | ||
| 229 | obj-resctl = resctl.o | 234 | obj-resctl = resctl.o |
| 230 | 235 | ||
| 236 | cuda_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 | ||
| 246 | gpu-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 | |||
| 18 | extern "C" void gpu_loop_start(int cs_length) { | ||
| 19 | cuda_loop<<<1, 1>>>(0.95 * cs_length); | ||
| 20 | } | ||
| 21 | |||
| 22 | extern "C" void wait_for_gpu_loop_end(void) { | ||
| 23 | cudaDeviceSynchronize(); | ||
| 24 | } | ||
| 25 | |||
| 26 | extern "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 | |||
| 19 | const 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 | |||
| 97 | static 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 | |||
| 108 | void default_sig_handler(int sig) { | ||
| 109 | if (sig == SIGSYS) | ||
| 110 | return; | ||
| 111 | } | ||
| 112 | |||
| 113 | #define NUMS 4096 | ||
| 114 | static int num[NUMS]; | ||
| 115 | static char* progname; | ||
| 116 | |||
| 117 | static int nr_of_pages = 0; | ||
| 118 | static int page_size; | ||
| 119 | static void *base = NULL; | ||
| 120 | |||
| 121 | static int cycles_ms = 0; | ||
| 122 | |||
| 123 | extern void gpu_loop_start(int cs_length); | ||
| 124 | extern void wait_for_gpu_loop_end(void); | ||
| 125 | extern void init_gpu_context(int* dev_mem); | ||
| 126 | |||
| 127 | static 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 | |||
| 142 | static 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 | |||
| 165 | static 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 | |||
| 203 | static 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 | |||
| 221 | static char input_buf[4096] = "<no input>"; | ||
| 222 | |||
| 223 | static 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 | |||
| 268 | static 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 | |||
| 298 | static 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 | |||
| 313 | static 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 | |||
| 357 | static 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 | |||
| 373 | int 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(¶m); | ||
| 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(), ¶m); | ||
| 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 | { |
