From: Vincent Guittot vincent.guittot@linaro.org
We can split the thread's behavior into several phases that will behave differently. This feature is useful to describe a behavior that is not fully periodic.
Signed-off-by: Vincent Guittot vincent.guittot@linaro.org Signed-off-by: Pi-Cheng Chen pi-cheng.chen@linaro.org --- src/rt-app.c | 112 +++++++++++++++++++++++++--------------- src/rt-app_args.c | 13 +++-- src/rt-app_parse_config.c | 127 ++++++++++++++++++++++++++++++---------------- src/rt-app_types.h | 15 ++++-- 4 files changed, 170 insertions(+), 97 deletions(-)
diff --git a/src/rt-app.c b/src/rt-app.c index 1c1c9fc..957f3fe 100644 --- a/src/rt-app.c +++ b/src/rt-app.c @@ -279,6 +279,7 @@ shutdown(int sig) void *thread_body(void *arg) { thread_data_t *data = (thread_data_t*) arg; + phase_data_t *pdata; struct sched_param param; struct timespec t_now, t_next; unsigned long t_start_usec; @@ -296,8 +297,7 @@ void *thread_body(void *arg) struct sched_attr attr; unsigned int flags = 0; #endif - int ret, i = 0; - int j; + int ret, i, j, loop;
/* set thread name */ ret = pthread_setname_np(pthread_self(), data->name); @@ -305,6 +305,9 @@ void *thread_body(void *arg) perror("pthread_setname_np thread name over 16 characters"); }
+ /* Get the 1st phase's data */ + pdata = &data->phases_data[0]; + /* set thread affinity */ if (data->cpuset != NULL) { @@ -337,13 +340,6 @@ void *thread_body(void *arg) exit(EXIT_FAILURE); }
- log_notice("[%d] starting thread with period: %lu, exec: %lu," - "deadline: %lu, priority: %d", - data->ind, - timespec_to_usec(&data->period), - timespec_to_usec(&data->min_et), - timespec_to_usec(&data->deadline), - data->sched_prio); break;
case other: @@ -351,13 +347,6 @@ void *thread_body(void *arg)
/* add priority setting */
- log_notice("[%d] starting thread with period: %lu, exec: %lu," - "deadline: %lu", - data->ind, - timespec_to_usec(&data->period), - timespec_to_usec(&data->min_et), - timespec_to_usec(&data->deadline)); - data->lock_pages = 0; /* forced off for SCHED_OTHER */ break;
@@ -398,10 +387,10 @@ void *thread_body(void *arg) attr.sched_flags = 0; attr.sched_policy = SCHED_DEADLINE; attr.sched_priority = 0; - attr.sched_runtime = timespec_to_nsec(&data->max_et) + - (timespec_to_nsec(&data->max_et) /100) * BUDGET_OVERP; - attr.sched_deadline = timespec_to_nsec(&data->deadline); - attr.sched_period = timespec_to_nsec(&data->period); + attr.sched_runtime = timespec_to_nsec(&pdata->max_et) + + (timespec_to_nsec(&pdata->max_et) /100) * BUDGET_OVERP; + attr.sched_deadline = timespec_to_nsec(&pdata->deadline); + attr.sched_period = timespec_to_nsec(&pdata->period); break; #endif
@@ -423,18 +412,37 @@ void *thread_body(void *arg) } }
+ log_notice("[%d] starting thread with period: %lu, exec: %lu," + "deadline: %lu", + data->ind, + timespec_to_usec(&pdata->period), + timespec_to_usec(&pdata->min_et), + timespec_to_usec(&pdata->deadline)); + /* if we know the duration we can calculate how many periods we will * do at most, and the log to memory, instead of logging to file. + * In case of several phase, we still use the logging file instead of + * memory. + * TODO: parse all the phase to compute the memory phase */ - timings = NULL; - if (data->duration > 0) { - my_duration_usec = (data->duration * 10e6) - - (data->wait_before_start * 1000); - nperiods = (int) ceil( my_duration_usec / - (double) timespec_to_usec(&data->period)); - timings = malloc ( nperiods * sizeof(timing_point_t)); + nperiods = 0; + if ((data->duration > 0) && (data->duration > data->wait_before_start) + && (data->nphases < 2)) { + my_duration_usec = (data->duration * 1000000) + - data->wait_before_start; + nperiods = (my_duration_usec + timespec_to_usec(&data->phases_data->period) - 1) + / timespec_to_usec(&data->phases_data->period) + 1; + } + + if ((pdata->loop > 0) && (pdata->loop < nperiods)) { + nperiods = data->loop + 1 ; }
+ if (nperiods) + timings = malloc(nperiods * sizeof(timing_point_t)); + else + timings = NULL; + fprintf(data->log_handler, "#idx\tperiod\tmin_et\tmax_et\trel_st\tstart" "\t\tend\t\tdeadline\tdur.\tslack" "\tBudget\tUsed Budget\n"); @@ -484,21 +492,24 @@ void *thread_body(void *arg)
clock_gettime(CLOCK_MONOTONIC, &t_now); t_next = t_now; - data->deadline = timespec_add(&t_now, &data->deadline); + pdata->deadline = timespec_add(&t_now, &pdata->deadline);
- while (continue_running && (i != data->loop)) { + i = j = loop = 0; + while (continue_running && (i != data->loop)) { struct timespec t_start, t_end, t_diff, t_slack;
if (opts.ftrace) - log_ftrace(ft_data.marker_fd, "[%d] begins loop %d", data->ind, i); + log_ftrace(ft_data.marker_fd, + "[%d] begins loop %d phase %d step %d", + data->ind, i, j, loop);
clock_gettime(CLOCK_MONOTONIC, &t_start); - run(data->ind, &data->min_et, &data->max_et, data->blockages, - data->nblockages); + run(data->ind, &pdata->min_et, &pdata->max_et, pdata->blockages, + pdata->nblockages); clock_gettime(CLOCK_MONOTONIC, &t_end);
t_diff = timespec_sub(&t_end, &t_start); - t_slack = timespec_sub(&data->deadline, &t_end); + t_slack = timespec_sub(&pdata->deadline, &t_end);
t_start_usec = timespec_to_usec(&t_start); if (timings) @@ -507,14 +518,14 @@ void *thread_body(void *arg) curr_timing = &tmp_timing;
curr_timing->ind = data->ind; - curr_timing->period = timespec_to_usec(&data->period); - curr_timing->min_et = timespec_to_usec(&data->min_et); - curr_timing->max_et = timespec_to_usec(&data->max_et); + curr_timing->period = timespec_to_usec(&pdata->period); + curr_timing->min_et = timespec_to_usec(&pdata->min_et); + curr_timing->max_et = timespec_to_usec(&pdata->max_et); curr_timing->rel_start_time = t_start_usec - timespec_to_usec(&data->main_app_start); curr_timing->abs_start_time = t_start_usec; curr_timing->end_time = timespec_to_usec(&t_end); - curr_timing->deadline = timespec_to_usec(&data->deadline); + curr_timing->deadline = timespec_to_usec(&pdata->deadline); curr_timing->duration = timespec_to_usec(&t_diff); curr_timing->slack = timespec_to_lusec(&t_slack);
@@ -536,12 +547,13 @@ void *thread_body(void *arg) if (!timings) log_timing(data->log_handler, curr_timing);
- t_next = timespec_add(&t_next, &data->period); - data->deadline = timespec_add(&data->deadline, &data->period); + t_next = timespec_add(&t_next, &pdata->period); + pdata->deadline = timespec_add(&pdata->deadline, &pdata->period);
if (opts.ftrace) - log_ftrace(ft_data.marker_fd, "[%d] end loop %d", - data->ind, i); + log_ftrace(ft_data.marker_fd, + "[%d] end loop %d phase %d step %d", + data->ind, i, j, loop);
if (curr_timing->slack < 0 && opts.die_on_dmiss) { log_critical("[%d] DEADLINE MISS !!!", data->ind); @@ -556,7 +568,23 @@ void *thread_body(void *arg) if (timespec_lower(&t_now, &t_next)) clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &t_next, NULL);
- i++; + loop++; + if (loop == pdata->loop) { + loop = 0; + + clock_gettime(CLOCK_MONOTONIC, &t_now); + t_next = t_now; + pdata->deadline = timespec_add(&t_now, &pdata->deadline); + + j++; + if (j == data->nphases) { + j = 0; + + i++; + } + + pdata = &data->phases_data[j]; + } }
exit_miss: diff --git a/src/rt-app_args.c b/src/rt-app_args.c index fa2c646..70783c8 100644 --- a/src/rt-app_args.c +++ b/src/rt-app_args.c @@ -97,7 +97,7 @@ parse_thread_args(char *arg, int idx, thread_data_t *tdata, policy_t def_policy) if (period <= 0 ) usage("Cannot set negative period.", EXIT_INV_COMMANDLINE); - tdata->period = usec_to_timespec(period); + tdata->phases_data->period = usec_to_timespec(period); i++; break;
@@ -110,8 +110,8 @@ parse_thread_args(char *arg, int idx, thread_data_t *tdata, policy_t def_policy) if (exec <= 0 ) usage("Cannot set negative exec time", EXIT_INV_COMMANDLINE); - tdata->min_et = usec_to_timespec(exec); - tdata->max_et = usec_to_timespec(exec); + tdata->phases_data->min_et = usec_to_timespec(exec); + tdata->phases_data->max_et = usec_to_timespec(exec); i++; break;
@@ -168,7 +168,7 @@ parse_thread_args(char *arg, int idx, thread_data_t *tdata, policy_t def_policy) if (dline <= 0 ) usage("Cannot set negative deadline", EXIT_INV_COMMANDLINE); - tdata->deadline = usec_to_timespec(dline); + tdata->phases_data->deadline = usec_to_timespec(dline); i++; break; } @@ -181,7 +181,7 @@ parse_thread_args(char *arg, int idx, thread_data_t *tdata, policy_t def_policy) }
if (dline == 0) - tdata->deadline = tdata->period; + tdata->phases_data->deadline = tdata->phases_data->period;
/* set cpu affinity mask */ if (tdata->cpuset_str) @@ -223,6 +223,7 @@ parse_command_line_options(int argc, char **argv, rtapp_options_t *opts) opts->pi_enabled = 0; opts->policy = other; opts->threads_data = malloc(sizeof(thread_data_t)); + opts->threads_data->phases_data = malloc(sizeof(phase_data_t)); #ifdef AQUOSA opts->fragment = 1; #endif @@ -297,6 +298,8 @@ parse_command_line_options(int argc, char **argv, rtapp_options_t *opts) opts->threads_data, (opts->nthreads+1) * \ sizeof(thread_data_t)); + opts->threads_data[opts->nthreads+1].phases_data = + malloc(sizeof(phase_data_t)); } parse_thread_args(optarg, opts->nthreads, &opts->threads_data[opts->nthreads], diff --git a/src/rt-app_parse_config.c b/src/rt-app_parse_config.c index dcc3010..b399916 100644 --- a/src/rt-app_parse_config.c +++ b/src/rt-app_parse_config.c @@ -306,7 +306,7 @@ serialize_acl(rtapp_resource_access_list_t **acl,
static void parse_thread_resources(const rtapp_options_t *opts, struct json_object *locks, - struct json_object *task_resources, thread_data_t *data) + struct json_object *task_resources, phase_data_t *data) { int i, j, usage_usec; struct json_object *res; @@ -386,43 +386,17 @@ parse_thread_resources(const rtapp_options_t *opts, struct json_object *locks, }
static void -parse_thread_data(char *name, struct json_object *obj, int idx, - thread_data_t *data, const rtapp_options_t *opts) +parse_thread_phase_data(struct json_object *obj, int idx, + phase_data_t *data, const rtapp_options_t *opts) { long exec, period, dline; - char *policy; - char def_policy[RTAPP_POLICY_DESCR_LENGTH]; - struct array_list *cpuset; - struct json_object *cpuset_obj, *cpu, *resources, *locks; - int i, cpu_idx; - - log_info(PFX "Parsing thread %s [%d]", name, idx); - - /* common and defaults */ - data->ind = idx; - data->name = strdup(name); - data->lock_pages = opts->lock_pages; - data->sched_prio = DEFAULT_THREAD_PRIORITY; - data->cpuset = NULL; - data->cpuset_str = NULL; + struct json_object *resources, *locks;
/* loop */ data->loop = get_int_value_from(obj, "loop", TRUE, -1);
- /* period */ - period = get_int_value_from(obj, "period", FALSE, 0); - if (period <= 0) { - log_critical(PIN2 "Cannot set negative period"); - exit(EXIT_INV_CONFIG); - } - data->period = usec_to_timespec(period); - /* exec time */ exec = get_int_value_from(obj, "exec", FALSE, 0); - if (exec > period) { - log_critical(PIN2 "Exec must be greather than period"); - exit(EXIT_INV_CONFIG); - } if (exec < 0) { log_critical(PIN2 "Cannot set negative exec time"); exit(EXIT_INV_CONFIG); @@ -430,6 +404,19 @@ parse_thread_data(char *name, struct json_object *obj, int idx, data->min_et = usec_to_timespec(exec); data->max_et = usec_to_timespec(exec);
+ /* period */ + period = get_int_value_from(obj, "period", TRUE, exec); + if (period <= 0) { + log_critical(PIN2 "Cannot set negative period"); + exit(EXIT_INV_CONFIG); + } + if (exec > period) { + log_critical(PIN2 "Period must be greater or equal than period"); + exit(EXIT_INV_CONFIG); + } + + data->period = usec_to_timespec(period); + /* deadline */ dline = get_int_value_from(obj, "deadline", TRUE, period); if (dline < exec) { @@ -442,6 +429,48 @@ parse_thread_data(char *name, struct json_object *obj, int idx, } data->deadline = usec_to_timespec(dline);
+ /* resources */ + resources = get_in_object(obj, "resources", TRUE); + locks = get_in_object(obj, "lock_order", TRUE); + if (locks) { + assure_type_is(locks, obj, "lock_order", json_type_array); + log_info(PIN "key: lock_order %s", json_object_to_json_string(locks)); + if (resources) { + assure_type_is(resources, obj, "resources", + json_type_object); + log_info(PIN "key: resources %s", + json_object_to_json_string(resources)); + } + parse_thread_resources(opts, locks, resources, data); + } else { + data->nblockages = 0; + } +} + +static void +parse_thread_data(char *name, struct json_object *obj, int idx, + thread_data_t *data, const rtapp_options_t *opts) +{ + long exec, period, dline; + char *policy; + char def_policy[RTAPP_POLICY_DESCR_LENGTH]; + struct array_list *cpuset; + struct json_object *cpuset_obj, *phases_obj, *cpu, *resources, *locks; + int i, cpu_idx; + + log_info(PFX "Parsing thread %s [%d]", name, idx); + + /* common and defaults */ + data->ind = idx; + data->name = strdup(name); + data->lock_pages = opts->lock_pages; + data->sched_prio = DEFAULT_THREAD_PRIORITY; + data->cpuset = NULL; + data->cpuset_str = NULL; + + /* loop */ + data->loop = get_int_value_from(obj, "loop", TRUE, -1); + /* policy */ policy_to_string(opts->policy, def_policy); policy = get_string_value_from(obj, "policy", TRUE, def_policy); @@ -476,21 +505,31 @@ parse_thread_data(char *name, struct json_object *obj, int idx, } log_info(PIN "key: cpus %s", data->cpuset_str);
- /* resources */ - resources = get_in_object(obj, "resources", TRUE); - locks = get_in_object(obj, "lock_order", TRUE); - if (locks) { - assure_type_is(locks, obj, "lock_order", json_type_array); - log_info(PIN "key: lock_order %s", json_object_to_json_string(locks)); - if (resources) { - assure_type_is(resources, obj, "resources", - json_type_object); - log_info(PIN "key: resources %s", - json_object_to_json_string(resources)); + /* phases */ + phases_obj = get_in_object(obj, "phases", TRUE); + if (phases_obj) { + /* used in the foreach macro */ + struct lh_entry *entry; char *key; struct json_object *val; int idx; + + assure_type_is(phases_obj, obj, "phases", json_type_object); + + log_info(PIN "Parsing phases section"); + data->nphases = 0; + foreach(phases_obj, entry, key, val, idx) { + data->nphases++; } - parse_thread_resources(opts, locks, resources, data); + log_info(PIN "Found %d phases", data->nphases); + data->phases_data = malloc(sizeof(phase_data_t) * data->nphases); + foreach(phases_obj, entry, key, val, idx) { + log_info(PIN "Parsing phase %s", key); + parse_thread_phase_data(val, idx, &data->phases_data[idx], opts); + } + } else { + data->nphases = 1; + data->phases_data = malloc(sizeof(phase_data_t) * data->nphases); + data->loop = 1; + parse_thread_phase_data(obj, 0, data->phases_data, opts); } - }
static void @@ -591,8 +630,6 @@ get_opts_from_json_object(struct json_object *root, rtapp_options_t *opts) parse_resources(resources, opts); json_object_put(resources); parse_tasks(tasks, opts); - json_object_put(tasks); - }
void diff --git a/src/rt-app_types.h b/src/rt-app_types.h index eb7cb95..b8988f7 100644 --- a/src/rt-app_types.h +++ b/src/rt-app_types.h @@ -90,6 +90,14 @@ typedef struct _rtapp_tasks_resource_list_t { struct _rtapp_resource_access_list_t *acl; } rtapp_tasks_resource_list_t;
+typedef struct _phase_data_t { + struct timespec min_et, max_et; + struct timespec period, deadline; + int loop, sleep; + rtapp_tasks_resource_list_t *blockages; + int nblockages; +} phase_data_t; + typedef struct _thread_data_t { int ind; char *name; @@ -98,19 +106,16 @@ typedef struct _thread_data_t { cpu_set_t *cpuset; char *cpuset_str; unsigned long wait_before_start; - struct timespec min_et, max_et; - struct timespec period, deadline; struct timespec main_app_start; int loop; + int nphases; + phase_data_t *phases_data;
FILE *log_handler; policy_t sched_policy; char sched_policy_descr[RTAPP_POLICY_DESCR_LENGTH]; int sched_prio;
- rtapp_tasks_resource_list_t *blockages; - int nblockages; - #ifdef AQUOSA int fragment; int sid;