Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Let user specify the start-time of the program #496

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions core/reactor.c
Original file line number Diff line number Diff line change
Expand Up @@ -328,8 +328,9 @@ int lf_reactor_c_main(int argc, const char* argv[]) {

LF_PRINT_DEBUG("Initializing.");
initialize_global();
// Set start time
start_time = lf_time_physical();
// Set the start time of the program (if it is not set from the command line). Possibly wait for
// it to arrive also.
_lf_set_and_wait_for_start_time();
#ifndef FEDERATED
lf_tracing_set_start_time(start_time);
#endif
Expand Down
106 changes: 76 additions & 30 deletions core/reactor_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@
// Global variable defined in tag.c:
extern instant_t start_time;

// Whether the start time of the program is decided by the user via a command line argument.
bool start_time_specified = false;

#if !defined NDEBUG
// Global variable defined in lf_token.c:
extern int _lf_count_payload_allocations;
Expand Down Expand Up @@ -882,6 +885,12 @@ void usage(int argc, const char* argv[]) {
printf(" Executed in <n> threads if possible (optional feature).\n\n");
printf(" -i, --id <n>\n");
printf(" The ID of the federation that this reactor will join.\n\n");
printf(" -s, --start-time <time-point> <units> \n");
printf(" The logical start time of the program, expressed as an absolute time point\n");
printf(" which is the duration since the epoch of the underlying system clock.\n");
printf(" The units are nsec, usec, msec, sec, minute, hour, day, week or the plurals of those.\n");
printf(" On linux, to compute a start time of 2 minutes into the future, expressed in seconds, do:\n");
printf(" `date -d \"2 minutes\" +%%s`.\n\n");
#ifdef FEDERATED
printf(" -r, --rti <n>\n");
printf(" The address of the RTI, which can be in the form of user@host:port or ip:port.\n\n");
Expand All @@ -901,6 +910,43 @@ void usage(int argc, const char* argv[]) {
int default_argc = 0;
const char** default_argv = NULL;

interval_t duration_string_to_interval(const char* time_spec, const char* units) {
interval_t duration = 0LL;

#if defined(PLATFORM_ARDUINO)
duration = atol(time_spec);
#else
duration = atoll(time_spec);
#endif

// A parse error returns 0LL, so check to see whether that is what is meant.
if (duration == 0LL && strncmp(time_spec, "0", 1) != 0) {
// Parse error.
return -1;
}
if (strncmp(units, "sec", 3) == 0) {
duration = SEC(duration);
} else if (strncmp(units, "msec", 4) == 0) {
duration = MSEC(duration);
} else if (strncmp(units, "usec", 4) == 0) {
duration = USEC(duration);
} else if (strncmp(units, "nsec", 4) == 0) {
duration = NSEC(duration);
} else if (strncmp(units, "min", 3) == 0) {
duration = MINUTE(duration);
} else if (strncmp(units, "hour", 4) == 0) {
duration = HOUR(duration);
} else if (strncmp(units, "day", 3) == 0) {
duration = DAY(duration);
} else if (strncmp(units, "week", 4) == 0) {
duration = WEEK(duration);
} else {
// Invalid units.
return -1;
}
return duration;
}

/**
* Process the command-line arguments. If the command line arguments are not
* understood, then print a usage message and return 0. Otherwise, return 1.
Expand Down Expand Up @@ -934,42 +980,30 @@ int process_args(int argc, const char* argv[]) {
}
const char* time_spec = argv[i++];
const char* units = argv[i++];

#if defined(PLATFORM_ARDUINO)
duration = atol(time_spec);
#else
duration = atoll(time_spec);
#endif

// A parse error returns 0LL, so check to see whether that is what is meant.
if (duration == 0LL && strncmp(time_spec, "0", 1) != 0) {
// Parse error.
lf_print_error("Invalid time value: %s", time_spec);
duration = duration_string_to_interval(time_spec, units);
if (duration < 0) {
lf_print_error("Invalid time units for --timeout.");
usage(argc, argv);
return 0;
}
if (strncmp(units, "sec", 3) == 0) {
duration = SEC(duration);
} else if (strncmp(units, "msec", 4) == 0) {
duration = MSEC(duration);
} else if (strncmp(units, "usec", 4) == 0) {
duration = USEC(duration);
} else if (strncmp(units, "nsec", 4) == 0) {
duration = NSEC(duration);
} else if (strncmp(units, "min", 3) == 0) {
duration = MINUTE(duration);
} else if (strncmp(units, "hour", 4) == 0) {
duration = HOUR(duration);
} else if (strncmp(units, "day", 3) == 0) {
duration = DAY(duration);
} else if (strncmp(units, "week", 4) == 0) {
duration = WEEK(duration);
} else {
// Invalid units.
lf_print_error("Invalid time units: %s", units);
} else if (strcmp(arg, "-s") == 0 || strcmp(arg, "--start-time") == 0) {
if (argc < i + 2) {
lf_print_error("--start-time needs time and units.");
usage(argc, argv);
return 0;
}

const char* time_spec = argv[i++];
const char* units = argv[i++];
start_time = duration_string_to_interval(time_spec, units);
if (start_time < 0) {
lf_print_error("Invalid time units for --start-time.");
usage(argc, argv);
return 0;
} else {
start_time_specified = true;
}

} else if (strcmp(arg, "-k") == 0 || strcmp(arg, "--keepalive") == 0) {
if (argc < i + 1) {
lf_print_error("--keepalive needs a boolean.");
Expand Down Expand Up @@ -1227,3 +1261,15 @@ index_t lf_combine_deadline_and_level(interval_t deadline, int level) {
else
return (deadline << 16) | level;
}

void _lf_set_and_wait_for_start_time() {
if (!start_time_specified) {
start_time = lf_time_physical();
} else {
instant_t now = lf_time_physical();
if (!fast && now < start_time) {
lf_print("Sleeping " PRINTF_TIME " ns until specified start time", start_time - now);
lf_sleep(start_time - now);
}
}
}
4 changes: 3 additions & 1 deletion core/threaded/reactor_threaded.c
Original file line number Diff line number Diff line change
Expand Up @@ -1017,7 +1017,9 @@ int lf_reactor_c_main(int argc, const char* argv[]) {

// Initialize the clock through the platform API. No reading of physical time before this.
_lf_initialize_clock();
start_time = lf_time_physical();
// Set the start time of the program (if it is not set from the command line). Possibly wait for
// it to arrive also.
_lf_set_and_wait_for_start_time();
#ifndef FEDERATED
lf_tracing_set_start_time(start_time);
#endif
Expand Down
6 changes: 6 additions & 0 deletions include/core/reactor_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ extern unsigned int _lf_number_of_workers;
extern int default_argc;
extern const char** default_argv;
extern instant_t duration;
extern bool start_time_specified;
extern bool fast;
extern bool keepalive_specified;

Expand All @@ -65,6 +66,11 @@ extern struct allocation_record_t* _lf_reactors_to_free;

////////////////////// Functions //////////////////////

/**
* @brief Set the start time of the program and possibly wait for it to arrive.
*/
void _lf_set_and_wait_for_start_time();

/**
* @brief Combine a deadline and a level into a single index for sorting in the reaction queue.
*
Expand Down
Loading