diff options
author | Bjoern Brandenburg <bbb@mpi-sws.org> | 2017-07-28 11:02:37 -0400 |
---|---|---|
committer | Bjoern Brandenburg <bbb@mpi-sws.org> | 2017-07-28 11:02:37 -0400 |
commit | 914897a4bc19ddf24ec85e5f4306431b1f07cbf2 (patch) | |
tree | da185d716e7bf8f84250fd81fd504f3659ec7427 | |
parent | 77ce0c782ba2c921e00e028760ac5e26cfb3d9da (diff) |
rtspin: add -O option to generate output at end of job
The combination of -S and -O can be used to generate simple event
chains. For example, under the GSN-EDF plugin, the following command
creates a simple two-stage pipeline that is triggered about once a
second for seven seconds.
(for x in 1 2 3 4 5 6 7; do echo $x; sleep 1; done) |
rtspin -v 10 1000 10 -O -S |
rtspin -v 10 100 10 -O -S > /tmp/foo.txt
The output is logged to /tmp/foo.txt.
-rw-r--r-- | bin/rtspin.c | 57 |
1 files changed, 54 insertions, 3 deletions
diff --git a/bin/rtspin.c b/bin/rtspin.c index 49542af..d7cb7b0 100644 --- a/bin/rtspin.c +++ b/bin/rtspin.c | |||
@@ -62,6 +62,10 @@ const char *usage_msg = | |||
62 | " -S[FILE] read from FILE to trigger sporadic job releases\n" | 62 | " -S[FILE] read from FILE to trigger sporadic job releases\n" |
63 | " default w/o -S: periodic job releases\n" | 63 | " default w/o -S: periodic job releases\n" |
64 | " default if FILE is omitted: read from STDIN\n" | 64 | " default if FILE is omitted: read from STDIN\n" |
65 | " -O[FILE] write to FILE when job completes (this is useful with -S\n" | ||
66 | " to create precedence constraints/event chains)\n" | ||
67 | " default w/o -O: no output\n" | ||
68 | " default if FILE is omitted: write to STDOUT\n" | ||
65 | "\n" | 69 | "\n" |
66 | " -T use clock_nanosleep() instead of sleep_next_period()\n" | 70 | " -T use clock_nanosleep() instead of sleep_next_period()\n" |
67 | " -D MAX-DELTA set maximum inter-arrival delay to MAX-DELTA [default: period]\n" | 71 | " -D MAX-DELTA set maximum inter-arrival delay to MAX-DELTA [default: period]\n" |
@@ -251,6 +255,8 @@ static void debug_delay_loop(void) | |||
251 | } | 255 | } |
252 | } | 256 | } |
253 | 257 | ||
258 | static char input_buf[4096] = "<no input>"; | ||
259 | |||
254 | static int wait_for_input(int event_fd) | 260 | static int wait_for_input(int event_fd) |
255 | { | 261 | { |
256 | /* We do a blocking read, accepting up to 4KiB of data. | 262 | /* We do a blocking read, accepting up to 4KiB of data. |
@@ -260,19 +266,42 @@ static int wait_for_input(int event_fd) | |||
260 | * be some sort of configurable job boundary marker, but that's | 266 | * be some sort of configurable job boundary marker, but that's |
261 | * not supported in this basic version yet. Patches welcome. | 267 | * not supported in this basic version yet. Patches welcome. |
262 | */ | 268 | */ |
263 | char buf[4096]; | ||
264 | size_t consumed; | 269 | size_t consumed; |
265 | 270 | ||
266 | consumed = read(event_fd, buf, sizeof(buf)); | 271 | consumed = read(event_fd, input_buf, sizeof(input_buf) - 1); |
267 | 272 | ||
268 | if (consumed == 0) | 273 | if (consumed == 0) |
269 | fprintf(stderr, "reached end-of-file on input event stream\n"); | 274 | fprintf(stderr, "reached end-of-file on input event stream\n"); |
270 | if (consumed < 0) | 275 | if (consumed < 0) |
271 | fprintf(stderr, "error reading input event stream (%m)\n"); | 276 | fprintf(stderr, "error reading input event stream (%m)\n"); |
272 | 277 | ||
278 | if (consumed > 0) { | ||
279 | /* zero-terminate string buffer */ | ||
280 | input_buf[consumed] = '\0'; | ||
281 | /* check if we can remove a trailing newline */ | ||
282 | if (consumed > 1 && input_buf[consumed - 1] == '\n') { | ||
283 | input_buf[consumed - 1] = '\0'; | ||
284 | } | ||
285 | } | ||
286 | |||
273 | return consumed > 0; | 287 | return consumed > 0; |
274 | } | 288 | } |
275 | 289 | ||
290 | static int generate_output(int output_fd) | ||
291 | { | ||
292 | char buf[4096]; | ||
293 | size_t len, written; | ||
294 | unsigned int job_no; | ||
295 | |||
296 | get_job_no(&job_no); | ||
297 | len = snprintf(buf, 4095, "(rtspin/%d:%u completed: %s @ %" PRIu64 "ns)\n", | ||
298 | getpid(), job_no, input_buf, (uint64_t) litmus_clock()); | ||
299 | |||
300 | written = write(output_fd, buf, len); | ||
301 | |||
302 | return written == len; | ||
303 | } | ||
304 | |||
276 | static void job(double exec_time, double program_end, int lock_od, double cs_length) | 305 | static void job(double exec_time, double program_end, int lock_od, double cs_length) |
277 | { | 306 | { |
278 | double chunk1, chunk2; | 307 | double chunk1, chunk2; |
@@ -297,7 +326,7 @@ static void job(double exec_time, double program_end, int lock_od, double cs_len | |||
297 | } | 326 | } |
298 | } | 327 | } |
299 | 328 | ||
300 | #define OPTSTR "p:c:wlveo:F:s:m:q:r:X:L:Q:iRu:U:Bhd:C:S::TD:E:" | 329 | #define OPTSTR "p:c:wlveo:F:s:m:q:r:X:L:Q:iRu:U:Bhd:C:S::O::TD:E:" |
301 | 330 | ||
302 | int main(int argc, char** argv) | 331 | int main(int argc, char** argv) |
303 | { | 332 | { |
@@ -334,6 +363,8 @@ int main(int argc, char** argv) | |||
334 | 363 | ||
335 | int sporadic = 0; /* trigger jobs sporadically? */ | 364 | int sporadic = 0; /* trigger jobs sporadically? */ |
336 | int event_fd = -1; /* file descriptor for sporadic events */ | 365 | int event_fd = -1; /* file descriptor for sporadic events */ |
366 | int want_output = 0; /* create output at end of job? */ | ||
367 | int output_fd = -1; /* file descriptor for output */ | ||
337 | 368 | ||
338 | int linux_sleep = 0; /* use Linux API for periodic activations? */ | 369 | int linux_sleep = 0; /* use Linux API for periodic activations? */ |
339 | lt_t next_release; | 370 | lt_t next_release; |
@@ -407,6 +438,21 @@ int main(int argc, char** argv) | |||
407 | "for STDIN."); | 438 | "for STDIN."); |
408 | } | 439 | } |
409 | break; | 440 | break; |
441 | |||
442 | case 'O': | ||
443 | want_output = 1; | ||
444 | if (!optarg || strcmp(optarg, "-") == 0) | ||
445 | output_fd = STDOUT_FILENO; | ||
446 | else | ||
447 | output_fd = open(optarg, O_WRONLY | O_APPEND); | ||
448 | if (output_fd == -1) { | ||
449 | fprintf(stderr, "Could not open file '%s' " | ||
450 | "(%m)\n", optarg); | ||
451 | usage("-O requires a valid file path or '-' " | ||
452 | "for STDOUT."); | ||
453 | } | ||
454 | break; | ||
455 | |||
410 | case 'T': | 456 | case 'T': |
411 | linux_sleep = 1; | 457 | linux_sleep = 1; |
412 | break; | 458 | break; |
@@ -708,6 +754,11 @@ int main(int argc, char** argv) | |||
708 | /* burn cycles */ | 754 | /* burn cycles */ |
709 | job(acet, start + duration, lock_od, cs_length * 0.001); | 755 | job(acet, start + duration, lock_od, cs_length * 0.001); |
710 | 756 | ||
757 | if (want_output) { | ||
758 | /* generate some output at end of job */ | ||
759 | generate_output(output_fd); | ||
760 | } | ||
761 | |||
711 | /* wait for periodic job activation (unless sporadic) */ | 762 | /* wait for periodic job activation (unless sporadic) */ |
712 | if (!sporadic) { | 763 | if (!sporadic) { |
713 | /* periodic job activations */ | 764 | /* periodic job activations */ |