diff options
| author | Bjoern Brandenburg <bbb@mpi-sws.org> | 2016-06-23 06:58:12 -0400 |
|---|---|---|
| committer | Bjoern Brandenburg <bbb@mpi-sws.org> | 2016-07-20 07:42:41 -0400 |
| commit | 9a8d7e447bbd1525f9f9f4660977072219bbc726 (patch) | |
| tree | ca4df9b22144b2d7e53c8a1c637dff6f8bb6629c | |
| parent | 98510c506a16b2a444eb6615ec8d78bc7c64e0aa (diff) | |
rtspin: Add sporadic task mode
While at it, also fix exec-times-from-CSV support.
| -rw-r--r-- | bin/rtspin.c | 259 |
1 files changed, 160 insertions, 99 deletions
diff --git a/bin/rtspin.c b/bin/rtspin.c index f14b549..d33e9b3 100644 --- a/bin/rtspin.c +++ b/bin/rtspin.c | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | #include <sys/time.h> | 1 | #include <sys/time.h> |
| 2 | 2 | ||
| 3 | #include <fcntl.h> | ||
| 3 | #include <stdio.h> | 4 | #include <stdio.h> |
| 4 | #include <stdlib.h> | 5 | #include <stdlib.h> |
| 5 | #include <unistd.h> | 6 | #include <unistd.h> |
| @@ -16,14 +17,20 @@ | |||
| 16 | 17 | ||
| 17 | const char *usage_msg = | 18 | const char *usage_msg = |
| 18 | "Usage: (1) rtspin OPTIONS WCET PERIOD DURATION\n" | 19 | "Usage: (1) rtspin OPTIONS WCET PERIOD DURATION\n" |
| 19 | " (2) rtspin OPTIONS -F FILE [-C COLUMN] WCET PERIOD\n" | 20 | " (2) rtspin -S [INPUT] WCET PERIOD DURATION\n" |
| 20 | " (3) rtspin -l\n" | 21 | " (3) rtspin OPTIONS -F FILE [-C COLUMN] WCET PERIOD [DURATION]\n" |
| 21 | " (4) rtspin -B\n" | 22 | " (4) rtspin -l\n" |
| 23 | " (5) rtspin -B -m FOOTPRINT\n" | ||
| 22 | "\n" | 24 | "\n" |
| 23 | "Modes: (1) run as periodic task with given WCET and PERIOD\n" | 25 | "Modes: (1) run as periodic task with given WCET and PERIOD\n" |
| 24 | " (2) as (1), but load per-job execution times from a CSV file\n" | 26 | " (2) run as sporadic task with given WCET and PERIOD,\n" |
| 25 | " (3) Run calibration loop (how accurately are target runtimes met?)\n" | 27 | " using INPUT as a file from which events are received\n" |
| 26 | " (4) Run background, non-real-time cache-thrashing loop (w/ -m).\n" | 28 | " by means of blocking reads (default: read from STDIN)\n" |
| 29 | " (3) as (1) or (2), but load per-job execution times from\n" | ||
| 30 | " a CSV file\n" | ||
| 31 | " (4) Run calibration loop (how accurately are target\n" | ||
| 32 | " runtimes met?)\n" | ||
| 33 | " (5) Run background, non-real-time cache-thrashing loop.\n" | ||
| 27 | "\n" | 34 | "\n" |
| 28 | "Required arguments:\n" | 35 | "Required arguments:\n" |
| 29 | " WCET, PERIOD reservation parameters (in ms)\n" | 36 | " WCET, PERIOD reservation parameters (in ms)\n" |
| @@ -49,7 +56,11 @@ const char *usage_msg = | |||
| 49 | " -w wait for synchronous release\n" | 56 | " -w wait for synchronous release\n" |
| 50 | "\n" | 57 | "\n" |
| 51 | " -F FILE load per-job execution times from CSV file\n" | 58 | " -F FILE load per-job execution times from CSV file\n" |
| 52 | " -C COLUMNS specify column to read per-job execution times from (default: 1)\n" | 59 | " -C COLUMN specify column to read per-job execution times from (default: 1)\n" |
| 60 | "\n" | ||
| 61 | " -S [FILE] read from FILE to trigger sporadic job releases\n" | ||
| 62 | " default w/o -S: periodic job releases\n" | ||
| 63 | " default if FILE is omitted: read from STDIN\n" | ||
| 53 | "\n" | 64 | "\n" |
| 54 | " -X PROTOCOL access a shared resource protected by a locking protocol\n" | 65 | " -X PROTOCOL access a shared resource protected by a locking protocol\n" |
| 55 | " -L CS-LENGTH simulate a critical section length of CS-LENGTH milliseconds\n" | 66 | " -L CS-LENGTH simulate a critical section length of CS-LENGTH milliseconds\n" |
| @@ -79,8 +90,7 @@ static void usage(char *error) { | |||
| 79 | */ | 90 | */ |
| 80 | static int skip_to_next_line(FILE *fstream) | 91 | static int skip_to_next_line(FILE *fstream) |
| 81 | { | 92 | { |
| 82 | int ch; | 93 | int ch; for (ch = fgetc(fstream); ch != EOF && ch != '\n'; ch = fgetc(fstream)); |
| 83 | for (ch = fgetc(fstream); ch != EOF && ch != '\n'; ch = fgetc(fstream)); | ||
| 84 | return ch; | 94 | return ch; |
| 85 | } | 95 | } |
| 86 | 96 | ||
| @@ -186,10 +196,14 @@ static int loop_for(double exec_time, double emergency_exit) | |||
| 186 | now = cputime(); | 196 | now = cputime(); |
| 187 | last_loop = now - loop_start; | 197 | last_loop = now - loop_start; |
| 188 | if (emergency_exit && wctime() > emergency_exit) { | 198 | if (emergency_exit && wctime() > emergency_exit) { |
| 189 | /* Oops --- this should only be possible if the execution time tracking | 199 | /* Oops --- this should only be possible if the |
| 190 | * is broken in the LITMUS^RT kernel. */ | 200 | * execution time tracking is broken in the LITMUS^RT |
| 191 | fprintf(stderr, "!!! rtspin/%d emergency exit!\n", getpid()); | 201 | * kernel or the user specified infeasible parameters. |
| 192 | fprintf(stderr, "Something is seriously wrong! Do not ignore this.\n"); | 202 | */ |
| 203 | fprintf(stderr, "!!! rtspin/%d emergency exit!\n", | ||
| 204 | getpid()); | ||
| 205 | fprintf(stderr, "Reached experiment timeout while " | ||
| 206 | "spinning.\n"); | ||
| 193 | break; | 207 | break; |
| 194 | } | 208 | } |
| 195 | } | 209 | } |
| @@ -216,37 +230,53 @@ static void debug_delay_loop(void) | |||
| 216 | } | 230 | } |
| 217 | } | 231 | } |
| 218 | 232 | ||
| 219 | static int job(double exec_time, double program_end, int lock_od, double cs_length) | 233 | static int wait_for_input(int event_fd) |
| 234 | { | ||
| 235 | /* We do a blocking read, accepting up to 4KiB of data. | ||
| 236 | * For simplicity, for now, if there's more than 4KiB of data, | ||
| 237 | * we treat this as multiple jobs. Note that this means that | ||
| 238 | * tardiness can result in coalesced jobs. Ideally, there should | ||
| 239 | * be some sort of configurable job boundary marker, but that's | ||
| 240 | * not supported in this basic version yet. Patches welcome. | ||
| 241 | */ | ||
| 242 | char buf[4096]; | ||
| 243 | size_t consumed; | ||
| 244 | |||
| 245 | consumed = read(event_fd, buf, sizeof(buf)); | ||
| 246 | |||
| 247 | if (consumed == 0) | ||
| 248 | fprintf(stderr, "reached end-of-file on input event stream\n"); | ||
| 249 | if (consumed < 0) | ||
| 250 | fprintf(stderr, "error reading input event stream (%m)\n"); | ||
| 251 | |||
| 252 | return consumed > 0; | ||
| 253 | } | ||
| 254 | |||
| 255 | static void job(double exec_time, double program_end, int lock_od, double cs_length) | ||
| 220 | { | 256 | { |
| 221 | double chunk1, chunk2; | 257 | double chunk1, chunk2; |
| 222 | 258 | ||
| 223 | if (wctime() > program_end) | 259 | if (lock_od >= 0) { |
| 224 | return 0; | 260 | /* simulate critical section somewhere in the middle */ |
| 225 | else { | 261 | chunk1 = drand48() * (exec_time - cs_length); |
| 226 | if (lock_od >= 0) { | 262 | chunk2 = exec_time - cs_length - chunk1; |
| 227 | /* simulate critical section somewhere in the middle */ | ||
| 228 | chunk1 = drand48() * (exec_time - cs_length); | ||
| 229 | chunk2 = exec_time - cs_length - chunk1; | ||
| 230 | 263 | ||
| 231 | /* non-critical section */ | 264 | /* non-critical section */ |
| 232 | loop_for(chunk1, program_end + 1); | 265 | loop_for(chunk1, program_end + 1); |
| 233 | 266 | ||
| 234 | /* critical section */ | 267 | /* critical section */ |
| 235 | litmus_lock(lock_od); | 268 | litmus_lock(lock_od); |
| 236 | loop_for(cs_length, program_end + 1); | 269 | loop_for(cs_length, program_end + 1); |
| 237 | litmus_unlock(lock_od); | 270 | litmus_unlock(lock_od); |
| 238 | 271 | ||
| 239 | /* non-critical section */ | 272 | /* non-critical section */ |
| 240 | loop_for(chunk2, program_end + 2); | 273 | loop_for(chunk2, program_end + 2); |
| 241 | } else { | 274 | } else { |
| 242 | loop_for(exec_time, program_end + 1); | 275 | loop_for(exec_time, program_end + 1); |
| 243 | } | ||
| 244 | sleep_next_period(); | ||
| 245 | return 1; | ||
| 246 | } | 276 | } |
| 247 | } | 277 | } |
| 248 | 278 | ||
| 249 | #define OPTSTR "p:c:wlveo:F:s:m:q:r:X:L:Q:iRu:Bhd:C:" | 279 | #define OPTSTR "p:c:wlveo:F:s:m:q:r:X:L:Q:iRu:Bhd:C:S::" |
| 250 | int main(int argc, char** argv) | 280 | int main(int argc, char** argv) |
| 251 | { | 281 | { |
| 252 | int ret; | 282 | int ret; |
| @@ -274,9 +304,12 @@ int main(int argc, char** argv) | |||
| 274 | int cur_job = 0, num_jobs = 0; | 304 | int cur_job = 0, num_jobs = 0; |
| 275 | struct rt_task param; | 305 | struct rt_task param; |
| 276 | 306 | ||
| 277 | int rss=0; | 307 | int rss = 0; |
| 278 | int idx; | 308 | int idx; |
| 279 | 309 | ||
| 310 | int sporadic = 0; /* trigger jobs sporadically? */ | ||
| 311 | int event_fd = -1; /* file descriptor for sporadic events */ | ||
| 312 | |||
| 280 | int verbose = 0; | 313 | int verbose = 0; |
| 281 | unsigned int job_no; | 314 | unsigned int job_no; |
| 282 | struct control_page* cp; | 315 | struct control_page* cp; |
| @@ -333,6 +366,19 @@ int main(int argc, char** argv) | |||
| 333 | case 'F': | 366 | case 'F': |
| 334 | file = optarg; | 367 | file = optarg; |
| 335 | break; | 368 | break; |
| 369 | case 'S': | ||
| 370 | sporadic = 1; | ||
| 371 | if (!optarg || strcmp(optarg, "-") == 0) | ||
| 372 | event_fd = STDIN_FILENO; | ||
| 373 | else | ||
| 374 | event_fd = open(optarg, O_RDONLY); | ||
| 375 | if (event_fd == -1) { | ||
| 376 | fprintf(stderr, "Could not open file '%s' " | ||
| 377 | "(%m)\n", optarg); | ||
| 378 | usage("-S requires a valid file path or '-' " | ||
| 379 | "for STDIN."); | ||
| 380 | } | ||
| 381 | break; | ||
| 336 | case 'm': | 382 | case 'm': |
| 337 | nr_of_pages = atoi(optarg); | 383 | nr_of_pages = atoi(optarg); |
| 338 | break; | 384 | break; |
| @@ -426,24 +472,8 @@ int main(int argc, char** argv) | |||
| 426 | return 0; | 472 | return 0; |
| 427 | } | 473 | } |
| 428 | 474 | ||
| 429 | if (file) { | 475 | if (argc - optind < 3 || (argc - optind < 2 && !file)) |
| 430 | get_exec_times(file, column, &num_jobs, &exec_times); | 476 | usage("Arguments missing."); |
| 431 | |||
| 432 | if (argc - optind < 2) | ||
| 433 | usage("Arguments missing."); | ||
| 434 | |||
| 435 | for (cur_job = 0; cur_job < num_jobs; ++cur_job) { | ||
| 436 | /* convert the execution time to seconds */ | ||
| 437 | duration += exec_times[cur_job] * 0.001; | ||
| 438 | } | < | |
