These series includes fixes/changes that have been done. These patches mainly fixed some typos or moves code but should not change the behavior of rt-app.
Those patches are also found in the branch: https://git.linaro.org/people/picheng.chen/rt-app.git fix
Chris Muller (1): Update thread name
Ivan T. Ivanov (1): fixup json-c dependencies
Vincent Guittot (12): Minor clean up fix deadline print format consolidate trace and debug point update .gitignore fix inconsistency in delay unit fix cpu affinity string info deadline: set deadline field to deadline parameter reorder the start sequence of threads cleanup of doc directory remove useless json_object_put remove conditional compilation of json Remove useless --with-json rt-app: remove use of deprecated json interface
.gitignore | 8 ++ README.in | 7 +- autogen.sh | 2 +- configure.ac | 17 ++-- doc/taskset.yml | 53 ----------- src/Makefile.am | 8 +- src/rt-app.c | 227 ++++++++++++++++++++++++++-------------------- src/rt-app_args.c | 77 ++++++++-------- src/rt-app_parse_config.c | 51 +++++++---- src/rt-app_parse_config.h | 2 +- src/rt-app_utils.c | 3 + src/rt-app_utils.h | 4 +- 12 files changed, 228 insertions(+), 231 deletions(-) delete mode 100644 doc/taskset.yml
From: Vincent Guittot vincent.guittot@linaro.org
remove useless space align tab remove useless comment
Signed-off-by: Vincent Guittot vincent.guittot@linaro.org Signed-off-by: Kevin Hilman khilman@linaro.org --- src/rt-app.c | 191 +++++++++++++++++++++++++--------------------- src/rt-app_args.c | 77 ++++++++++--------- src/rt-app_parse_config.c | 31 ++++++-- src/rt-app_utils.c | 3 + src/rt-app_utils.h | 4 +- 5 files changed, 174 insertions(+), 132 deletions(-)
diff --git a/src/rt-app.c b/src/rt-app.c index 3c293e7..4629980 100644 --- a/src/rt-app.c +++ b/src/rt-app.c @@ -27,17 +27,13 @@ static volatile int continue_running; static pthread_t *threads; static int nthreads; rtapp_options_t opts; + static ftrace_data_t ft_data = { - .debugfs = "/debug", + .debugfs = "/sys/kernel/debug", .trace_fd = -1, .marker_fd = -1, };
-static inline unsigned int max_run(int min, int max) -{ - return min + (((double) rand()) / RAND_MAX) * (max - min); -} - static inline busywait(struct timespec *to) { struct timespec t_step; @@ -52,27 +48,29 @@ void run(int ind, struct timespec *min, struct timespec *max, rtapp_tasks_resource_list_t *blockages, int nblockages) { int i; - //int m = max_run(timespec_to_msec(min), timespec_to_msec(max)); - //struct timespec t_start, t_step, t_exec = msec_to_timespec(m); struct timespec t_start, now, t_exec, t_totexec = *max; rtapp_resource_access_list_t *lock, *last;
- /* get the start time */ + /* Get the start time */ clock_gettime(CLOCK_THREAD_CPUTIME_ID, &t_start);
for (i = 0; i < nblockages; i++) { + + /* Lock resources */ lock = blockages[i].acl; while (lock != NULL) { log_debug("[%d] locking %d", ind, lock->res->index); if (opts.ftrace) log_ftrace(ft_data.marker_fd, - "[%d] locking %d", - ind, lock->res->index); + "[%d] locking %d", + ind, lock->res->index); pthread_mutex_lock(&lock->res->mtx); last = lock; lock = lock->next; } + + /* Busy wait */ clock_gettime(CLOCK_THREAD_CPUTIME_ID, &now); t_exec = timespec_add(&now, &blockages[i].usage); log_debug("[%d] busywait for %lu", ind, timespec_to_usec(&blockages[i].usage)); @@ -81,19 +79,21 @@ void run(int ind, struct timespec *min, struct timespec *max, "[%d] busywait for %d", ind, timespec_to_usec(&blockages[i].usage)); busywait(&t_exec); + + /* Unlock resources */ lock = last; while (lock != NULL) { log_debug("[%d] unlocking %d", ind, lock->res->index); if (opts.ftrace) log_ftrace(ft_data.marker_fd, - "[%d] unlocking %d", - ind, lock->res->index); + "[%d] unlocking %d", + ind, lock->res->index); pthread_mutex_unlock(&lock->res->mtx); lock = lock->prev; } }
- /* compute finish time for CPUTIME_ID clock */ + /* Compute finish time for CPUTIME_ID clock */ t_exec = timespec_add(&t_start, &t_totexec); busywait(&t_exec); } @@ -108,6 +108,7 @@ shutdown(int sig) { pthread_join(threads[i], NULL); } + if (opts.ftrace) { log_notice("stopping ftrace"); log_ftrace(ft_data.marker_fd, "main ends\n"); @@ -115,6 +116,7 @@ shutdown(int sig) close(ft_data.trace_fd); close(ft_data.marker_fd); } + exit(EXIT_SUCCESS); }
@@ -122,7 +124,7 @@ void *thread_body(void *arg) { thread_data_t *data = (thread_data_t*) arg; struct sched_param param; - struct timespec t, t_next; + struct timespec t_now, t_next; unsigned long t_start_usec; unsigned long my_duration_usec; int nperiods; @@ -162,11 +164,11 @@ void *thread_body(void *arg) case rr: case fifo: fprintf(data->log_handler, "# Policy : %s\n", - (data->sched_policy == rr ? "SCHED_RR" : "SCHED_FIFO")); + (data->sched_policy == rr ? "SCHED_RR" : "SCHED_FIFO")); param.sched_priority = data->sched_prio; ret = pthread_setschedparam(pthread_self(), - data->sched_policy, - ¶m); + data->sched_policy, + ¶m); if (ret != 0) { errno = ret; perror("pthread_setschedparam"); @@ -174,49 +176,56 @@ void *thread_body(void *arg) }
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 - ); + "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: fprintf(data->log_handler, "# Policy : SCHED_OTHER\n"); + + /* 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) - ); + "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; + #ifdef AQUOSA case aquosa: fprintf(data->log_handler, "# Policy : AQUOSA\n"); - data->params.Q_min = round((timespec_to_usec(&data->min_et) * (( 100.0 + data->sched_prio ) / 100)) / (data->fragment * 1.0)); - data->params.Q = round((timespec_to_usec(&data->max_et) * (( 100.0 + data->sched_prio ) / 100)) / (data->fragment * 1.0)); - data->params.P = round(timespec_to_usec(&data->period) / (data->fragment * 1.0)); + data->params.Q_min = round((timespec_to_usec(&data->min_et) + * (( 100.0 + data->sched_prio ) / 100)) / (data->fragment * 1.0)); + data->params.Q = round((timespec_to_usec(&data->max_et) + * (( 100.0 + data->sched_prio ) / 100)) / (data->fragment * 1.0)); + data->params.P = round(timespec_to_usec(&data->period) + / (data->fragment * 1.0)); data->params.flags = 0; + log_notice("[%d] Creating QRES Server with Q=%ld, P=%ld", - data->ind,data->params.Q, data->params.P); + data->ind,data->params.Q, data->params.P);
qos_chk_ok_exit(qres_init()); - qos_chk_ok_exit(qres_create_server(&data->params, - &data->sid)); + qos_chk_ok_exit(qres_create_server(&data->params, + &data->sid)); log_notice("[%d] AQuoSA server ID: %d", data->ind, data->sid); log_notice("[%d] attaching thread (deadline: %lu) to server %d", - data->ind, - timespec_to_usec(&data->deadline), - data->sid - ); - qos_chk_ok_exit(qres_attach_thread(data->sid, 0, 0)); + data->ind, + timespec_to_usec(&data->deadline), + data->sid);
- break; + qos_chk_ok_exit(qres_attach_thread(data->sid, 0, 0)); + break; #endif + #ifdef DLSCHED case deadline: fprintf(data->log_handler, "# Policy : SCHED_DEADLINE\n"); @@ -226,16 +235,16 @@ void *thread_body(void *arg) 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; + (timespec_to_nsec(&data->max_et) /100) * BUDGET_OVERP; attr.sched_deadline = timespec_to_nsec(&data->period); attr.sched_period = timespec_to_nsec(&data->period); - - break; + break; #endif
default: log_error("Unknown scheduling policy %d", - data->sched_policy); + data->sched_policy); + exit(EXIT_FAILURE); }
@@ -253,45 +262,46 @@ void *thread_body(void *arg) if (data->wait_before_start > 0) { log_notice("[%d] Waiting %ld usecs... ", data->ind, data->wait_before_start); - clock_gettime(CLOCK_MONOTONIC, &t); + clock_gettime(CLOCK_MONOTONIC, &t_now); t_next = msec_to_timespec(data->wait_before_start); - t_next = timespec_add(&t, &t_next); + t_next = timespec_add(&t_now, &t_next); clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &t_next, NULL); log_notice("[%d] Starting...", data->ind); } + /* 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. */ 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)); + 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)); }
fprintf(data->log_handler, "#idx\tperiod\tmin_et\tmax_et\trel_st\tstart" - "\t\tend\t\tdeadline\tdur.\tslack" - "\tBudget\tUsed Budget\n"); + "\t\tend\t\tdeadline\tdur.\tslack" + "\tBudget\tUsed Budget\n");
#ifdef DLSCHED + /* TODO find a better way to handle that constraint */ /* * Set the task to SCHED_DEADLINE as far as possible touching its * budget as little as possible for the first iteration. */ if (data->sched_policy == SCHED_DEADLINE) { log_notice("[%d] starting thread with period: %lu, exec: %lu," - "deadline: %lu, priority: %d", - data->ind, - attr.sched_period / 1000, - attr.sched_runtime / 1000, - attr.sched_deadline / 1000, - attr.sched_priority - ); + "deadline: %lu, priority: %d", + data->ind, + attr.sched_period / 1000, + attr.sched_runtime / 1000, + attr.sched_deadline / 1000, + attr.sched_priority);
ret = sched_setattr(tid, &attr, flags); if (ret != 0) { @@ -306,15 +316,17 @@ void *thread_body(void *arg)
if (opts.ftrace) log_ftrace(ft_data.marker_fd, "[%d] starts", data->ind); - clock_gettime(CLOCK_MONOTONIC, &t); - t_next = t; - data->deadline = timespec_add(&t, &data->deadline); + + clock_gettime(CLOCK_MONOTONIC, &t_now); + t_next = t_now; + data->deadline = timespec_add(&t_now, &data->deadline);
while (continue_running) { 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); + clock_gettime(CLOCK_MONOTONIC, &t_start); run(data->ind, &data->min_et, &data->max_et, data->blockages, data->nblockages); @@ -328,6 +340,7 @@ void *thread_body(void *arg) curr_timing = &timings[i]; else 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); @@ -339,14 +352,15 @@ void *thread_body(void *arg) curr_timing->deadline = timespec_to_usec(&data->deadline); curr_timing->duration = timespec_to_usec(&t_diff); curr_timing->slack = timespec_to_lusec(&t_slack); + #ifdef AQUOSA if (data->sched_policy == aquosa) { curr_timing->budget = data->params.Q; qres_get_exec_time(data->sid, - &abs_used_budget, - NULL); + &abs_used_budget, + NULL); curr_timing->used_budget = - abs_used_budget - prev_abs_used_budget; + abs_used_budget - prev_abs_used_budget; prev_abs_used_budget = abs_used_budget;
} else { @@ -359,9 +373,11 @@ void *thread_body(void *arg)
t_next = timespec_add(&t_next, &data->period); data->deadline = timespec_add(&data->deadline, &data->period); + if (opts.ftrace) log_ftrace(ft_data.marker_fd, "[%d] end loop %d", data->ind, i); + if (curr_timing->slack < 0 && opts.die_on_dmiss) { log_critical("[%d] DEADLINE MISS !!!", data->ind); if (opts.ftrace) @@ -370,7 +386,11 @@ void *thread_body(void *arg) shutdown(SIGTERM); goto exit_miss; } - clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &t_next, NULL); + + clock_gettime(CLOCK_MONOTONIC, &t_now); + if (timespec_lower(&t_now, &t_next)) + clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &t_next, NULL); + i++; }
@@ -393,18 +413,17 @@ exit_miss: log_ftrace(ft_data.marker_fd, "[%d] exiting", data->ind); log_notice("[%d] Exiting.", data->ind); fclose(data->log_handler); + #ifdef AQUOSA if (data->sched_policy == aquosa) { qres_destroy_server(data->sid); qres_cleanup(); } #endif + pthread_exit(NULL); }
-/* parse a thread token in the form $period:$exec:$deadline:$policy:$prio and - * fills the thread_data structure - */
int main(int argc, char* argv[]) { @@ -416,6 +435,7 @@ int main(int argc, char* argv[])
parse_command_line(argc, argv, &opts);
+ /* allocated threads */ nthreads = opts.nthreads; threads = malloc(nthreads * sizeof(pthread_t));
@@ -425,7 +445,7 @@ int main(int argc, char* argv[]) signal(SIGHUP, shutdown); signal(SIGINT, shutdown);
- /* if using ftrace open trace and marker fds */ + /* if using ftrace, open trace and marker fds */ if (opts.ftrace) { log_notice("configuring ftrace"); strcpy(tmp, ft_data.debugfs); @@ -454,8 +474,7 @@ int main(int argc, char* argv[]) clock_gettime(CLOCK_MONOTONIC, &t_start);
/* start threads */ - for (i = 0; i < nthreads; i++) - { + for (i = 0; i < nthreads; i++) { tdata = &opts.threads_data[i]; if (opts.spacing > 0 ) { /* start the thread, then it will sleep accordingly @@ -466,19 +485,21 @@ int main(int argc, char* argv[]) } else { tdata->wait_before_start = 0; } + tdata->duration = opts.duration; tdata->main_app_start = t_start; tdata->lock_pages = opts.lock_pages; #ifdef AQUOSA tdata->fragment = opts.fragment; #endif + if (opts.logdir) { snprintf(tmp, PATH_LENGTH, "%s/%s-%s.log", opts.logdir, opts.logbasename, tdata->name); tdata->log_handler = fopen(tmp, "w"); - if (!tdata->log_handler){ + if (!tdata->log_handler) { log_error("Cannot open logfile %s", tmp); exit(EXIT_FAILURE); } @@ -494,8 +515,7 @@ int main(int argc, char* argv[]) }
/* print gnuplot files */ - if (opts.logdir && opts.gnuplot) - { + if (opts.logdir && opts.gnuplot) { snprintf(tmp, PATH_LENGTH, "%s/%s-duration.plot", opts.logdir, opts.logbasename); gnuplot_script = fopen(tmp, "w+"); @@ -511,8 +531,7 @@ int main(int argc, char* argv[]) "set ylabel "Exec Time [usec]"\n" "plot ", tmp);
- for (i=0; i<nthreads; i++) - { + for (i=0; i<nthreads; i++) { snprintf(tmp, PATH_LENGTH, "%s/%s-duration.plot", opts.logdir, opts.logbasename);
@@ -528,11 +547,12 @@ int main(int argc, char* argv[]) else fprintf(gnuplot_script, ", "); } + fprintf(gnuplot_script, "set terminal wxt\nreplot\n"); fclose(gnuplot_script);
snprintf(tmp, PATH_LENGTH, "%s/%s-slack.plot", - opts.logdir, opts.logbasename); + opts.logdir, opts.logbasename); gnuplot_script = fopen(tmp, "w+"); snprintf(tmp, PATH_LENGTH, "%s-slack.eps", opts.logbasename); @@ -547,8 +567,7 @@ int main(int argc, char* argv[]) "set ylabel "Slack/Tardiness [usec]"\n" "plot ", tmp);
- for (i=0; i < nthreads; i++) - { + for (i=0; i < nthreads; i++) { fprintf(gnuplot_script, ""%s-%s.log" u ($5/1000):10 w l" " title "thread [%s] (%s)"", @@ -562,19 +581,19 @@ int main(int argc, char* argv[]) fprintf(gnuplot_script, ", ");
} + fprintf(gnuplot_script, "set terminal wxt\nreplot\n"); fclose(gnuplot_script); }
- if (opts.duration > 0) - { + if (opts.duration > 0) { sleep(opts.duration); if (opts.ftrace) log_ftrace(ft_data.marker_fd, "main shutdown\n"); shutdown(SIGTERM); }
- for (i = 0; i < nthreads; i++) { + for (i = 0; i < nthreads; i++) { pthread_join(threads[i], NULL); }
diff --git a/src/rt-app_args.c b/src/rt-app_args.c index 36e7e51..49ff749 100644 --- a/src/rt-app_args.c +++ b/src/rt-app_args.c @@ -28,7 +28,7 @@ usage (const char* msg, int ex_code) "rt-app <taskset.json>\nOR\n"); #endif printf("rt-app [options] -t <period>:<exec>[:policy" - "[:CPU affinity[:prio[:deadline]]]] -t ...\n\n"); + "[:CPU affinity[:prio[:deadline]]]] -t ...\n\n"); printf("-h, --help\t\t:\tshow this help\n"); printf("-f, --fifo\t\t:\tset default policy for threads to SCHED_FIFO\n"); printf("-r, --rr\t\t:\tset default policy fior threads to SCHED_RR\n"); @@ -81,6 +81,7 @@ parse_thread_args(char *arg, int idx, thread_data_t *tdata, policy_t def_policy) token = strtok(str, ":"); tdata->name = malloc(sizeof(char) * 5); tdata->ind = idx; + /* default name for command line threads */ snprintf(tdata->name, 1, "t%d", tdata->ind); tdata->sched_prio = DEFAULT_THREAD_PRIORITY; @@ -105,10 +106,10 @@ parse_thread_args(char *arg, int idx, thread_data_t *tdata, policy_t def_policy) //TODO: add support for max_et somehow if (exec > period) usage("Exec time cannot be greater than" - " period.", EXIT_INV_COMMANDLINE); + " period.", EXIT_INV_COMMANDLINE); if (exec <= 0 ) usage("Cannot set negative exec time", - EXIT_INV_COMMANDLINE); + EXIT_INV_COMMANDLINE); tdata->min_et = usec_to_timespec(exec); tdata->max_et = usec_to_timespec(exec); i++; @@ -173,6 +174,7 @@ parse_thread_args(char *arg, int idx, thread_data_t *tdata, policy_t def_policy) } token = strtok(NULL, ":"); } + if ( i < 2 ) { printf("Period and exec time are mandatory\n"); exit(EXIT_INV_COMMANDLINE); @@ -224,25 +226,27 @@ parse_command_line_options(int argc, char **argv, rtapp_options_t *opts) #ifdef AQUOSA opts->fragment = 1; #endif + static struct option long_options[] = { - {"help", 0, 0, 'h'}, - {"fifo", 0, 0, 'f'}, - {"rr", 0, 0, 'r'}, - {"thread", 1, 0, 't'}, - {"spacing", 1, 0, 's'}, - {"logdir", 1, 0, 'l'}, - {"baselog", 1, 0, 'b'}, - {"gnuplot", 1, 0, 'G'}, - {"duration", 1, 0, 'D'}, - {"ftrace", 0, 0, 'T'}, - {"pi_enabled", 0, 0, 'T'}, - {"die_on_dmiss", 0, 0, 'M'}, + {"help", 0, 0, 'h'}, + {"fifo", 0, 0, 'f'}, + {"rr", 0, 0, 'r'}, + {"thread", 1, 0, 't'}, + {"spacing", 1, 0, 's'}, + {"logdir", 1, 0, 'l'}, + {"baselog", 1, 0, 'b'}, + {"gnuplot", 1, 0, 'G'}, + {"duration", 1, 0, 'D'}, + {"ftrace", 0, 0, 'T'}, + {"pi_enabled", 0, 0, 'T'}, + {"die_on_dmiss", 0, 0, 'M'}, #ifdef AQUOSA - {"qos", 0, 0, 'q'}, - {"frag",1, 0, 'g'}, + {"qos", 0, 0, 'q'}, + {"frag",1, 0, 'g'}, #endif - {0, 0, 0, 0} - }; + {0, 0, 0, 0} + }; + #ifdef AQUOSA while (( ch = getopt_long(argc,argv,"D:GKhfrb:s:l:qg:t:TM", long_options, &longopt_idx)) != -1) @@ -259,13 +263,13 @@ parse_command_line_options(int argc, char **argv, rtapp_options_t *opts) case 'f': if (opts->policy != other) usage("Cannot set multiple policies", - EXIT_INV_COMMANDLINE); + EXIT_INV_COMMANDLINE); opts->policy = fifo; break; case 'r': if (opts->policy != other) usage("Cannot set multiple policies", - EXIT_INV_COMMANDLINE); + EXIT_INV_COMMANDLINE); opts->policy = rr; break; case 'b': @@ -277,26 +281,26 @@ parse_command_line_options(int argc, char **argv, rtapp_options_t *opts) opts->spacing = strtol(optarg, NULL, 0); if (opts->spacing < 0) usage("Cannot set negative spacing", - EXIT_INV_COMMANDLINE); + EXIT_INV_COMMANDLINE); break; case 'l': opts->logdir = strdup(optarg); lstat(opts->logdir, &dirstat); if (! S_ISDIR(dirstat.st_mode)) usage("Cannot stat log directory", - EXIT_INV_COMMANDLINE); + EXIT_INV_COMMANDLINE); break; case 't': if (opts->nthreads > 0) { opts->threads_data = realloc( - opts->threads_data, - (opts->nthreads+1) * \ + opts->threads_data, + (opts->nthreads+1) * \ sizeof(thread_data_t)); } parse_thread_args(optarg, opts->nthreads, - &opts->threads_data[opts->nthreads], - opts->policy); + &opts->threads_data[opts->nthreads], + opts->policy); opts->nthreads++; break; case 'G': @@ -306,7 +310,7 @@ parse_command_line_options(int argc, char **argv, rtapp_options_t *opts) opts->duration = strtol(optarg, NULL, 10); if (opts->duration < 0) usage("Cannot set negative duration", - EXIT_INV_COMMANDLINE); + EXIT_INV_COMMANDLINE); break; case 'K': opts->lock_pages = 0; @@ -324,26 +328,25 @@ parse_command_line_options(int argc, char **argv, rtapp_options_t *opts) case 'q': if (opts->policy != other) usage("Cannot set multiple policies", - EXIT_INV_COMMANDLINE); + EXIT_INV_COMMANDLINE); opts->policy = aquosa; break; case 'g': opts->fragment = strtol(optarg, NULL, 10); if (opts->fragment < 1 || opts->fragment > 16) usage("Fragment divisor must be between" - "1 and 16", EXIT_INV_COMMANDLINE); + "1 and 16", EXIT_INV_COMMANDLINE); break; #endif default: log_error("Invalid option %c", ch); usage(NULL, EXIT_INV_COMMANDLINE); - } - } + if ( opts->nthreads < 1) usage("You have to set parameters for at least one thread", - EXIT_INV_COMMANDLINE); + EXIT_INV_COMMANDLINE);
}
@@ -351,18 +354,20 @@ void parse_command_line(int argc, char **argv, rtapp_options_t *opts) { #ifdef JSON + struct stat config_file_stat; + if (argc < 2) usage(NULL, EXIT_SUCCESS); - struct stat config_file_stat; + if (stat(argv[1], &config_file_stat) == 0) { parse_config(argv[1], opts); return; - } - else if (strcmp(argv[1], "-") == 0) { + } else if (strcmp(argv[1], "-") == 0) { parse_config_stdin(opts); return; } #endif + parse_command_line_options(argc, argv, opts); opts->resources = NULL; opts->nresources = 0; diff --git a/src/rt-app_parse_config.c b/src/rt-app_parse_config.c index 4d8bff8..7411b45 100644 --- a/src/rt-app_parse_config.c +++ b/src/rt-app_parse_config.c @@ -246,7 +246,6 @@ serialize_acl(rtapp_resource_access_list_t **acl, /* recurse on the rest of resources */ serialize_acl(&(*acl), next_idx, task_resources, resources); } - }
static void @@ -261,10 +260,11 @@ parse_thread_resources(const rtapp_options_t *opts, struct json_object *locks, rtapp_resource_access_list_t *tmp, *head, *last; char debug_msg[512], tmpmsg[512];
- data->blockages = malloc(sizeof(rtapp_tasks_resource_list_t) * - json_object_array_length(locks)); data->nblockages = json_object_array_length(locks); - for (i = 0; i< json_object_array_length(locks); i++) + data->blockages = malloc(sizeof(rtapp_tasks_resource_list_t) * + data->nblockages); + + for (i = 0; i< data->nblockages; i++) { res = json_object_array_get_idx(locks, i); if (!json_object_is_type(res, json_type_int)){ @@ -286,6 +286,7 @@ parse_thread_resources(const rtapp_options_t *opts, struct json_object *locks, last = tmp; tmp = tmp->next; } while (tmp != NULL); + /* move first element to list end */ if (last != head) { data->blockages[i].acl = head->next; @@ -318,7 +319,7 @@ parse_thread_resources(const rtapp_options_t *opts, struct json_object *locks, data->blockages[i].usage = usec_to_timespec(usage_usec); } log_info(PIN "res %d, usage: %d acl: %s", cur_res_idx, - usage_usec, debug_msg); + usage_usec, debug_msg); } }
@@ -363,6 +364,18 @@ 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);
+ /* deadline */ + dline = get_int_value_from(obj, "deadline", TRUE, period); + if (dline < exec) { + log_critical(PIN2 "Deadline cannot be less than exec time"); + exit(EXIT_INV_CONFIG); + } + if (dline > period) { + log_critical(PIN2 "Deadline cannot be greater than period"); + exit(EXIT_INV_CONFIG); + } + data->deadline = usec_to_timespec(dline); + /* policy */ policy_to_string(opts->policy, def_policy); policy = get_string_value_from(obj, "policy", TRUE, def_policy); @@ -376,7 +389,7 @@ parse_thread_data(char *name, struct json_object *obj, int idx,
/* priority */ data->sched_prio = get_int_value_from(obj, "priority", TRUE, - DEFAULT_THREAD_PRIORITY); + DEFAULT_THREAD_PRIORITY);
/* deadline */ dline = get_int_value_from(obj, "deadline", TRUE, period); @@ -502,8 +515,10 @@ get_opts_from_json_object(struct json_object *root, rtapp_options_t *opts) void parse_config_stdin(rtapp_options_t *opts) { - /* read from stdin until EOF, write to temp file and parse - * as a "normal" config file */ + /* + * Read from stdin until EOF, write to temp file and parse + * as a "normal" config file + */ size_t in_length; char buf[JSON_FILE_BUF_SIZE]; struct json_object *js; diff --git a/src/rt-app_utils.c b/src/rt-app_utils.c index 0c08f02..9719053 100644 --- a/src/rt-app_utils.c +++ b/src/rt-app_utils.c @@ -224,17 +224,20 @@ void ftrace_write(int mark_fd, const char *fmt, ...) va_start(ap, fmt); n = vsnprintf(tmp, BUF_SIZE, fmt, ap); va_end(ap); + /* If it worked return success */ if (n > -1 && n < size) { write(mark_fd, tmp, n); free(tmp); return; } + /* Else try again with more space */ if (n > -1) /* glibc 2.1 */ size = n+1; else /* glibc 2.0 */ size *= 2; + if ((ntmp = realloc(tmp, size)) == NULL) { free(tmp); log_error("Cannot reallocate ftrace buffer"); diff --git a/src/rt-app_utils.h b/src/rt-app_utils.h index c7444dc..ba01f56 100644 --- a/src/rt-app_utils.h +++ b/src/rt-app_utils.h @@ -121,10 +121,10 @@ timespec_to_nsec(struct timespec *ts); #endif
int -string_to_policy(const char *policy_name, policy_t *policy); +policy_to_string(policy_t policy, char *policy_name);
int -policy_to_string(policy_t policy, char *policy_name); +string_to_policy(const char *policy_name, policy_t *policy);
void ftrace_write(int mark_fd, const char *fmt, ...);
Hi,
On 20/03/15 08:45, pi-cheng.chen wrote:
From: Vincent Guittot vincent.guittot@linaro.org
remove useless space align tab remove useless comment
I understand that this patch cleans things up by applying same kind of changes over and over, but I'd still split it in several smaller patches. Maybe a patch for each of the above points?
Signed-off-by: Vincent Guittot vincent.guittot@linaro.org Signed-off-by: Kevin Hilman khilman@linaro.org
src/rt-app.c | 191 +++++++++++++++++++++++++--------------------- src/rt-app_args.c | 77 ++++++++++--------- src/rt-app_parse_config.c | 31 ++++++-- src/rt-app_utils.c | 3 + src/rt-app_utils.h | 4 +- 5 files changed, 174 insertions(+), 132 deletions(-)
diff --git a/src/rt-app.c b/src/rt-app.c index 3c293e7..4629980 100644 --- a/src/rt-app.c +++ b/src/rt-app.c @@ -27,17 +27,13 @@ static volatile int continue_running; static pthread_t *threads; static int nthreads; rtapp_options_t opts;
static ftrace_data_t ft_data = {
.debugfs = "/debug",
.debugfs = "/sys/kernel/debug",
This maybe deserves a standalone patch, as it doesn't fit in any of the points in the changelog.
.trace_fd = -1, .marker_fd = -1,
};
-static inline unsigned int max_run(int min, int max) -{
return min + (((double) rand()) / RAND_MAX) * (max - min);
-}
This as well.
static inline busywait(struct timespec *to) { struct timespec t_step; @@ -52,27 +48,29 @@ void run(int ind, struct timespec *min, struct timespec *max, rtapp_tasks_resource_list_t *blockages, int nblockages) { int i;
//int m = max_run(timespec_to_msec(min), timespec_to_msec(max));
//struct timespec t_start, t_step, t_exec = msec_to_timespec(m); struct timespec t_start, now, t_exec, t_totexec = *max; rtapp_resource_access_list_t *lock, *last;
/* get the start time */
/* Get the start time */ clock_gettime(CLOCK_THREAD_CPUTIME_ID, &t_start); for (i = 0; i < nblockages; i++) {
/* Lock resources */ lock = blockages[i].acl; while (lock != NULL) { log_debug("[%d] locking %d", ind, lock->res->index); if (opts.ftrace) log_ftrace(ft_data.marker_fd,
"[%d] locking %d",
ind, lock->res->index);
"[%d] locking %d",
ind, lock->res->index);
I generally prefer to keep arguments aligned with the first argument. Can we keep this convention?
pthread_mutex_lock(&lock->res->mtx); last = lock; lock = lock->next; }
/* Busy wait */ clock_gettime(CLOCK_THREAD_CPUTIME_ID, &now); t_exec = timespec_add(&now, &blockages[i].usage); log_debug("[%d] busywait for %lu", ind, timespec_to_usec(&blockages[i].usage));
@@ -81,19 +79,21 @@ void run(int ind, struct timespec *min, struct timespec *max, "[%d] busywait for %d", ind, timespec_to_usec(&blockages[i].usage)); busywait(&t_exec);
/* Unlock resources */ lock = last; while (lock != NULL) { log_debug("[%d] unlocking %d", ind, lock->res->index); if (opts.ftrace) log_ftrace(ft_data.marker_fd,
"[%d] unlocking %d",
ind, lock->res->index);
"[%d] unlocking %d",
ind, lock->res->index); pthread_mutex_unlock(&lock->res->mtx); lock = lock->prev; } }
/* compute finish time for CPUTIME_ID clock */
/* Compute finish time for CPUTIME_ID clock */ t_exec = timespec_add(&t_start, &t_totexec); busywait(&t_exec);
} @@ -108,6 +108,7 @@ shutdown(int sig) { pthread_join(threads[i], NULL); }
if (opts.ftrace) { log_notice("stopping ftrace"); log_ftrace(ft_data.marker_fd, "main ends\n");
@@ -115,6 +116,7 @@ shutdown(int sig) close(ft_data.trace_fd); close(ft_data.marker_fd); }
exit(EXIT_SUCCESS);
}
@@ -122,7 +124,7 @@ void *thread_body(void *arg) { thread_data_t *data = (thread_data_t*) arg; struct sched_param param;
struct timespec t, t_next;
struct timespec t_now, t_next;
Maybe a standalone patch, even if it's just renaming?
unsigned long t_start_usec; unsigned long my_duration_usec; int nperiods;
@@ -162,11 +164,11 @@ void *thread_body(void *arg) case rr: case fifo: fprintf(data->log_handler, "# Policy : %s\n",
(data->sched_policy == rr ? "SCHED_RR" : "SCHED_FIFO"));
(data->sched_policy == rr ? "SCHED_RR" : "SCHED_FIFO")); param.sched_priority = data->sched_prio; ret = pthread_setschedparam(pthread_self(),
data->sched_policy,
¶m);
data->sched_policy,
¶m); if (ret != 0) { errno = ret; perror("pthread_setschedparam");
@@ -174,49 +176,56 @@ void *thread_body(void *arg) }
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
);
"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: fprintf(data->log_handler, "# Policy : SCHED_OTHER\n");
/* 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)
);
"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;
#ifdef AQUOSA case aquosa: fprintf(data->log_handler, "# Policy : AQUOSA\n");
data->params.Q_min = round((timespec_to_usec(&data->min_et) * (( 100.0 + data->sched_prio ) / 100)) / (data->fragment * 1.0));
data->params.Q = round((timespec_to_usec(&data->max_et) * (( 100.0 + data->sched_prio ) / 100)) / (data->fragment * 1.0));
data->params.P = round(timespec_to_usec(&data->period) / (data->fragment * 1.0));
data->params.Q_min = round((timespec_to_usec(&data->min_et)
* (( 100.0 + data->sched_prio ) / 100)) / (data->fragment * 1.0));
data->params.Q = round((timespec_to_usec(&data->max_et)
* (( 100.0 + data->sched_prio ) / 100)) / (data->fragment * 1.0));
data->params.P = round(timespec_to_usec(&data->period)
/ (data->fragment * 1.0)); data->params.flags = 0;
log_notice("[%d] Creating QRES Server with Q=%ld, P=%ld",
data->ind,data->params.Q, data->params.P);
data->ind,data->params.Q, data->params.P); qos_chk_ok_exit(qres_init());
qos_chk_ok_exit(qres_create_server(&data->params,
&data->sid));
qos_chk_ok_exit(qres_create_server(&data->params,
&data->sid)); log_notice("[%d] AQuoSA server ID: %d", data->ind, data->sid); log_notice("[%d] attaching thread (deadline: %lu) to server %d",
data->ind,
timespec_to_usec(&data->deadline),
data->sid
);
qos_chk_ok_exit(qres_attach_thread(data->sid, 0, 0));
data->ind,
timespec_to_usec(&data->deadline),
data->sid);
break;
qos_chk_ok_exit(qres_attach_thread(data->sid, 0, 0));
break;
#endif
#ifdef DLSCHED case deadline: fprintf(data->log_handler, "# Policy : SCHED_DEADLINE\n"); @@ -226,16 +235,16 @@ void *thread_body(void *arg) 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;
(timespec_to_nsec(&data->max_et) /100) * BUDGET_OVERP; attr.sched_deadline = timespec_to_nsec(&data->period); attr.sched_period = timespec_to_nsec(&data->period);
break;
break;
#endif
default: log_error("Unknown scheduling policy %d",
data->sched_policy);
data->sched_policy);
exit(EXIT_FAILURE); }
@@ -253,45 +262,46 @@ void *thread_body(void *arg) if (data->wait_before_start > 0) { log_notice("[%d] Waiting %ld usecs... ", data->ind, data->wait_before_start);
clock_gettime(CLOCK_MONOTONIC, &t);
clock_gettime(CLOCK_MONOTONIC, &t_now); t_next = msec_to_timespec(data->wait_before_start);
t_next = timespec_add(&t, &t_next);
t_next = timespec_add(&t_now, &t_next); clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &t_next, NULL); log_notice("[%d] Starting...", data->ind); }
/* 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. */ 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));
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)); } fprintf(data->log_handler, "#idx\tperiod\tmin_et\tmax_et\trel_st\tstart"
"\t\tend\t\tdeadline\tdur.\tslack"
"\tBudget\tUsed Budget\n");
"\t\tend\t\tdeadline\tdur.\tslack"
"\tBudget\tUsed Budget\n");
#ifdef DLSCHED
/* TODO find a better way to handle that constraint */ /* * Set the task to SCHED_DEADLINE as far as possible touching its * budget as little as possible for the first iteration. */ if (data->sched_policy == SCHED_DEADLINE) { log_notice("[%d] starting thread with period: %lu, exec: %lu,"
"deadline: %lu, priority: %d",
data->ind,
attr.sched_period / 1000,
attr.sched_runtime / 1000,
attr.sched_deadline / 1000,
attr.sched_priority
);
"deadline: %lu, priority: %d",
data->ind,
attr.sched_period / 1000,
attr.sched_runtime / 1000,
attr.sched_deadline / 1000,
attr.sched_priority); ret = sched_setattr(tid, &attr, flags); if (ret != 0) {
@@ -306,15 +316,17 @@ void *thread_body(void *arg)
if (opts.ftrace) log_ftrace(ft_data.marker_fd, "[%d] starts", data->ind);
clock_gettime(CLOCK_MONOTONIC, &t);
t_next = t;
data->deadline = timespec_add(&t, &data->deadline);
clock_gettime(CLOCK_MONOTONIC, &t_now);
t_next = t_now;
data->deadline = timespec_add(&t_now, &data->deadline); while (continue_running) { 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);
clock_gettime(CLOCK_MONOTONIC, &t_start); run(data->ind, &data->min_et, &data->max_et, data->blockages, data->nblockages);
@@ -328,6 +340,7 @@ void *thread_body(void *arg) curr_timing = &timings[i]; else 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);
@@ -339,14 +352,15 @@ void *thread_body(void *arg) curr_timing->deadline = timespec_to_usec(&data->deadline); curr_timing->duration = timespec_to_usec(&t_diff); curr_timing->slack = timespec_to_lusec(&t_slack);
#ifdef AQUOSA if (data->sched_policy == aquosa) { curr_timing->budget = data->params.Q; qres_get_exec_time(data->sid,
&abs_used_budget,
NULL);
&abs_used_budget,
NULL); curr_timing->used_budget =
abs_used_budget - prev_abs_used_budget;
abs_used_budget - prev_abs_used_budget; prev_abs_used_budget = abs_used_budget; } else {
@@ -359,9 +373,11 @@ void *thread_body(void *arg)
t_next = timespec_add(&t_next, &data->period); data->deadline = timespec_add(&data->deadline, &data->period);
if (opts.ftrace) log_ftrace(ft_data.marker_fd, "[%d] end loop %d", data->ind, i);
if (curr_timing->slack < 0 && opts.die_on_dmiss) { log_critical("[%d] DEADLINE MISS !!!", data->ind); if (opts.ftrace)
@@ -370,7 +386,11 @@ void *thread_body(void *arg) shutdown(SIGTERM); goto exit_miss; }
clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &t_next, NULL);
clock_gettime(CLOCK_MONOTONIC, &t_now);
if (timespec_lower(&t_now, &t_next))
clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &t_next, NULL);
Can you explain, maybe in a separate patch, why we need this change?
i++; }
@@ -393,18 +413,17 @@ exit_miss: log_ftrace(ft_data.marker_fd, "[%d] exiting", data->ind); log_notice("[%d] Exiting.", data->ind); fclose(data->log_handler);
#ifdef AQUOSA if (data->sched_policy == aquosa) { qres_destroy_server(data->sid); qres_cleanup(); } #endif
pthread_exit(NULL);
}
-/* parse a thread token in the form $period:$exec:$deadline:$policy:$prio and
- fills the thread_data structure
- */
int main(int argc, char* argv[]) { @@ -416,6 +435,7 @@ int main(int argc, char* argv[])
parse_command_line(argc, argv, &opts);
/* allocated threads */ nthreads = opts.nthreads; threads = malloc(nthreads * sizeof(pthread_t));
@@ -425,7 +445,7 @@ int main(int argc, char* argv[]) signal(SIGHUP, shutdown); signal(SIGINT, shutdown);
/* if using ftrace open trace and marker fds */
/* if using ftrace, open trace and marker fds */ if (opts.ftrace) { log_notice("configuring ftrace"); strcpy(tmp, ft_data.debugfs);
@@ -454,8 +474,7 @@ int main(int argc, char* argv[]) clock_gettime(CLOCK_MONOTONIC, &t_start);
/* start threads */
for (i = 0; i < nthreads; i++)
{
for (i = 0; i < nthreads; i++) { tdata = &opts.threads_data[i]; if (opts.spacing > 0 ) { /* start the thread, then it will sleep accordingly
@@ -466,19 +485,21 @@ int main(int argc, char* argv[]) } else { tdata->wait_before_start = 0; }
tdata->duration = opts.duration; tdata->main_app_start = t_start; tdata->lock_pages = opts.lock_pages;
#ifdef AQUOSA tdata->fragment = opts.fragment; #endif
if (opts.logdir) { snprintf(tmp, PATH_LENGTH, "%s/%s-%s.log", opts.logdir, opts.logbasename, tdata->name); tdata->log_handler = fopen(tmp, "w");
if (!tdata->log_handler){
if (!tdata->log_handler) { log_error("Cannot open logfile %s", tmp); exit(EXIT_FAILURE); }
@@ -494,8 +515,7 @@ int main(int argc, char* argv[]) }
/* print gnuplot files */
if (opts.logdir && opts.gnuplot)
{
if (opts.logdir && opts.gnuplot) { snprintf(tmp, PATH_LENGTH, "%s/%s-duration.plot", opts.logdir, opts.logbasename); gnuplot_script = fopen(tmp, "w+");
@@ -511,8 +531,7 @@ int main(int argc, char* argv[]) "set ylabel "Exec Time [usec]"\n" "plot ", tmp);
for (i=0; i<nthreads; i++)
{
for (i=0; i<nthreads; i++) { snprintf(tmp, PATH_LENGTH, "%s/%s-duration.plot", opts.logdir, opts.logbasename);
@@ -528,11 +547,12 @@ int main(int argc, char* argv[]) else fprintf(gnuplot_script, ", "); }
fprintf(gnuplot_script, "set terminal wxt\nreplot\n"); fclose(gnuplot_script); snprintf(tmp, PATH_LENGTH, "%s/%s-slack.plot",
opts.logdir, opts.logbasename);
opts.logdir, opts.logbasename); gnuplot_script = fopen(tmp, "w+"); snprintf(tmp, PATH_LENGTH, "%s-slack.eps", opts.logbasename);
@@ -547,8 +567,7 @@ int main(int argc, char* argv[]) "set ylabel "Slack/Tardiness [usec]"\n" "plot ", tmp);
for (i=0; i < nthreads; i++)
{
for (i=0; i < nthreads; i++) { fprintf(gnuplot_script, "\"%s-%s.log\" u ($5/1000):10 w l" " title \"thread [%s] (%s)\"",
@@ -562,19 +581,19 @@ int main(int argc, char* argv[]) fprintf(gnuplot_script, ", ");
}
fprintf(gnuplot_script, "set terminal wxt\nreplot\n"); fclose(gnuplot_script); }
if (opts.duration > 0)
{
if (opts.duration > 0) { sleep(opts.duration); if (opts.ftrace) log_ftrace(ft_data.marker_fd, "main shutdown\n"); shutdown(SIGTERM); }
for (i = 0; i < nthreads; i++) {
for (i = 0; i < nthreads; i++) { pthread_join(threads[i], NULL); }
diff --git a/src/rt-app_args.c b/src/rt-app_args.c index 36e7e51..49ff749 100644 --- a/src/rt-app_args.c +++ b/src/rt-app_args.c @@ -28,7 +28,7 @@ usage (const char* msg, int ex_code) "rt-app <taskset.json>\nOR\n"); #endif printf("rt-app [options] -t <period>:<exec>[:policy"
"[:CPU affinity[:prio[:deadline]]]] -t ...\n\n");
"[:CPU affinity[:prio[:deadline]]]] -t ...\n\n"); printf("-h, --help\t\t:\tshow this help\n"); printf("-f, --fifo\t\t:\tset default policy for threads to SCHED_FIFO\n"); printf("-r, --rr\t\t:\tset default policy fior threads to SCHED_RR\n");
@@ -81,6 +81,7 @@ parse_thread_args(char *arg, int idx, thread_data_t *tdata, policy_t def_policy) token = strtok(str, ":"); tdata->name = malloc(sizeof(char) * 5); tdata->ind = idx;
/* default name for command line threads */ snprintf(tdata->name, 1, "t%d", tdata->ind); tdata->sched_prio = DEFAULT_THREAD_PRIORITY;
@@ -105,10 +106,10 @@ parse_thread_args(char *arg, int idx, thread_data_t *tdata, policy_t def_policy) //TODO: add support for max_et somehow if (exec > period) usage("Exec time cannot be greater than"
" period.", EXIT_INV_COMMANDLINE);
" period.", EXIT_INV_COMMANDLINE); if (exec <= 0 ) usage("Cannot set negative exec time",
EXIT_INV_COMMANDLINE);
EXIT_INV_COMMANDLINE); tdata->min_et = usec_to_timespec(exec); tdata->max_et = usec_to_timespec(exec); i++;
@@ -173,6 +174,7 @@ parse_thread_args(char *arg, int idx, thread_data_t *tdata, policy_t def_policy) } token = strtok(NULL, ":"); }
if ( i < 2 ) { printf("Period and exec time are mandatory\n"); exit(EXIT_INV_COMMANDLINE);
@@ -224,25 +226,27 @@ parse_command_line_options(int argc, char **argv, rtapp_options_t *opts) #ifdef AQUOSA opts->fragment = 1; #endif
static struct option long_options[] = {
{"help", 0, 0, 'h'},
{"fifo", 0, 0, 'f'},
{"rr", 0, 0, 'r'},
{"thread", 1, 0, 't'},
{"spacing", 1, 0, 's'},
{"logdir", 1, 0, 'l'},
{"baselog", 1, 0, 'b'},
{"gnuplot", 1, 0, 'G'},
{"duration", 1, 0, 'D'},
{"ftrace", 0, 0, 'T'},
{"pi_enabled", 0, 0, 'T'},
{"die_on_dmiss", 0, 0, 'M'},
{"help", 0, 0, 'h'},
{"fifo", 0, 0, 'f'},
{"rr", 0, 0, 'r'},
{"thread", 1, 0, 't'},
{"spacing", 1, 0, 's'},
{"logdir", 1, 0, 'l'},
{"baselog", 1, 0, 'b'},
{"gnuplot", 1, 0, 'G'},
{"duration", 1, 0, 'D'},
{"ftrace", 0, 0, 'T'},
{"pi_enabled", 0, 0, 'T'},
{"die_on_dmiss", 0, 0, 'M'},
#ifdef AQUOSA
{"qos", 0, 0, 'q'},
{"frag",1, 0, 'g'},
{"qos", 0, 0, 'q'},
{"frag",1, 0, 'g'},
#endif
{0, 0, 0, 0}
};
{0, 0, 0, 0}
};
#ifdef AQUOSA while (( ch = getopt_long(argc,argv,"D:GKhfrb:s:l:qg:t:TM", long_options, &longopt_idx)) != -1) @@ -259,13 +263,13 @@ parse_command_line_options(int argc, char **argv, rtapp_options_t *opts) case 'f': if (opts->policy != other) usage("Cannot set multiple policies",
EXIT_INV_COMMANDLINE);
EXIT_INV_COMMANDLINE); opts->policy = fifo; break; case 'r': if (opts->policy != other) usage("Cannot set multiple policies",
EXIT_INV_COMMANDLINE);
EXIT_INV_COMMANDLINE); opts->policy = rr; break; case 'b':
@@ -277,26 +281,26 @@ parse_command_line_options(int argc, char **argv, rtapp_options_t *opts) opts->spacing = strtol(optarg, NULL, 0); if (opts->spacing < 0) usage("Cannot set negative spacing",
EXIT_INV_COMMANDLINE);
EXIT_INV_COMMANDLINE); break; case 'l': opts->logdir = strdup(optarg); lstat(opts->logdir, &dirstat); if (! S_ISDIR(dirstat.st_mode)) usage("Cannot stat log directory",
EXIT_INV_COMMANDLINE);
EXIT_INV_COMMANDLINE); break; case 't': if (opts->nthreads > 0) { opts->threads_data = realloc(
opts->threads_data,
(opts->nthreads+1) * \
opts->threads_data,
(opts->nthreads+1) * \ sizeof(thread_data_t)); } parse_thread_args(optarg, opts->nthreads,
&opts->threads_data[opts->nthreads],
opts->policy);
&opts->threads_data[opts->nthreads],
opts->policy); opts->nthreads++; break; case 'G':
@@ -306,7 +310,7 @@ parse_command_line_options(int argc, char **argv, rtapp_options_t *opts) opts->duration = strtol(optarg, NULL, 10); if (opts->duration < 0) usage("Cannot set negative duration",
EXIT_INV_COMMANDLINE);
EXIT_INV_COMMANDLINE); break; case 'K': opts->lock_pages = 0;
@@ -324,26 +328,25 @@ parse_command_line_options(int argc, char **argv, rtapp_options_t *opts) case 'q': if (opts->policy != other) usage("Cannot set multiple policies",
EXIT_INV_COMMANDLINE);
EXIT_INV_COMMANDLINE); opts->policy = aquosa; break; case 'g': opts->fragment = strtol(optarg, NULL, 10); if (opts->fragment < 1 || opts->fragment > 16) usage("Fragment divisor must be between"
"1 and 16", EXIT_INV_COMMANDLINE);
"1 and 16", EXIT_INV_COMMANDLINE); break;
#endif default: log_error("Invalid option %c", ch); usage(NULL, EXIT_INV_COMMANDLINE);
}
}
if ( opts->nthreads < 1) usage("You have to set parameters for at least one thread",
EXIT_INV_COMMANDLINE);
EXIT_INV_COMMANDLINE);
}
@@ -351,18 +354,20 @@ void parse_command_line(int argc, char **argv, rtapp_options_t *opts) { #ifdef JSON
struct stat config_file_stat;
if (argc < 2) usage(NULL, EXIT_SUCCESS);
struct stat config_file_stat;
if (stat(argv[1], &config_file_stat) == 0) { parse_config(argv[1], opts); return;
}
else if (strcmp(argv[1], "-") == 0) {
} else if (strcmp(argv[1], "-") == 0) { parse_config_stdin(opts); return; }
#endif
parse_command_line_options(argc, argv, opts); opts->resources = NULL; opts->nresources = 0;
diff --git a/src/rt-app_parse_config.c b/src/rt-app_parse_config.c index 4d8bff8..7411b45 100644 --- a/src/rt-app_parse_config.c +++ b/src/rt-app_parse_config.c @@ -246,7 +246,6 @@ serialize_acl(rtapp_resource_access_list_t **acl, /* recurse on the rest of resources */ serialize_acl(&(*acl), next_idx, task_resources, resources); }
}
static void @@ -261,10 +260,11 @@ parse_thread_resources(const rtapp_options_t *opts, struct json_object *locks, rtapp_resource_access_list_t *tmp, *head, *last; char debug_msg[512], tmpmsg[512];
data->blockages = malloc(sizeof(rtapp_tasks_resource_list_t) *
json_object_array_length(locks)); data->nblockages = json_object_array_length(locks);
for (i = 0; i< json_object_array_length(locks); i++)
data->blockages = malloc(sizeof(rtapp_tasks_resource_list_t) *
data->nblockages);
for (i = 0; i< data->nblockages; i++)
This might deserve a separate patch as well.
{ res = json_object_array_get_idx(locks, i); if (!json_object_is_type(res, json_type_int)){
@@ -286,6 +286,7 @@ parse_thread_resources(const rtapp_options_t *opts, struct json_object *locks, last = tmp; tmp = tmp->next; } while (tmp != NULL);
/* move first element to list end */ if (last != head) { data->blockages[i].acl = head->next;
@@ -318,7 +319,7 @@ parse_thread_resources(const rtapp_options_t *opts, struct json_object *locks, data->blockages[i].usage = usec_to_timespec(usage_usec); } log_info(PIN "res %d, usage: %d acl: %s", cur_res_idx,
usage_usec, debug_msg);
usage_usec, debug_msg); }
}
@@ -363,6 +364,18 @@ 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);
/* deadline */
dline = get_int_value_from(obj, "deadline", TRUE, period);
if (dline < exec) {
log_critical(PIN2 "Deadline cannot be less than exec time");
exit(EXIT_INV_CONFIG);
}
if (dline > period) {
log_critical(PIN2 "Deadline cannot be greater than period");
exit(EXIT_INV_CONFIG);
}
data->deadline = usec_to_timespec(dline);
Separate patch for this change as well?
/* policy */ policy_to_string(opts->policy, def_policy); policy = get_string_value_from(obj, "policy", TRUE, def_policy);
@@ -376,7 +389,7 @@ parse_thread_data(char *name, struct json_object *obj, int idx,
/* priority */ data->sched_prio = get_int_value_from(obj, "priority", TRUE,
DEFAULT_THREAD_PRIORITY);
DEFAULT_THREAD_PRIORITY); /* deadline */ dline = get_int_value_from(obj, "deadline", TRUE, period);
@@ -502,8 +515,10 @@ get_opts_from_json_object(struct json_object *root, rtapp_options_t *opts) void parse_config_stdin(rtapp_options_t *opts) {
/* read from stdin until EOF, write to temp file and parse
* as a "normal" config file */
/*
* Read from stdin until EOF, write to temp file and parse
* as a "normal" config file
*/ size_t in_length; char buf[JSON_FILE_BUF_SIZE]; struct json_object *js;
diff --git a/src/rt-app_utils.c b/src/rt-app_utils.c index 0c08f02..9719053 100644 --- a/src/rt-app_utils.c +++ b/src/rt-app_utils.c @@ -224,17 +224,20 @@ void ftrace_write(int mark_fd, const char *fmt, ...) va_start(ap, fmt); n = vsnprintf(tmp, BUF_SIZE, fmt, ap); va_end(ap);
/* If it worked return success */ if (n > -1 && n < size) { write(mark_fd, tmp, n); free(tmp); return; }
/* Else try again with more space */ if (n > -1) /* glibc 2.1 */ size = n+1; else /* glibc 2.0 */ size *= 2;
if ((ntmp = realloc(tmp, size)) == NULL) { free(tmp); log_error("Cannot reallocate ftrace buffer");
diff --git a/src/rt-app_utils.h b/src/rt-app_utils.h index c7444dc..ba01f56 100644 --- a/src/rt-app_utils.h +++ b/src/rt-app_utils.h @@ -121,10 +121,10 @@ timespec_to_nsec(struct timespec *ts); #endif
int -string_to_policy(const char *policy_name, policy_t *policy); +policy_to_string(policy_t policy, char *policy_name);
Is this fixing complaints from compiler? Maybe fix it in a separate patch?
int -policy_to_string(policy_t policy, char *policy_name); +string_to_policy(const char *policy_name, policy_t *policy);
void ftrace_write(int mark_fd, const char *fmt, ...); -- 1.9.1
Thanks a lot again for this effort!
Best,
- Juri
On 13 April 2015 at 15:35, Juri Lelli juri.lelli@arm.com wrote:
Hi,
On 20/03/15 08:45, pi-cheng.chen wrote:
From: Vincent Guittot vincent.guittot@linaro.org
remove useless space align tab remove useless comment
I understand that this patch cleans things up by applying same kind of changes over and over, but I'd still split it in several smaller patches. Maybe a patch for each of the above points?
I have squashed them in one patch in order to minimize the number of patches but they can be split if you prefer
Signed-off-by: Vincent Guittot vincent.guittot@linaro.org Signed-off-by: Kevin Hilman khilman@linaro.org
src/rt-app.c | 191 +++++++++++++++++++++++++--------------------- src/rt-app_args.c | 77 ++++++++++--------- src/rt-app_parse_config.c | 31 ++++++-- src/rt-app_utils.c | 3 + src/rt-app_utils.h | 4 +- 5 files changed, 174 insertions(+), 132 deletions(-)
diff --git a/src/rt-app.c b/src/rt-app.c index 3c293e7..4629980 100644 --- a/src/rt-app.c +++ b/src/rt-app.c @@ -27,17 +27,13 @@ static volatile int continue_running; static pthread_t *threads; static int nthreads; rtapp_options_t opts;
static ftrace_data_t ft_data = {
.debugfs = "/debug",
.debugfs = "/sys/kernel/debug",
This maybe deserves a standalone patch, as it doesn't fit in any of the points in the changelog.
.trace_fd = -1, .marker_fd = -1,
};
-static inline unsigned int max_run(int min, int max) -{
return min + (((double) rand()) / RAND_MAX) * (max - min);
-}
This as well.
static inline busywait(struct timespec *to) { struct timespec t_step; @@ -52,27 +48,29 @@ void run(int ind, struct timespec *min, struct timespec *max, rtapp_tasks_resource_list_t *blockages, int nblockages) { int i;
//int m = max_run(timespec_to_msec(min), timespec_to_msec(max));
//struct timespec t_start, t_step, t_exec = msec_to_timespec(m); struct timespec t_start, now, t_exec, t_totexec = *max; rtapp_resource_access_list_t *lock, *last;
/* get the start time */
/* Get the start time */ clock_gettime(CLOCK_THREAD_CPUTIME_ID, &t_start); for (i = 0; i < nblockages; i++) {
/* Lock resources */ lock = blockages[i].acl; while (lock != NULL) { log_debug("[%d] locking %d", ind, lock->res->index); if (opts.ftrace) log_ftrace(ft_data.marker_fd,
"[%d] locking %d",
ind, lock->res->index);
"[%d] locking %d",
ind, lock->res->index);
I generally prefer to keep arguments aligned with the first argument. Can we keep this convention?
i'm fine with this point. This change was to align the arguments (but stay aligned with tab width) which were not aligned with my text editor (which tab width are you using ?) If you want to be aligned, tab should be replaced by withe space
pthread_mutex_lock(&lock->res->mtx); last = lock; lock = lock->next; }
/* Busy wait */ clock_gettime(CLOCK_THREAD_CPUTIME_ID, &now); t_exec = timespec_add(&now, &blockages[i].usage); log_debug("[%d] busywait for %lu", ind, timespec_to_usec(&blockages[i].usage));
@@ -81,19 +79,21 @@ void run(int ind, struct timespec *min, struct timespec *max, "[%d] busywait for %d", ind, timespec_to_usec(&blockages[i].usage)); busywait(&t_exec);
/* Unlock resources */ lock = last; while (lock != NULL) { log_debug("[%d] unlocking %d", ind, lock->res->index); if (opts.ftrace) log_ftrace(ft_data.marker_fd,
"[%d] unlocking %d",
ind, lock->res->index);
"[%d] unlocking %d",
ind, lock->res->index); pthread_mutex_unlock(&lock->res->mtx); lock = lock->prev; } }
/* compute finish time for CPUTIME_ID clock */
/* Compute finish time for CPUTIME_ID clock */ t_exec = timespec_add(&t_start, &t_totexec); busywait(&t_exec);
} @@ -108,6 +108,7 @@ shutdown(int sig) { pthread_join(threads[i], NULL); }
if (opts.ftrace) { log_notice("stopping ftrace"); log_ftrace(ft_data.marker_fd, "main ends\n");
@@ -115,6 +116,7 @@ shutdown(int sig) close(ft_data.trace_fd); close(ft_data.marker_fd); }
exit(EXIT_SUCCESS);
}
@@ -122,7 +124,7 @@ void *thread_body(void *arg) { thread_data_t *data = (thread_data_t*) arg; struct sched_param param;
struct timespec t, t_next;
struct timespec t_now, t_next;
Maybe a standalone patch, even if it's just renaming?
unsigned long t_start_usec; unsigned long my_duration_usec; int nperiods;
@@ -162,11 +164,11 @@ void *thread_body(void *arg) case rr: case fifo: fprintf(data->log_handler, "# Policy : %s\n",
(data->sched_policy == rr ? "SCHED_RR" : "SCHED_FIFO"));
(data->sched_policy == rr ? "SCHED_RR" : "SCHED_FIFO")); param.sched_priority = data->sched_prio; ret = pthread_setschedparam(pthread_self(),
data->sched_policy,
¶m);
data->sched_policy,
¶m); if (ret != 0) { errno = ret; perror("pthread_setschedparam");
@@ -174,49 +176,56 @@ void *thread_body(void *arg) }
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
);
"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: fprintf(data->log_handler, "# Policy : SCHED_OTHER\n");
/* 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)
);
"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;
#ifdef AQUOSA case aquosa: fprintf(data->log_handler, "# Policy : AQUOSA\n");
data->params.Q_min = round((timespec_to_usec(&data->min_et) * (( 100.0 + data->sched_prio ) / 100)) / (data->fragment * 1.0));
data->params.Q = round((timespec_to_usec(&data->max_et) * (( 100.0 + data->sched_prio ) / 100)) / (data->fragment * 1.0));
data->params.P = round(timespec_to_usec(&data->period) / (data->fragment * 1.0));
data->params.Q_min = round((timespec_to_usec(&data->min_et)
* (( 100.0 + data->sched_prio ) / 100)) / (data->fragment * 1.0));
data->params.Q = round((timespec_to_usec(&data->max_et)
* (( 100.0 + data->sched_prio ) / 100)) / (data->fragment * 1.0));
data->params.P = round(timespec_to_usec(&data->period)
/ (data->fragment * 1.0)); data->params.flags = 0;
log_notice("[%d] Creating QRES Server with Q=%ld, P=%ld",
data->ind,data->params.Q, data->params.P);
data->ind,data->params.Q, data->params.P); qos_chk_ok_exit(qres_init());
qos_chk_ok_exit(qres_create_server(&data->params,
&data->sid));
qos_chk_ok_exit(qres_create_server(&data->params,
&data->sid)); log_notice("[%d] AQuoSA server ID: %d", data->ind, data->sid); log_notice("[%d] attaching thread (deadline: %lu) to server %d",
data->ind,
timespec_to_usec(&data->deadline),
data->sid
);
qos_chk_ok_exit(qres_attach_thread(data->sid, 0, 0));
data->ind,
timespec_to_usec(&data->deadline),
data->sid);
break;
qos_chk_ok_exit(qres_attach_thread(data->sid, 0, 0));
break;
#endif
#ifdef DLSCHED case deadline: fprintf(data->log_handler, "# Policy : SCHED_DEADLINE\n"); @@ -226,16 +235,16 @@ void *thread_body(void *arg) 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;
(timespec_to_nsec(&data->max_et) /100) * BUDGET_OVERP; attr.sched_deadline = timespec_to_nsec(&data->period); attr.sched_period = timespec_to_nsec(&data->period);
break;
break;
#endif
default: log_error("Unknown scheduling policy %d",
data->sched_policy);
data->sched_policy);
exit(EXIT_FAILURE); }
@@ -253,45 +262,46 @@ void *thread_body(void *arg) if (data->wait_before_start > 0) { log_notice("[%d] Waiting %ld usecs... ", data->ind, data->wait_before_start);
clock_gettime(CLOCK_MONOTONIC, &t);
clock_gettime(CLOCK_MONOTONIC, &t_now); t_next = msec_to_timespec(data->wait_before_start);
t_next = timespec_add(&t, &t_next);
t_next = timespec_add(&t_now, &t_next); clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &t_next, NULL); log_notice("[%d] Starting...", data->ind); }
/* 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. */ 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));
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)); } fprintf(data->log_handler, "#idx\tperiod\tmin_et\tmax_et\trel_st\tstart"
"\t\tend\t\tdeadline\tdur.\tslack"
"\tBudget\tUsed Budget\n");
"\t\tend\t\tdeadline\tdur.\tslack"
"\tBudget\tUsed Budget\n");
#ifdef DLSCHED
/* TODO find a better way to handle that constraint */ /* * Set the task to SCHED_DEADLINE as far as possible touching its * budget as little as possible for the first iteration. */ if (data->sched_policy == SCHED_DEADLINE) { log_notice("[%d] starting thread with period: %lu, exec: %lu,"
"deadline: %lu, priority: %d",
data->ind,
attr.sched_period / 1000,
attr.sched_runtime / 1000,
attr.sched_deadline / 1000,
attr.sched_priority
);
"deadline: %lu, priority: %d",
data->ind,
attr.sched_period / 1000,
attr.sched_runtime / 1000,
attr.sched_deadline / 1000,
attr.sched_priority); ret = sched_setattr(tid, &attr, flags); if (ret != 0) {
@@ -306,15 +316,17 @@ void *thread_body(void *arg)
if (opts.ftrace) log_ftrace(ft_data.marker_fd, "[%d] starts", data->ind);
clock_gettime(CLOCK_MONOTONIC, &t);
t_next = t;
data->deadline = timespec_add(&t, &data->deadline);
clock_gettime(CLOCK_MONOTONIC, &t_now);
t_next = t_now;
data->deadline = timespec_add(&t_now, &data->deadline); while (continue_running) { 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);
clock_gettime(CLOCK_MONOTONIC, &t_start); run(data->ind, &data->min_et, &data->max_et, data->blockages, data->nblockages);
@@ -328,6 +340,7 @@ void *thread_body(void *arg) curr_timing = &timings[i]; else 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);
@@ -339,14 +352,15 @@ void *thread_body(void *arg) curr_timing->deadline = timespec_to_usec(&data->deadline); curr_timing->duration = timespec_to_usec(&t_diff); curr_timing->slack = timespec_to_lusec(&t_slack);
#ifdef AQUOSA if (data->sched_policy == aquosa) { curr_timing->budget = data->params.Q; qres_get_exec_time(data->sid,
&abs_used_budget,
NULL);
&abs_used_budget,
NULL); curr_timing->used_budget =
abs_used_budget - prev_abs_used_budget;
abs_used_budget - prev_abs_used_budget; prev_abs_used_budget = abs_used_budget; } else {
@@ -359,9 +373,11 @@ void *thread_body(void *arg)
t_next = timespec_add(&t_next, &data->period); data->deadline = timespec_add(&data->deadline, &data->period);
if (opts.ftrace) log_ftrace(ft_data.marker_fd, "[%d] end loop %d", data->ind, i);
if (curr_timing->slack < 0 && opts.die_on_dmiss) { log_critical("[%d] DEADLINE MISS !!!", data->ind); if (opts.ftrace)
@@ -370,7 +386,11 @@ void *thread_body(void *arg) shutdown(SIGTERM); goto exit_miss; }
clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &t_next, NULL);
clock_gettime(CLOCK_MONOTONIC, &t_now);
if (timespec_lower(&t_now, &t_next))
clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &t_next, NULL);
Can you explain, maybe in a separate patch, why we need this change?
To be honest i can't remember the root cause of such change. I would have say to not sleep if we have run longer than expected but clock_nanosleep handles such situation.
i++; }
@@ -393,18 +413,17 @@ exit_miss: log_ftrace(ft_data.marker_fd, "[%d] exiting", data->ind); log_notice("[%d] Exiting.", data->ind); fclose(data->log_handler);
#ifdef AQUOSA if (data->sched_policy == aquosa) { qres_destroy_server(data->sid); qres_cleanup(); } #endif
pthread_exit(NULL);
}
-/* parse a thread token in the form $period:$exec:$deadline:$policy:$prio and
- fills the thread_data structure
- */
int main(int argc, char* argv[]) { @@ -416,6 +435,7 @@ int main(int argc, char* argv[])
parse_command_line(argc, argv, &opts);
/* allocated threads */ nthreads = opts.nthreads; threads = malloc(nthreads * sizeof(pthread_t));
@@ -425,7 +445,7 @@ int main(int argc, char* argv[]) signal(SIGHUP, shutdown); signal(SIGINT, shutdown);
/* if using ftrace open trace and marker fds */
/* if using ftrace, open trace and marker fds */ if (opts.ftrace) { log_notice("configuring ftrace"); strcpy(tmp, ft_data.debugfs);
@@ -454,8 +474,7 @@ int main(int argc, char* argv[]) clock_gettime(CLOCK_MONOTONIC, &t_start);
/* start threads */
for (i = 0; i < nthreads; i++)
{
for (i = 0; i < nthreads; i++) { tdata = &opts.threads_data[i]; if (opts.spacing > 0 ) { /* start the thread, then it will sleep accordingly
@@ -466,19 +485,21 @@ int main(int argc, char* argv[]) } else { tdata->wait_before_start = 0; }
tdata->duration = opts.duration; tdata->main_app_start = t_start; tdata->lock_pages = opts.lock_pages;
#ifdef AQUOSA tdata->fragment = opts.fragment; #endif
if (opts.logdir) { snprintf(tmp, PATH_LENGTH, "%s/%s-%s.log", opts.logdir, opts.logbasename, tdata->name); tdata->log_handler = fopen(tmp, "w");
if (!tdata->log_handler){
if (!tdata->log_handler) { log_error("Cannot open logfile %s", tmp); exit(EXIT_FAILURE); }
@@ -494,8 +515,7 @@ int main(int argc, char* argv[]) }
/* print gnuplot files */
if (opts.logdir && opts.gnuplot)
{
if (opts.logdir && opts.gnuplot) { snprintf(tmp, PATH_LENGTH, "%s/%s-duration.plot", opts.logdir, opts.logbasename); gnuplot_script = fopen(tmp, "w+");
@@ -511,8 +531,7 @@ int main(int argc, char* argv[]) "set ylabel "Exec Time [usec]"\n" "plot ", tmp);
for (i=0; i<nthreads; i++)
{
for (i=0; i<nthreads; i++) { snprintf(tmp, PATH_LENGTH, "%s/%s-duration.plot", opts.logdir, opts.logbasename);
@@ -528,11 +547,12 @@ int main(int argc, char* argv[]) else fprintf(gnuplot_script, ", "); }
fprintf(gnuplot_script, "set terminal wxt\nreplot\n"); fclose(gnuplot_script); snprintf(tmp, PATH_LENGTH, "%s/%s-slack.plot",
opts.logdir, opts.logbasename);
opts.logdir, opts.logbasename); gnuplot_script = fopen(tmp, "w+"); snprintf(tmp, PATH_LENGTH, "%s-slack.eps", opts.logbasename);
@@ -547,8 +567,7 @@ int main(int argc, char* argv[]) "set ylabel "Slack/Tardiness [usec]"\n" "plot ", tmp);
for (i=0; i < nthreads; i++)
{
for (i=0; i < nthreads; i++) { fprintf(gnuplot_script, "\"%s-%s.log\" u ($5/1000):10 w l" " title \"thread [%s] (%s)\"",
@@ -562,19 +581,19 @@ int main(int argc, char* argv[]) fprintf(gnuplot_script, ", ");
}
fprintf(gnuplot_script, "set terminal wxt\nreplot\n"); fclose(gnuplot_script); }
if (opts.duration > 0)
{
if (opts.duration > 0) { sleep(opts.duration); if (opts.ftrace) log_ftrace(ft_data.marker_fd, "main shutdown\n"); shutdown(SIGTERM); }
for (i = 0; i < nthreads; i++) {
for (i = 0; i < nthreads; i++) { pthread_join(threads[i], NULL); }
diff --git a/src/rt-app_args.c b/src/rt-app_args.c index 36e7e51..49ff749 100644 --- a/src/rt-app_args.c +++ b/src/rt-app_args.c @@ -28,7 +28,7 @@ usage (const char* msg, int ex_code) "rt-app <taskset.json>\nOR\n"); #endif printf("rt-app [options] -t <period>:<exec>[:policy"
"[:CPU affinity[:prio[:deadline]]]] -t ...\n\n");
"[:CPU affinity[:prio[:deadline]]]] -t ...\n\n"); printf("-h, --help\t\t:\tshow this help\n"); printf("-f, --fifo\t\t:\tset default policy for threads to SCHED_FIFO\n"); printf("-r, --rr\t\t:\tset default policy fior threads to SCHED_RR\n");
@@ -81,6 +81,7 @@ parse_thread_args(char *arg, int idx, thread_data_t *tdata, policy_t def_policy) token = strtok(str, ":"); tdata->name = malloc(sizeof(char) * 5); tdata->ind = idx;
/* default name for command line threads */ snprintf(tdata->name, 1, "t%d", tdata->ind); tdata->sched_prio = DEFAULT_THREAD_PRIORITY;
@@ -105,10 +106,10 @@ parse_thread_args(char *arg, int idx, thread_data_t *tdata, policy_t def_policy) //TODO: add support for max_et somehow if (exec > period) usage("Exec time cannot be greater than"
" period.", EXIT_INV_COMMANDLINE);
" period.", EXIT_INV_COMMANDLINE); if (exec <= 0 ) usage("Cannot set negative exec time",
EXIT_INV_COMMANDLINE);
EXIT_INV_COMMANDLINE); tdata->min_et = usec_to_timespec(exec); tdata->max_et = usec_to_timespec(exec); i++;
@@ -173,6 +174,7 @@ parse_thread_args(char *arg, int idx, thread_data_t *tdata, policy_t def_policy) } token = strtok(NULL, ":"); }
if ( i < 2 ) { printf("Period and exec time are mandatory\n"); exit(EXIT_INV_COMMANDLINE);
@@ -224,25 +226,27 @@ parse_command_line_options(int argc, char **argv, rtapp_options_t *opts) #ifdef AQUOSA opts->fragment = 1; #endif
static struct option long_options[] = {
{"help", 0, 0, 'h'},
{"fifo", 0, 0, 'f'},
{"rr", 0, 0, 'r'},
{"thread", 1, 0, 't'},
{"spacing", 1, 0, 's'},
{"logdir", 1, 0, 'l'},
{"baselog", 1, 0, 'b'},
{"gnuplot", 1, 0, 'G'},
{"duration", 1, 0, 'D'},
{"ftrace", 0, 0, 'T'},
{"pi_enabled", 0, 0, 'T'},
{"die_on_dmiss", 0, 0, 'M'},
{"help", 0, 0, 'h'},
{"fifo", 0, 0, 'f'},
{"rr", 0, 0, 'r'},
{"thread", 1, 0, 't'},
{"spacing", 1, 0, 's'},
{"logdir", 1, 0, 'l'},
{"baselog", 1, 0, 'b'},
{"gnuplot", 1, 0, 'G'},
{"duration", 1, 0, 'D'},
{"ftrace", 0, 0, 'T'},
{"pi_enabled", 0, 0, 'T'},
{"die_on_dmiss", 0, 0, 'M'},
#ifdef AQUOSA
{"qos", 0, 0, 'q'},
{"frag",1, 0, 'g'},
{"qos", 0, 0, 'q'},
{"frag",1, 0, 'g'},
#endif
{0, 0, 0, 0}
};
{0, 0, 0, 0}
};
#ifdef AQUOSA while (( ch = getopt_long(argc,argv,"D:GKhfrb:s:l:qg:t:TM", long_options, &longopt_idx)) != -1) @@ -259,13 +263,13 @@ parse_command_line_options(int argc, char **argv, rtapp_options_t *opts) case 'f': if (opts->policy != other) usage("Cannot set multiple policies",
EXIT_INV_COMMANDLINE);
EXIT_INV_COMMANDLINE); opts->policy = fifo; break; case 'r': if (opts->policy != other) usage("Cannot set multiple policies",
EXIT_INV_COMMANDLINE);
EXIT_INV_COMMANDLINE); opts->policy = rr; break; case 'b':
@@ -277,26 +281,26 @@ parse_command_line_options(int argc, char **argv, rtapp_options_t *opts) opts->spacing = strtol(optarg, NULL, 0); if (opts->spacing < 0) usage("Cannot set negative spacing",
EXIT_INV_COMMANDLINE);
EXIT_INV_COMMANDLINE); break; case 'l': opts->logdir = strdup(optarg); lstat(opts->logdir, &dirstat); if (! S_ISDIR(dirstat.st_mode)) usage("Cannot stat log directory",
EXIT_INV_COMMANDLINE);
EXIT_INV_COMMANDLINE); break; case 't': if (opts->nthreads > 0) { opts->threads_data = realloc(
opts->threads_data,
(opts->nthreads+1) * \
opts->threads_data,
(opts->nthreads+1) * \ sizeof(thread_data_t)); } parse_thread_args(optarg, opts->nthreads,
&opts->threads_data[opts->nthreads],
opts->policy);
&opts->threads_data[opts->nthreads],
opts->policy); opts->nthreads++; break; case 'G':
@@ -306,7 +310,7 @@ parse_command_line_options(int argc, char **argv, rtapp_options_t *opts) opts->duration = strtol(optarg, NULL, 10); if (opts->duration < 0) usage("Cannot set negative duration",
EXIT_INV_COMMANDLINE);
EXIT_INV_COMMANDLINE); break; case 'K': opts->lock_pages = 0;
@@ -324,26 +328,25 @@ parse_command_line_options(int argc, char **argv, rtapp_options_t *opts) case 'q': if (opts->policy != other) usage("Cannot set multiple policies",
EXIT_INV_COMMANDLINE);
EXIT_INV_COMMANDLINE); opts->policy = aquosa; break; case 'g': opts->fragment = strtol(optarg, NULL, 10); if (opts->fragment < 1 || opts->fragment > 16) usage("Fragment divisor must be between"
"1 and 16", EXIT_INV_COMMANDLINE);
"1 and 16", EXIT_INV_COMMANDLINE); break;
#endif default: log_error("Invalid option %c", ch); usage(NULL, EXIT_INV_COMMANDLINE);
}
}
if ( opts->nthreads < 1) usage("You have to set parameters for at least one thread",
EXIT_INV_COMMANDLINE);
EXIT_INV_COMMANDLINE);
}
@@ -351,18 +354,20 @@ void parse_command_line(int argc, char **argv, rtapp_options_t *opts) { #ifdef JSON
struct stat config_file_stat;
if (argc < 2) usage(NULL, EXIT_SUCCESS);
struct stat config_file_stat;
if (stat(argv[1], &config_file_stat) == 0) { parse_config(argv[1], opts); return;
}
else if (strcmp(argv[1], "-") == 0) {
} else if (strcmp(argv[1], "-") == 0) { parse_config_stdin(opts); return; }
#endif
parse_command_line_options(argc, argv, opts); opts->resources = NULL; opts->nresources = 0;
diff --git a/src/rt-app_parse_config.c b/src/rt-app_parse_config.c index 4d8bff8..7411b45 100644 --- a/src/rt-app_parse_config.c +++ b/src/rt-app_parse_config.c @@ -246,7 +246,6 @@ serialize_acl(rtapp_resource_access_list_t **acl, /* recurse on the rest of resources */ serialize_acl(&(*acl), next_idx, task_resources, resources); }
}
static void @@ -261,10 +260,11 @@ parse_thread_resources(const rtapp_options_t *opts, struct json_object *locks, rtapp_resource_access_list_t *tmp, *head, *last; char debug_msg[512], tmpmsg[512];
data->blockages = malloc(sizeof(rtapp_tasks_resource_list_t) *
json_object_array_length(locks)); data->nblockages = json_object_array_length(locks);
for (i = 0; i< json_object_array_length(locks); i++)
data->blockages = malloc(sizeof(rtapp_tasks_resource_list_t) *
data->nblockages);
for (i = 0; i< data->nblockages; i++)
This might deserve a separate patch as well.
{ res = json_object_array_get_idx(locks, i); if (!json_object_is_type(res, json_type_int)){
@@ -286,6 +286,7 @@ parse_thread_resources(const rtapp_options_t *opts, struct json_object *locks, last = tmp; tmp = tmp->next; } while (tmp != NULL);
/* move first element to list end */ if (last != head) { data->blockages[i].acl = head->next;
@@ -318,7 +319,7 @@ parse_thread_resources(const rtapp_options_t *opts, struct json_object *locks, data->blockages[i].usage = usec_to_timespec(usage_usec); } log_info(PIN "res %d, usage: %d acl: %s", cur_res_idx,
usage_usec, debug_msg);
usage_usec, debug_msg); }
}
@@ -363,6 +364,18 @@ 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);
/* deadline */
dline = get_int_value_from(obj, "deadline", TRUE, period);
if (dline < exec) {
log_critical(PIN2 "Deadline cannot be less than exec time");
exit(EXIT_INV_CONFIG);
}
if (dline > period) {
log_critical(PIN2 "Deadline cannot be greater than period");
exit(EXIT_INV_CONFIG);
}
data->deadline = usec_to_timespec(dline);
Separate patch for this change as well?
/* policy */ policy_to_string(opts->policy, def_policy); policy = get_string_value_from(obj, "policy", TRUE, def_policy);
@@ -376,7 +389,7 @@ parse_thread_data(char *name, struct json_object *obj, int idx,
/* priority */ data->sched_prio = get_int_value_from(obj, "priority", TRUE,
DEFAULT_THREAD_PRIORITY);
DEFAULT_THREAD_PRIORITY); /* deadline */ dline = get_int_value_from(obj, "deadline", TRUE, period);
@@ -502,8 +515,10 @@ get_opts_from_json_object(struct json_object *root, rtapp_options_t *opts) void parse_config_stdin(rtapp_options_t *opts) {
/* read from stdin until EOF, write to temp file and parse
* as a "normal" config file */
/*
* Read from stdin until EOF, write to temp file and parse
* as a "normal" config file
*/ size_t in_length; char buf[JSON_FILE_BUF_SIZE]; struct json_object *js;
diff --git a/src/rt-app_utils.c b/src/rt-app_utils.c index 0c08f02..9719053 100644 --- a/src/rt-app_utils.c +++ b/src/rt-app_utils.c @@ -224,17 +224,20 @@ void ftrace_write(int mark_fd, const char *fmt, ...) va_start(ap, fmt); n = vsnprintf(tmp, BUF_SIZE, fmt, ap); va_end(ap);
/* If it worked return success */ if (n > -1 && n < size) { write(mark_fd, tmp, n); free(tmp); return; }
/* Else try again with more space */ if (n > -1) /* glibc 2.1 */ size = n+1; else /* glibc 2.0 */ size *= 2;
if ((ntmp = realloc(tmp, size)) == NULL) { free(tmp); log_error("Cannot reallocate ftrace buffer");
diff --git a/src/rt-app_utils.h b/src/rt-app_utils.h index c7444dc..ba01f56 100644 --- a/src/rt-app_utils.h +++ b/src/rt-app_utils.h @@ -121,10 +121,10 @@ timespec_to_nsec(struct timespec *ts); #endif
int -string_to_policy(const char *policy_name, policy_t *policy); +policy_to_string(policy_t policy, char *policy_name);
Is this fixing complaints from compiler? Maybe fix it in a separate patch?
yes
Regards, Vincent
int -policy_to_string(policy_t policy, char *policy_name); +string_to_policy(const char *policy_name, policy_t *policy);
void ftrace_write(int mark_fd, const char *fmt, ...); -- 1.9.1
Thanks a lot again for this effort!
Best,
- Juri
Hi Vincent,
On 14/04/15 14:33, Vincent Guittot wrote:
On 13 April 2015 at 15:35, Juri Lelli juri.lelli@arm.com wrote:
Hi,
On 20/03/15 08:45, pi-cheng.chen wrote:
From: Vincent Guittot vincent.guittot@linaro.org
remove useless space align tab remove useless comment
I understand that this patch cleans things up by applying same kind of changes over and over, but I'd still split it in several smaller patches. Maybe a patch for each of the above points?
I have squashed them in one patch in order to minimize the number of patches but they can be split if you prefer
Yes, please. I understand your point, but IMHO it's easier to keep track of changes with littler patches.
Signed-off-by: Vincent Guittot vincent.guittot@linaro.org Signed-off-by: Kevin Hilman khilman@linaro.org
src/rt-app.c | 191 +++++++++++++++++++++++++--------------------- src/rt-app_args.c | 77 ++++++++++--------- src/rt-app_parse_config.c | 31 ++++++-- src/rt-app_utils.c | 3 + src/rt-app_utils.h | 4 +- 5 files changed, 174 insertions(+), 132 deletions(-)
diff --git a/src/rt-app.c b/src/rt-app.c index 3c293e7..4629980 100644 --- a/src/rt-app.c +++ b/src/rt-app.c @@ -27,17 +27,13 @@ static volatile int continue_running; static pthread_t *threads; static int nthreads; rtapp_options_t opts;
static ftrace_data_t ft_data = {
.debugfs = "/debug",
.debugfs = "/sys/kernel/debug",
This maybe deserves a standalone patch, as it doesn't fit in any of the points in the changelog.
.trace_fd = -1, .marker_fd = -1,
};
-static inline unsigned int max_run(int min, int max) -{
return min + (((double) rand()) / RAND_MAX) * (max - min);
-}
This as well.
static inline busywait(struct timespec *to) { struct timespec t_step; @@ -52,27 +48,29 @@ void run(int ind, struct timespec *min, struct timespec *max, rtapp_tasks_resource_list_t *blockages, int nblockages) { int i;
//int m = max_run(timespec_to_msec(min), timespec_to_msec(max));
//struct timespec t_start, t_step, t_exec = msec_to_timespec(m); struct timespec t_start, now, t_exec, t_totexec = *max; rtapp_resource_access_list_t *lock, *last;
/* get the start time */
/* Get the start time */ clock_gettime(CLOCK_THREAD_CPUTIME_ID, &t_start); for (i = 0; i < nblockages; i++) {
/* Lock resources */ lock = blockages[i].acl; while (lock != NULL) { log_debug("[%d] locking %d", ind, lock->res->index); if (opts.ftrace) log_ftrace(ft_data.marker_fd,
"[%d] locking %d",
ind, lock->res->index);
"[%d] locking %d",
ind, lock->res->index);
I generally prefer to keep arguments aligned with the first argument. Can we keep this convention?
i'm fine with this point. This change was to align the arguments (but stay aligned with tab width) which were not aligned with my text editor (which tab width are you using ?)
8-char.
If you want to be aligned, tab should be replaced by withe space
I usually align parameters with spaces after the last tab, but that's only personal taste I guess :).
pthread_mutex_lock(&lock->res->mtx); last = lock; lock = lock->next; }
/* Busy wait */ clock_gettime(CLOCK_THREAD_CPUTIME_ID, &now); t_exec = timespec_add(&now, &blockages[i].usage); log_debug("[%d] busywait for %lu", ind, timespec_to_usec(&blockages[i].usage));
@@ -81,19 +79,21 @@ void run(int ind, struct timespec *min, struct timespec *max, "[%d] busywait for %d", ind, timespec_to_usec(&blockages[i].usage)); busywait(&t_exec);
/* Unlock resources */ lock = last; while (lock != NULL) { log_debug("[%d] unlocking %d", ind, lock->res->index); if (opts.ftrace) log_ftrace(ft_data.marker_fd,
"[%d] unlocking %d",
ind, lock->res->index);
"[%d] unlocking %d",
ind, lock->res->index); pthread_mutex_unlock(&lock->res->mtx); lock = lock->prev; } }
/* compute finish time for CPUTIME_ID clock */
/* Compute finish time for CPUTIME_ID clock */ t_exec = timespec_add(&t_start, &t_totexec); busywait(&t_exec);
} @@ -108,6 +108,7 @@ shutdown(int sig) { pthread_join(threads[i], NULL); }
if (opts.ftrace) { log_notice("stopping ftrace"); log_ftrace(ft_data.marker_fd, "main ends\n");
@@ -115,6 +116,7 @@ shutdown(int sig) close(ft_data.trace_fd); close(ft_data.marker_fd); }
exit(EXIT_SUCCESS);
}
@@ -122,7 +124,7 @@ void *thread_body(void *arg) { thread_data_t *data = (thread_data_t*) arg; struct sched_param param;
struct timespec t, t_next;
struct timespec t_now, t_next;
Maybe a standalone patch, even if it's just renaming?
unsigned long t_start_usec; unsigned long my_duration_usec; int nperiods;
@@ -162,11 +164,11 @@ void *thread_body(void *arg) case rr: case fifo: fprintf(data->log_handler, "# Policy : %s\n",
(data->sched_policy == rr ? "SCHED_RR" : "SCHED_FIFO"));
(data->sched_policy == rr ? "SCHED_RR" : "SCHED_FIFO")); param.sched_priority = data->sched_prio; ret = pthread_setschedparam(pthread_self(),
data->sched_policy,
¶m);
data->sched_policy,
¶m); if (ret != 0) { errno = ret; perror("pthread_setschedparam");
@@ -174,49 +176,56 @@ void *thread_body(void *arg) }
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
);
"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: fprintf(data->log_handler, "# Policy : SCHED_OTHER\n");
/* 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)
);
"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;
#ifdef AQUOSA case aquosa: fprintf(data->log_handler, "# Policy : AQUOSA\n");
data->params.Q_min = round((timespec_to_usec(&data->min_et) * (( 100.0 + data->sched_prio ) / 100)) / (data->fragment * 1.0));
data->params.Q = round((timespec_to_usec(&data->max_et) * (( 100.0 + data->sched_prio ) / 100)) / (data->fragment * 1.0));
data->params.P = round(timespec_to_usec(&data->period) / (data->fragment * 1.0));
data->params.Q_min = round((timespec_to_usec(&data->min_et)
* (( 100.0 + data->sched_prio ) / 100)) / (data->fragment * 1.0));
data->params.Q = round((timespec_to_usec(&data->max_et)
* (( 100.0 + data->sched_prio ) / 100)) / (data->fragment * 1.0));
data->params.P = round(timespec_to_usec(&data->period)
/ (data->fragment * 1.0)); data->params.flags = 0;
log_notice("[%d] Creating QRES Server with Q=%ld, P=%ld",
data->ind,data->params.Q, data->params.P);
data->ind,data->params.Q, data->params.P); qos_chk_ok_exit(qres_init());
qos_chk_ok_exit(qres_create_server(&data->params,
&data->sid));
qos_chk_ok_exit(qres_create_server(&data->params,
&data->sid)); log_notice("[%d] AQuoSA server ID: %d", data->ind, data->sid); log_notice("[%d] attaching thread (deadline: %lu) to server %d",
data->ind,
timespec_to_usec(&data->deadline),
data->sid
);
qos_chk_ok_exit(qres_attach_thread(data->sid, 0, 0));
data->ind,
timespec_to_usec(&data->deadline),
data->sid);
break;
qos_chk_ok_exit(qres_attach_thread(data->sid, 0, 0));
break;
#endif
#ifdef DLSCHED case deadline: fprintf(data->log_handler, "# Policy : SCHED_DEADLINE\n"); @@ -226,16 +235,16 @@ void *thread_body(void *arg) 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;
(timespec_to_nsec(&data->max_et) /100) * BUDGET_OVERP; attr.sched_deadline = timespec_to_nsec(&data->period); attr.sched_period = timespec_to_nsec(&data->period);
break;
break;
#endif
default: log_error("Unknown scheduling policy %d",
data->sched_policy);
data->sched_policy);
exit(EXIT_FAILURE); }
@@ -253,45 +262,46 @@ void *thread_body(void *arg) if (data->wait_before_start > 0) { log_notice("[%d] Waiting %ld usecs... ", data->ind, data->wait_before_start);
clock_gettime(CLOCK_MONOTONIC, &t);
clock_gettime(CLOCK_MONOTONIC, &t_now); t_next = msec_to_timespec(data->wait_before_start);
t_next = timespec_add(&t, &t_next);
t_next = timespec_add(&t_now, &t_next); clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &t_next, NULL); log_notice("[%d] Starting...", data->ind); }
/* 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. */ 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));
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)); } fprintf(data->log_handler, "#idx\tperiod\tmin_et\tmax_et\trel_st\tstart"
"\t\tend\t\tdeadline\tdur.\tslack"
"\tBudget\tUsed Budget\n");
"\t\tend\t\tdeadline\tdur.\tslack"
"\tBudget\tUsed Budget\n");
#ifdef DLSCHED
/* TODO find a better way to handle that constraint */ /* * Set the task to SCHED_DEADLINE as far as possible touching its * budget as little as possible for the first iteration. */ if (data->sched_policy == SCHED_DEADLINE) { log_notice("[%d] starting thread with period: %lu, exec: %lu,"
"deadline: %lu, priority: %d",
data->ind,
attr.sched_period / 1000,
attr.sched_runtime / 1000,
attr.sched_deadline / 1000,
attr.sched_priority
);
"deadline: %lu, priority: %d",
data->ind,
attr.sched_period / 1000,
attr.sched_runtime / 1000,
attr.sched_deadline / 1000,
attr.sched_priority); ret = sched_setattr(tid, &attr, flags); if (ret != 0) {
@@ -306,15 +316,17 @@ void *thread_body(void *arg)
if (opts.ftrace) log_ftrace(ft_data.marker_fd, "[%d] starts", data->ind);
clock_gettime(CLOCK_MONOTONIC, &t);
t_next = t;
data->deadline = timespec_add(&t, &data->deadline);
clock_gettime(CLOCK_MONOTONIC, &t_now);
t_next = t_now;
data->deadline = timespec_add(&t_now, &data->deadline); while (continue_running) { 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);
clock_gettime(CLOCK_MONOTONIC, &t_start); run(data->ind, &data->min_et, &data->max_et, data->blockages, data->nblockages);
@@ -328,6 +340,7 @@ void *thread_body(void *arg) curr_timing = &timings[i]; else 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);
@@ -339,14 +352,15 @@ void *thread_body(void *arg) curr_timing->deadline = timespec_to_usec(&data->deadline); curr_timing->duration = timespec_to_usec(&t_diff); curr_timing->slack = timespec_to_lusec(&t_slack);
#ifdef AQUOSA if (data->sched_policy == aquosa) { curr_timing->budget = data->params.Q; qres_get_exec_time(data->sid,
&abs_used_budget,
NULL);
&abs_used_budget,
NULL); curr_timing->used_budget =
abs_used_budget - prev_abs_used_budget;
abs_used_budget - prev_abs_used_budget; prev_abs_used_budget = abs_used_budget; } else {
@@ -359,9 +373,11 @@ void *thread_body(void *arg)
t_next = timespec_add(&t_next, &data->period); data->deadline = timespec_add(&data->deadline, &data->period);
if (opts.ftrace) log_ftrace(ft_data.marker_fd, "[%d] end loop %d", data->ind, i);
if (curr_timing->slack < 0 && opts.die_on_dmiss) { log_critical("[%d] DEADLINE MISS !!!", data->ind); if (opts.ftrace)
@@ -370,7 +386,11 @@ void *thread_body(void *arg) shutdown(SIGTERM); goto exit_miss; }
clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &t_next, NULL);
clock_gettime(CLOCK_MONOTONIC, &t_now);
if (timespec_lower(&t_now, &t_next))
clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &t_next, NULL);
Can you explain, maybe in a separate patch, why we need this change?
To be honest i can't remember the root cause of such change. I would have say to not sleep if we have run longer than expected but clock_nanosleep handles such situation.
Yeah, right. Don't know, but we can still have this as a separate change, though.
i++; }
@@ -393,18 +413,17 @@ exit_miss: log_ftrace(ft_data.marker_fd, "[%d] exiting", data->ind); log_notice("[%d] Exiting.", data->ind); fclose(data->log_handler);
#ifdef AQUOSA if (data->sched_policy == aquosa) { qres_destroy_server(data->sid); qres_cleanup(); } #endif
pthread_exit(NULL);
}
-/* parse a thread token in the form $period:$exec:$deadline:$policy:$prio and
- fills the thread_data structure
- */
int main(int argc, char* argv[]) { @@ -416,6 +435,7 @@ int main(int argc, char* argv[])
parse_command_line(argc, argv, &opts);
/* allocated threads */ nthreads = opts.nthreads; threads = malloc(nthreads * sizeof(pthread_t));
@@ -425,7 +445,7 @@ int main(int argc, char* argv[]) signal(SIGHUP, shutdown); signal(SIGINT, shutdown);
/* if using ftrace open trace and marker fds */
/* if using ftrace, open trace and marker fds */ if (opts.ftrace) { log_notice("configuring ftrace"); strcpy(tmp, ft_data.debugfs);
@@ -454,8 +474,7 @@ int main(int argc, char* argv[]) clock_gettime(CLOCK_MONOTONIC, &t_start);
/* start threads */
for (i = 0; i < nthreads; i++)
{
for (i = 0; i < nthreads; i++) { tdata = &opts.threads_data[i]; if (opts.spacing > 0 ) { /* start the thread, then it will sleep accordingly
@@ -466,19 +485,21 @@ int main(int argc, char* argv[]) } else { tdata->wait_before_start = 0; }
tdata->duration = opts.duration; tdata->main_app_start = t_start; tdata->lock_pages = opts.lock_pages;
#ifdef AQUOSA tdata->fragment = opts.fragment; #endif
if (opts.logdir) { snprintf(tmp, PATH_LENGTH, "%s/%s-%s.log", opts.logdir, opts.logbasename, tdata->name); tdata->log_handler = fopen(tmp, "w");
if (!tdata->log_handler){
if (!tdata->log_handler) { log_error("Cannot open logfile %s", tmp); exit(EXIT_FAILURE); }
@@ -494,8 +515,7 @@ int main(int argc, char* argv[]) }
/* print gnuplot files */
if (opts.logdir && opts.gnuplot)
{
if (opts.logdir && opts.gnuplot) { snprintf(tmp, PATH_LENGTH, "%s/%s-duration.plot", opts.logdir, opts.logbasename); gnuplot_script = fopen(tmp, "w+");
@@ -511,8 +531,7 @@ int main(int argc, char* argv[]) "set ylabel "Exec Time [usec]"\n" "plot ", tmp);
for (i=0; i<nthreads; i++)
{
for (i=0; i<nthreads; i++) { snprintf(tmp, PATH_LENGTH, "%s/%s-duration.plot", opts.logdir, opts.logbasename);
@@ -528,11 +547,12 @@ int main(int argc, char* argv[]) else fprintf(gnuplot_script, ", "); }
fprintf(gnuplot_script, "set terminal wxt\nreplot\n"); fclose(gnuplot_script); snprintf(tmp, PATH_LENGTH, "%s/%s-slack.plot",
opts.logdir, opts.logbasename);
opts.logdir, opts.logbasename); gnuplot_script = fopen(tmp, "w+"); snprintf(tmp, PATH_LENGTH, "%s-slack.eps", opts.logbasename);
@@ -547,8 +567,7 @@ int main(int argc, char* argv[]) "set ylabel "Slack/Tardiness [usec]"\n" "plot ", tmp);
for (i=0; i < nthreads; i++)
{
for (i=0; i < nthreads; i++) { fprintf(gnuplot_script, "\"%s-%s.log\" u ($5/1000):10 w l" " title \"thread [%s] (%s)\"",
@@ -562,19 +581,19 @@ int main(int argc, char* argv[]) fprintf(gnuplot_script, ", ");
}
fprintf(gnuplot_script, "set terminal wxt\nreplot\n"); fclose(gnuplot_script); }
if (opts.duration > 0)
{
if (opts.duration > 0) { sleep(opts.duration); if (opts.ftrace) log_ftrace(ft_data.marker_fd, "main shutdown\n"); shutdown(SIGTERM); }
for (i = 0; i < nthreads; i++) {
for (i = 0; i < nthreads; i++) { pthread_join(threads[i], NULL); }
diff --git a/src/rt-app_args.c b/src/rt-app_args.c index 36e7e51..49ff749 100644 --- a/src/rt-app_args.c +++ b/src/rt-app_args.c @@ -28,7 +28,7 @@ usage (const char* msg, int ex_code) "rt-app <taskset.json>\nOR\n"); #endif printf("rt-app [options] -t <period>:<exec>[:policy"
"[:CPU affinity[:prio[:deadline]]]] -t ...\n\n");
"[:CPU affinity[:prio[:deadline]]]] -t ...\n\n"); printf("-h, --help\t\t:\tshow this help\n"); printf("-f, --fifo\t\t:\tset default policy for threads to SCHED_FIFO\n"); printf("-r, --rr\t\t:\tset default policy fior threads to SCHED_RR\n");
@@ -81,6 +81,7 @@ parse_thread_args(char *arg, int idx, thread_data_t *tdata, policy_t def_policy) token = strtok(str, ":"); tdata->name = malloc(sizeof(char) * 5); tdata->ind = idx;
/* default name for command line threads */ snprintf(tdata->name, 1, "t%d", tdata->ind); tdata->sched_prio = DEFAULT_THREAD_PRIORITY;
@@ -105,10 +106,10 @@ parse_thread_args(char *arg, int idx, thread_data_t *tdata, policy_t def_policy) //TODO: add support for max_et somehow if (exec > period) usage("Exec time cannot be greater than"
" period.", EXIT_INV_COMMANDLINE);
" period.", EXIT_INV_COMMANDLINE); if (exec <= 0 ) usage("Cannot set negative exec time",
EXIT_INV_COMMANDLINE);
EXIT_INV_COMMANDLINE); tdata->min_et = usec_to_timespec(exec); tdata->max_et = usec_to_timespec(exec); i++;
@@ -173,6 +174,7 @@ parse_thread_args(char *arg, int idx, thread_data_t *tdata, policy_t def_policy) } token = strtok(NULL, ":"); }
if ( i < 2 ) { printf("Period and exec time are mandatory\n"); exit(EXIT_INV_COMMANDLINE);
@@ -224,25 +226,27 @@ parse_command_line_options(int argc, char **argv, rtapp_options_t *opts) #ifdef AQUOSA opts->fragment = 1; #endif
static struct option long_options[] = {
{"help", 0, 0, 'h'},
{"fifo", 0, 0, 'f'},
{"rr", 0, 0, 'r'},
{"thread", 1, 0, 't'},
{"spacing", 1, 0, 's'},
{"logdir", 1, 0, 'l'},
{"baselog", 1, 0, 'b'},
{"gnuplot", 1, 0, 'G'},
{"duration", 1, 0, 'D'},
{"ftrace", 0, 0, 'T'},
{"pi_enabled", 0, 0, 'T'},
{"die_on_dmiss", 0, 0, 'M'},
{"help", 0, 0, 'h'},
{"fifo", 0, 0, 'f'},
{"rr", 0, 0, 'r'},
{"thread", 1, 0, 't'},
{"spacing", 1, 0, 's'},
{"logdir", 1, 0, 'l'},
{"baselog", 1, 0, 'b'},
{"gnuplot", 1, 0, 'G'},
{"duration", 1, 0, 'D'},
{"ftrace", 0, 0, 'T'},
{"pi_enabled", 0, 0, 'T'},
{"die_on_dmiss", 0, 0, 'M'},
#ifdef AQUOSA
{"qos", 0, 0, 'q'},
{"frag",1, 0, 'g'},
{"qos", 0, 0, 'q'},
{"frag",1, 0, 'g'},
#endif
{0, 0, 0, 0}
};
{0, 0, 0, 0}
};
#ifdef AQUOSA while (( ch = getopt_long(argc,argv,"D:GKhfrb:s:l:qg:t:TM", long_options, &longopt_idx)) != -1) @@ -259,13 +263,13 @@ parse_command_line_options(int argc, char **argv, rtapp_options_t *opts) case 'f': if (opts->policy != other) usage("Cannot set multiple policies",
EXIT_INV_COMMANDLINE);
EXIT_INV_COMMANDLINE); opts->policy = fifo; break; case 'r': if (opts->policy != other) usage("Cannot set multiple policies",
EXIT_INV_COMMANDLINE);
EXIT_INV_COMMANDLINE); opts->policy = rr; break; case 'b':
@@ -277,26 +281,26 @@ parse_command_line_options(int argc, char **argv, rtapp_options_t *opts) opts->spacing = strtol(optarg, NULL, 0); if (opts->spacing < 0) usage("Cannot set negative spacing",
EXIT_INV_COMMANDLINE);
EXIT_INV_COMMANDLINE); break; case 'l': opts->logdir = strdup(optarg); lstat(opts->logdir, &dirstat); if (! S_ISDIR(dirstat.st_mode)) usage("Cannot stat log directory",
EXIT_INV_COMMANDLINE);
EXIT_INV_COMMANDLINE); break; case 't': if (opts->nthreads > 0) { opts->threads_data = realloc(
opts->threads_data,
(opts->nthreads+1) * \
opts->threads_data,
(opts->nthreads+1) * \ sizeof(thread_data_t)); } parse_thread_args(optarg, opts->nthreads,
&opts->threads_data[opts->nthreads],
opts->policy);
&opts->threads_data[opts->nthreads],
opts->policy); opts->nthreads++; break; case 'G':
@@ -306,7 +310,7 @@ parse_command_line_options(int argc, char **argv, rtapp_options_t *opts) opts->duration = strtol(optarg, NULL, 10); if (opts->duration < 0) usage("Cannot set negative duration",
EXIT_INV_COMMANDLINE);
EXIT_INV_COMMANDLINE); break; case 'K': opts->lock_pages = 0;
@@ -324,26 +328,25 @@ parse_command_line_options(int argc, char **argv, rtapp_options_t *opts) case 'q': if (opts->policy != other) usage("Cannot set multiple policies",
EXIT_INV_COMMANDLINE);
EXIT_INV_COMMANDLINE); opts->policy = aquosa; break; case 'g': opts->fragment = strtol(optarg, NULL, 10); if (opts->fragment < 1 || opts->fragment > 16) usage("Fragment divisor must be between"
"1 and 16", EXIT_INV_COMMANDLINE);
"1 and 16", EXIT_INV_COMMANDLINE); break;
#endif default: log_error("Invalid option %c", ch); usage(NULL, EXIT_INV_COMMANDLINE);
}
}
if ( opts->nthreads < 1) usage("You have to set parameters for at least one thread",
EXIT_INV_COMMANDLINE);
EXIT_INV_COMMANDLINE);
}
@@ -351,18 +354,20 @@ void parse_command_line(int argc, char **argv, rtapp_options_t *opts) { #ifdef JSON
struct stat config_file_stat;
if (argc < 2) usage(NULL, EXIT_SUCCESS);
struct stat config_file_stat;
if (stat(argv[1], &config_file_stat) == 0) { parse_config(argv[1], opts); return;
}
else if (strcmp(argv[1], "-") == 0) {
} else if (strcmp(argv[1], "-") == 0) { parse_config_stdin(opts); return; }
#endif
parse_command_line_options(argc, argv, opts); opts->resources = NULL; opts->nresources = 0;
diff --git a/src/rt-app_parse_config.c b/src/rt-app_parse_config.c index 4d8bff8..7411b45 100644 --- a/src/rt-app_parse_config.c +++ b/src/rt-app_parse_config.c @@ -246,7 +246,6 @@ serialize_acl(rtapp_resource_access_list_t **acl, /* recurse on the rest of resources */ serialize_acl(&(*acl), next_idx, task_resources, resources); }
}
static void @@ -261,10 +260,11 @@ parse_thread_resources(const rtapp_options_t *opts, struct json_object *locks, rtapp_resource_access_list_t *tmp, *head, *last; char debug_msg[512], tmpmsg[512];
data->blockages = malloc(sizeof(rtapp_tasks_resource_list_t) *
json_object_array_length(locks)); data->nblockages = json_object_array_length(locks);
for (i = 0; i< json_object_array_length(locks); i++)
data->blockages = malloc(sizeof(rtapp_tasks_resource_list_t) *
data->nblockages);
for (i = 0; i< data->nblockages; i++)
This might deserve a separate patch as well.
{ res = json_object_array_get_idx(locks, i); if (!json_object_is_type(res, json_type_int)){
@@ -286,6 +286,7 @@ parse_thread_resources(const rtapp_options_t *opts, struct json_object *locks, last = tmp; tmp = tmp->next; } while (tmp != NULL);
/* move first element to list end */ if (last != head) { data->blockages[i].acl = head->next;
@@ -318,7 +319,7 @@ parse_thread_resources(const rtapp_options_t *opts, struct json_object *locks, data->blockages[i].usage = usec_to_timespec(usage_usec); } log_info(PIN "res %d, usage: %d acl: %s", cur_res_idx,
usage_usec, debug_msg);
usage_usec, debug_msg); }
}
@@ -363,6 +364,18 @@ 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);
/* deadline */
dline = get_int_value_from(obj, "deadline", TRUE, period);
if (dline < exec) {
log_critical(PIN2 "Deadline cannot be less than exec time");
exit(EXIT_INV_CONFIG);
}
if (dline > period) {
log_critical(PIN2 "Deadline cannot be greater than period");
exit(EXIT_INV_CONFIG);
}
data->deadline = usec_to_timespec(dline);
Separate patch for this change as well?
/* policy */ policy_to_string(opts->policy, def_policy); policy = get_string_value_from(obj, "policy", TRUE, def_policy);
@@ -376,7 +389,7 @@ parse_thread_data(char *name, struct json_object *obj, int idx,
/* priority */ data->sched_prio = get_int_value_from(obj, "priority", TRUE,
DEFAULT_THREAD_PRIORITY);
DEFAULT_THREAD_PRIORITY); /* deadline */ dline = get_int_value_from(obj, "deadline", TRUE, period);
@@ -502,8 +515,10 @@ get_opts_from_json_object(struct json_object *root, rtapp_options_t *opts) void parse_config_stdin(rtapp_options_t *opts) {
/* read from stdin until EOF, write to temp file and parse
* as a "normal" config file */
/*
* Read from stdin until EOF, write to temp file and parse
* as a "normal" config file
*/ size_t in_length; char buf[JSON_FILE_BUF_SIZE]; struct json_object *js;
diff --git a/src/rt-app_utils.c b/src/rt-app_utils.c index 0c08f02..9719053 100644 --- a/src/rt-app_utils.c +++ b/src/rt-app_utils.c @@ -224,17 +224,20 @@ void ftrace_write(int mark_fd, const char *fmt, ...) va_start(ap, fmt); n = vsnprintf(tmp, BUF_SIZE, fmt, ap); va_end(ap);
/* If it worked return success */ if (n > -1 && n < size) { write(mark_fd, tmp, n); free(tmp); return; }
/* Else try again with more space */ if (n > -1) /* glibc 2.1 */ size = n+1; else /* glibc 2.0 */ size *= 2;
if ((ntmp = realloc(tmp, size)) == NULL) { free(tmp); log_error("Cannot reallocate ftrace buffer");
diff --git a/src/rt-app_utils.h b/src/rt-app_utils.h index c7444dc..ba01f56 100644 --- a/src/rt-app_utils.h +++ b/src/rt-app_utils.h @@ -121,10 +121,10 @@ timespec_to_nsec(struct timespec *ts); #endif
int -string_to_policy(const char *policy_name, policy_t *policy); +policy_to_string(policy_t policy, char *policy_name);
Is this fixing complaints from compiler? Maybe fix it in a separate patch?
yes
Thanks a lot,
- Juri
Regards, Vincent
int -policy_to_string(policy_t policy, char *policy_name); +string_to_policy(const char *policy_name, policy_t *policy);
void ftrace_write(int mark_fd, const char *fmt, ...); -- 1.9.1
Thanks a lot again for this effort!
Best,
- Juri
From: Vincent Guittot vincent.guittot@linaro.org
use %llu to display 64bits value
Signed-off-by: Vincent Guittot vincent.guittot@linaro.org --- src/rt-app.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/rt-app.c b/src/rt-app.c index 4629980..1095bc8 100644 --- a/src/rt-app.c +++ b/src/rt-app.c @@ -295,8 +295,8 @@ void *thread_body(void *arg) * budget as little as possible for the first iteration. */ if (data->sched_policy == SCHED_DEADLINE) { - log_notice("[%d] starting thread with period: %lu, exec: %lu," - "deadline: %lu, priority: %d", + log_notice("[%d] starting thread with period: %llu, exec: %llu," + "deadline: %llu, priority: %d", data->ind, attr.sched_period / 1000, attr.sched_runtime / 1000,
From: Vincent Guittot vincent.guittot@linaro.org
Add a trace point for end of run loop
Signed-off-by: Vincent Guittot vincent.guittot@linaro.org --- src/rt-app.c | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/src/rt-app.c b/src/rt-app.c index 1095bc8..0ff0c40 100644 --- a/src/rt-app.c +++ b/src/rt-app.c @@ -95,6 +95,11 @@ void run(int ind, struct timespec *min, struct timespec *max,
/* Compute finish time for CPUTIME_ID clock */ t_exec = timespec_add(&t_start, &t_totexec); + log_debug("[%d] busywait for %lu", ind, timespec_to_usec(&t_exec)); + if (opts.ftrace) + log_ftrace(ft_data.marker_fd, + "[%d] busywait for %d", + ind, timespec_to_usec(&t_exec)); busywait(&t_exec); }
From: Vincent Guittot vincent.guittot@linaro.org
Signed-off-by: Vincent Guittot vincent.guittot@linaro.org --- .gitignore | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/.gitignore b/.gitignore index 3097e0a..148b45f 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,12 @@ Makefile Makefile.in README aclocal.m4 +*.txt +*.swp +*.patch +cscope.out +ID +TAGS.LST autom4te.cache/ build-aux/ config.log @@ -24,5 +30,7 @@ src/config.h src/config.h.in src/rt-app src/*.o +src/*.txt +src/*.swp src/stamp-h1
From: Vincent Guittot vincent.guittot@linaro.org
json file is filled in usec, the log displays usec but we used the value as a msec duration. fix that and use it as usec unit
Signed-off-by: Vincent Guittot vincent.guittot@linaro.org --- src/rt-app.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/rt-app.c b/src/rt-app.c index 0ff0c40..78d9a21 100644 --- a/src/rt-app.c +++ b/src/rt-app.c @@ -268,7 +268,7 @@ void *thread_body(void *arg) log_notice("[%d] Waiting %ld usecs... ", data->ind, data->wait_before_start); clock_gettime(CLOCK_MONOTONIC, &t_now); - t_next = msec_to_timespec(data->wait_before_start); + t_next = usec_to_timespec(data->wait_before_start); t_next = timespec_add(&t_now, &t_next); clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME,
From: Vincent Guittot vincent.guittot@linaro.org
don't rely on json object data
Signed-off-by: Vincent Guittot vincent.guittot@linaro.org --- src/rt-app_parse_config.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/src/rt-app_parse_config.c b/src/rt-app_parse_config.c index 7411b45..8139310 100644 --- a/src/rt-app_parse_config.c +++ b/src/rt-app_parse_config.c @@ -407,8 +407,7 @@ parse_thread_data(char *name, struct json_object *obj, int idx, cpuset_obj = get_in_object(obj, "cpus", TRUE); if (cpuset_obj) { assure_type_is(cpuset_obj, obj, "cpus", json_type_array); - data->cpuset_str = json_object_to_json_string(cpuset_obj); - log_info(PIN "key: cpus %s", data->cpuset_str); + data->cpuset_str = strdup(json_object_to_json_string(cpuset_obj)); data->cpuset = malloc(sizeof(cpu_set_t)); cpuset = json_object_get_array(cpuset_obj); CPU_ZERO(data->cpuset); @@ -420,8 +419,8 @@ parse_thread_data(char *name, struct json_object *obj, int idx, } else { data->cpuset_str = strdup("-"); data->cpuset = NULL; - log_info(PIN "key: cpus %s", data->cpuset_str); } + log_info(PIN "key: cpus %s", data->cpuset_str);
/* resources */ resources = get_in_object(obj, "resources", TRUE);
From: Chris Muller christian.muller@linaro.org
Thread name shall match the thread name from configuration file. The name cannot exceed 16 characters.
Signed-off-by: Chris Muller christian.muller@linaro.org --- src/rt-app.c | 6 ++++++ 1 file changed, 6 insertions(+)
diff --git a/src/rt-app.c b/src/rt-app.c index 78d9a21..1f5e969 100644 --- a/src/rt-app.c +++ b/src/rt-app.c @@ -148,6 +148,12 @@ void *thread_body(void *arg) int ret, i = 0; int j;
+ /* set thread name */ + ret = pthread_setname_np(pthread_self(), data->name); + if (ret != 0) { + perror("pthread_setname_np thread name over 16 characters"); + } + /* set thread affinity */ if (data->cpuset != NULL) {
From: Vincent Guittot vincent.guittot@linaro.org
Signed-off-by: Vincent Guittot vincent.guittot@linaro.org --- src/rt-app.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/rt-app.c b/src/rt-app.c index 1f5e969..0c11c72 100644 --- a/src/rt-app.c +++ b/src/rt-app.c @@ -247,7 +247,7 @@ void *thread_body(void *arg) 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->period); + attr.sched_deadline = timespec_to_nsec(&data->deadline); attr.sched_period = timespec_to_nsec(&data->period); break; #endif
From: Vincent Guittot vincent.guittot@linaro.org
Signed-off-by: Vincent Guittot vincent.guittot@linaro.org --- src/rt-app.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-)
diff --git a/src/rt-app.c b/src/rt-app.c index 0c11c72..235c622 100644 --- a/src/rt-app.c +++ b/src/rt-app.c @@ -270,19 +270,6 @@ void *thread_body(void *arg) } }
- if (data->wait_before_start > 0) { - log_notice("[%d] Waiting %ld usecs... ", data->ind, - data->wait_before_start); - clock_gettime(CLOCK_MONOTONIC, &t_now); - t_next = usec_to_timespec(data->wait_before_start); - t_next = timespec_add(&t_now, &t_next); - clock_nanosleep(CLOCK_MONOTONIC, - TIMER_ABSTIME, - &t_next, - NULL); - log_notice("[%d] Starting...", data->ind); - } - /* 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. */ @@ -299,6 +286,20 @@ void *thread_body(void *arg) "\t\tend\t\tdeadline\tdur.\tslack" "\tBudget\tUsed Budget\n");
+ + if (data->wait_before_start > 0) { + log_notice("[%d] Waiting %ld usecs... ", data->ind, + data->wait_before_start); + clock_gettime(CLOCK_MONOTONIC, &t_now); + t_next = usec_to_timespec(data->wait_before_start); + t_next = timespec_add(&t_now, &t_next); + clock_nanosleep(CLOCK_MONOTONIC, + TIMER_ABSTIME, + &t_next, + NULL); + log_notice("[%d] Starting...", data->ind); + } + #ifdef DLSCHED /* TODO find a better way to handle that constraint */ /*
Hi,
On 20/03/15 08:45, pi-cheng.chen wrote:
From: Vincent Guittot vincent.guittot@linaro.org
Signed-off-by: Vincent Guittot vincent.guittot@linaro.org
src/rt-app.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-)
diff --git a/src/rt-app.c b/src/rt-app.c index 0c11c72..235c622 100644 --- a/src/rt-app.c +++ b/src/rt-app.c @@ -270,19 +270,6 @@ void *thread_body(void *arg) } }
- if (data->wait_before_start > 0) {
log_notice("[%d] Waiting %ld usecs... ", data->ind,
data->wait_before_start);
clock_gettime(CLOCK_MONOTONIC, &t_now);
t_next = usec_to_timespec(data->wait_before_start);
t_next = timespec_add(&t_now, &t_next);
clock_nanosleep(CLOCK_MONOTONIC,
TIMER_ABSTIME,
&t_next,
NULL);
log_notice("[%d] Starting...", data->ind);
- }
- /* 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.
@@ -299,6 +286,20 @@ void *thread_body(void *arg) "\t\tend\t\tdeadline\tdur.\tslack" "\tBudget\tUsed Budget\n");
- if (data->wait_before_start > 0) {
log_notice("[%d] Waiting %ld usecs... ", data->ind,
data->wait_before_start);
clock_gettime(CLOCK_MONOTONIC, &t_now);
t_next = usec_to_timespec(data->wait_before_start);
t_next = timespec_add(&t_now, &t_next);
clock_nanosleep(CLOCK_MONOTONIC,
TIMER_ABSTIME,
&t_next,
NULL);
log_notice("[%d] Starting...", data->ind);
- }
#ifdef DLSCHED /* TODO find a better way to handle that constraint */ /*
Can you explain in the changelog why we need this fix and what it changes?
Thanks,
- Juri
On 13 April 2015 at 15:39, Juri Lelli juri.lelli@arm.com wrote:
Hi,
On 20/03/15 08:45, pi-cheng.chen wrote:
From: Vincent Guittot vincent.guittot@linaro.org
Signed-off-by: Vincent Guittot vincent.guittot@linaro.org
src/rt-app.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-)
diff --git a/src/rt-app.c b/src/rt-app.c index 0c11c72..235c622 100644 --- a/src/rt-app.c +++ b/src/rt-app.c @@ -270,19 +270,6 @@ void *thread_body(void *arg) } }
if (data->wait_before_start > 0) {
log_notice("[%d] Waiting %ld usecs... ", data->ind,
data->wait_before_start);
clock_gettime(CLOCK_MONOTONIC, &t_now);
t_next = usec_to_timespec(data->wait_before_start);
t_next = timespec_add(&t_now, &t_next);
clock_nanosleep(CLOCK_MONOTONIC,
TIMER_ABSTIME,
&t_next,
NULL);
log_notice("[%d] Starting...", data->ind);
}
/* 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. */
@@ -299,6 +286,20 @@ void *thread_body(void *arg) "\t\tend\t\tdeadline\tdur.\tslack" "\tBudget\tUsed Budget\n");
if (data->wait_before_start > 0) {
log_notice("[%d] Waiting %ld usecs... ", data->ind,
data->wait_before_start);
clock_gettime(CLOCK_MONOTONIC, &t_now);
t_next = usec_to_timespec(data->wait_before_start);
t_next = timespec_add(&t_now, &t_next);
clock_nanosleep(CLOCK_MONOTONIC,
TIMER_ABSTIME,
&t_next,
NULL);
log_notice("[%d] Starting...", data->ind);
}
#ifdef DLSCHED /* TODO find a better way to handle that constraint */ /*
Can you explain in the changelog why we need this fix and what it changes?
ok. The goal is to gather all configuration, init and allocation of the thread and then start the sequence which can start with a wait for a duration
Vincent
Thanks,
- Juri
On 14/04/15 14:45, Vincent Guittot wrote:
On 13 April 2015 at 15:39, Juri Lelli juri.lelli@arm.com wrote:
Hi,
On 20/03/15 08:45, pi-cheng.chen wrote:
From: Vincent Guittot vincent.guittot@linaro.org
Signed-off-by: Vincent Guittot vincent.guittot@linaro.org
src/rt-app.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-)
diff --git a/src/rt-app.c b/src/rt-app.c index 0c11c72..235c622 100644 --- a/src/rt-app.c +++ b/src/rt-app.c @@ -270,19 +270,6 @@ void *thread_body(void *arg) } }
if (data->wait_before_start > 0) {
log_notice("[%d] Waiting %ld usecs... ", data->ind,
data->wait_before_start);
clock_gettime(CLOCK_MONOTONIC, &t_now);
t_next = usec_to_timespec(data->wait_before_start);
t_next = timespec_add(&t_now, &t_next);
clock_nanosleep(CLOCK_MONOTONIC,
TIMER_ABSTIME,
&t_next,
NULL);
log_notice("[%d] Starting...", data->ind);
}
/* 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. */
@@ -299,6 +286,20 @@ void *thread_body(void *arg) "\t\tend\t\tdeadline\tdur.\tslack" "\tBudget\tUsed Budget\n");
if (data->wait_before_start > 0) {
log_notice("[%d] Waiting %ld usecs... ", data->ind,
data->wait_before_start);
clock_gettime(CLOCK_MONOTONIC, &t_now);
t_next = usec_to_timespec(data->wait_before_start);
t_next = timespec_add(&t_now, &t_next);
clock_nanosleep(CLOCK_MONOTONIC,
TIMER_ABSTIME,
&t_next,
NULL);
log_notice("[%d] Starting...", data->ind);
}
#ifdef DLSCHED /* TODO find a better way to handle that constraint */ /*
Can you explain in the changelog why we need this fix and what it changes?
ok. The goal is to gather all configuration, init and allocation of the thread and then start the sequence which can start with a wait for a duration
Makes sense. Can we please have something like what you just said in the changelog?
Thanks,
- Juri
Vincent
Thanks,
- Juri
From: Vincent Guittot vincent.guittot@linaro.org
Signed-off-by: Vincent Guittot vincent.guittot@linaro.org --- doc/taskset.yml | 53 ----------------------------------------------------- 1 file changed, 53 deletions(-) delete mode 100644 doc/taskset.yml
diff --git a/doc/taskset.yml b/doc/taskset.yml deleted file mode 100644 index 5483dce..0000000 --- a/doc/taskset.yml +++ /dev/null @@ -1,53 +0,0 @@ -# maybe useless to pre-define resources here. -resources: - - m0 - - m1 - - m2 - - m3 - -tasks: - # task name can be "A", "t0", etc. It will only be used in log names - # and in graphs. - t0: - - exec: 10000 # usec, mandatory - period: 10000 # usec, mandatory - deadline: 8000 # usec, optional, default = $period - cpu: 0,1 # optional, default = - (all) - policy: FIFO # optional, default = $global.default_policy - lock: m1 - resources: - - m1: - - duration : 1000 - t1: - - exec: 50000 - period: 100000 - cpu: 1 - policy: DEADLINE - lock: m0,m3,m2 # optional. direct lock order - resources: - - m0: - - duration: 1000 # usec, mandatory if present in $lock list. - access : m2 # optional, list - - m1: - - duration: 100 - access: m3 - - - m2: - - duration: 200 - access: m1 - - - m3: - - duration: 500 - -global: - # here values are set to their defaults, as an example. - - spacing: 0 # msec, optional - default_policy: OTHER # optional - duration: -1 # seconds, optional, -1 means not ending - gnuplot: false # optional - logdir: null # full/relative path to the directory where to store logs - # by default it is not set, so rt-app logs to stdout - baselog: rt-app # basename for thread logs (needs $lodgir != null) - frag: 1 # fragmentation of resource reservations w.r.t thread $period - # i.e. 2 means thread period is twice as big as RR period. -
Hi,
On 20/03/15 08:45, pi-cheng.chen wrote:
From: Vincent Guittot vincent.guittot@linaro.org
Maybe just say that we remove this example as we don't support yaml. Also the subject might be more explicit on this.
Thanks,
- Juri
Signed-off-by: Vincent Guittot vincent.guittot@linaro.org
doc/taskset.yml | 53 ----------------------------------------------------- 1 file changed, 53 deletions(-) delete mode 100644 doc/taskset.yml
diff --git a/doc/taskset.yml b/doc/taskset.yml deleted file mode 100644 index 5483dce..0000000 --- a/doc/taskset.yml +++ /dev/null @@ -1,53 +0,0 @@ -# maybe useless to pre-define resources here. -resources:
- m0
- m1
- m2
- m3
-tasks:
# task name can be "A", "t0", etc. It will only be used in log names
# and in graphs.
t0:
- exec: 10000 # usec, mandatory
period: 10000 # usec, mandatory
deadline: 8000 # usec, optional, default = $period
cpu: 0,1 # optional, default = - (all)
policy: FIFO # optional, default = $global.default_policy
lock: m1
resources:
- m1:
- duration : 1000
t1:
- exec: 50000
period: 100000
cpu: 1
policy: DEADLINE
lock: m0,m3,m2 # optional. direct lock order
resources:
- m0:
- duration: 1000 # usec, mandatory if present in $lock list.
access : m2 # optional, list
- m1:
- duration: 100
access: m3
- m2:
- duration: 200
access: m1
- m3:
- duration: 500
-global:
# here values are set to their defaults, as an example.
- spacing: 0 # msec, optional
default_policy: OTHER # optional
duration: -1 # seconds, optional, -1 means not ending
gnuplot: false # optional
logdir: null # full/relative path to the directory where to store logs
# by default it is not set, so rt-app logs to stdout
baselog: rt-app # basename for thread logs (needs $lodgir != null)
frag: 1 # fragmentation of resource reservations w.r.t thread $period
# i.e. 2 means thread period is twice as big as RR period.
On 13 April 2015 at 15:50, Juri Lelli juri.lelli@arm.com wrote:
Hi,
On 20/03/15 08:45, pi-cheng.chen wrote:
From: Vincent Guittot vincent.guittot@linaro.org
Maybe just say that we remove this example as we don't support yaml. Also the subject might be more explicit on this.
ok
Vincent
Thanks,
- Juri
Signed-off-by: Vincent Guittot vincent.guittot@linaro.org
doc/taskset.yml | 53 ----------------------------------------------------- 1 file changed, 53 deletions(-) delete mode 100644 doc/taskset.yml
diff --git a/doc/taskset.yml b/doc/taskset.yml deleted file mode 100644 index 5483dce..0000000 --- a/doc/taskset.yml +++ /dev/null @@ -1,53 +0,0 @@ -# maybe useless to pre-define resources here. -resources:
- m0
- m1
- m2
- m3
-tasks:
# task name can be "A", "t0", etc. It will only be used in log names
# and in graphs.
t0:
- exec: 10000 # usec, mandatory
period: 10000 # usec, mandatory
deadline: 8000 # usec, optional, default = $period
cpu: 0,1 # optional, default = - (all)
policy: FIFO # optional, default = $global.default_policy
lock: m1
resources:
- m1:
- duration : 1000
t1:
- exec: 50000
period: 100000
cpu: 1
policy: DEADLINE
lock: m0,m3,m2 # optional. direct lock order
resources:
- m0:
- duration: 1000 # usec, mandatory if present in $lock list.
access : m2 # optional, list
- m1:
- duration: 100
access: m3
- m2:
- duration: 200
access: m1
- m3:
- duration: 500
-global:
# here values are set to their defaults, as an example.
- spacing: 0 # msec, optional
default_policy: OTHER # optional
duration: -1 # seconds, optional, -1 means not ending
gnuplot: false # optional
logdir: null # full/relative path to the directory where to store logs
# by default it is not set, so rt-app logs to stdout
baselog: rt-app # basename for thread logs (needs $lodgir != null)
frag: 1 # fragmentation of resource reservations w.r.t thread $period
# i.e. 2 means thread period is twice as big as RR period.
From: Vincent Guittot vincent.guittot@linaro.org
futhermore, some object are used several times
Conflicts: src/rt-app_parse_config.c --- src/rt-app_parse_config.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/src/rt-app_parse_config.c b/src/rt-app_parse_config.c index 8139310..cae5f90 100644 --- a/src/rt-app_parse_config.c +++ b/src/rt-app_parse_config.c @@ -120,7 +120,6 @@ get_int_value_from(struct json_object *where, set_default_if_needed(key, value, have_def, def_value); assure_type_is(value, where, key, json_type_int); i_value = json_object_get_int(value); - json_object_put(value); log_info(PIN "key: %s, value: %d, type <int>", key, i_value); return i_value; } @@ -137,7 +136,6 @@ get_bool_value_from(struct json_object *where, set_default_if_needed(key, value, have_def, def_value); assure_type_is(value, where, key, json_type_boolean); b_value = json_object_get_boolean(value); - json_object_put(value); log_info(PIN "key: %s, value: %d, type <bool>", key, b_value); return b_value; } @@ -158,7 +156,6 @@ get_string_value_from(struct json_object *where, } assure_type_is(value, where, key, json_type_string); s_value = strdup(json_object_get_string(value)); - json_object_put(value); log_info(PIN "key: %s, value: %s, type <string>", key, s_value); return s_value; } @@ -508,6 +505,7 @@ get_opts_from_json_object(struct json_object *root, rtapp_options_t *opts) parse_global(global, opts); parse_resources(resources, opts); parse_tasks(tasks, opts); + json_object_put(tasks);
}
From: Vincent Guittot vincent.guittot@linaro.org
Signed-off-by: Vincent Guittot vincent.guittot@linaro.org Tested-by: Nicolas Pitre nico@linaro.org --- README.in | 7 +------ autogen.sh | 2 +- configure.ac | 17 ++++++++--------- src/Makefile.am | 8 +++----- 4 files changed, 13 insertions(+), 21 deletions(-)
diff --git a/README.in b/README.in index 1883455..9fdaf99 100644 --- a/README.in +++ b/README.in @@ -48,11 +48,6 @@ $ ./configure --with-deadline adds support for SCHED_DEADLINE. There are no compile-time requirements for this feature.
-$ ./configure --with-json - adds support for reading taskset definitions from JSON files - (and from stdin). - json-c (libjson.so.0.0.1) is needed to compile this feature. - $ ./configure --prefix=<directory> installs the compiled program in the given directory
@@ -67,7 +62,7 @@ cross-compiler, and provide the --host option (e.g., --host=arm).
$ rt-app <config_file> where config file is a full/relative path to a json file (look under doc/ for -an example config file) or "-" (without quotes) to read JSON data from stdin. +examples config file) or "-" (without quotes) to read JSON data from stdin.
OR you can use commandline to define the taskset. Keep in mind that on commandline it will never be possible to define resources diff --git a/autogen.sh b/autogen.sh index e06db9e..6887018 100755 --- a/autogen.sh +++ b/autogen.sh @@ -7,5 +7,5 @@ echo "----------------------------------------------------------------" echo "Initialized build system. For a common configuration please run:" echo "----------------------------------------------------------------" echo -echo "./configure --with-deadline --with-json" +echo "./configure --with-deadline" echo diff --git a/configure.ac b/configure.ac index dd1c1aa..f157519 100644 --- a/configure.ac +++ b/configure.ac @@ -40,15 +40,14 @@ AS_IF([test "x$with_deadline" != xno], [AC_DEFINE([DLSCHED], [1], [Define if you have SCHED_DEADLINE support]) ])
-AC_ARG_WITH([json], - [AS_HELP_STRING([--with-json], - [Add support for reading json config file] - ) - ], [], [with_json=no] - ) -AS_IF([test "x$with_json" != "xno"], - [PKG_CHECK_MODULES([LIBJSON], [json-c], [AC_DEFINE([JSON], [1], [Define if you have libjson])]) - ]) +LIBJSON= + AC_CHECK_LIB([json], [json_object_from_file], + [AC_SUBST([LIBJSON], ["-ljson"]) + AC_DEFINE([JSON], [1], [Define if you have libjson]) + ], + [AC_MSG_FAILURE([libjson test failed (use --without-json to disable or install json-c)])], + [-ljson] + )
AM_CONDITIONAL([AMJSON], [ test x$with_json != xno])
diff --git a/src/Makefile.am b/src/Makefile.am index e9a0ee3..600d468 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,9 +1,7 @@ ACLOCAL_AMFLAGS = -I m4 AM_CPPFLAGS = -I$(srcdir)/../libdl/ bin_PROGRAMS = rt-app -rt_app_SOURCES= rt-app_types.h rt-app_args.h rt-app_utils.h rt-app_utils.c rt-app_args.c rt-app.h rt-app.c -if AMJSON +rt_app_SOURCES= rt-app_types.h rt-app_args.h rt-app_utils.h rt-app_utils.c rt-app_args.c rt-app.h rt-app.c rt_app_SOURCES += rt-app_parse_config.h rt-app_parse_config.c -AM_CPPFLAGS += $(LIBJSON_CFLAGS) -endif -rt_app_LDADD = $(QRESLIB) ../libdl/libdl.a $(LIBJSON_LIBS) +rt_app_LDADD = $(QRESLIB) ../libdl/libdl.a $(LIBJSON) +
Hi,
subject is confusing, maybe a squash leftover?
On 20/03/15 08:45, pi-cheng.chen wrote:
From: Vincent Guittot vincent.guittot@linaro.org
Signed-off-by: Vincent Guittot vincent.guittot@linaro.org Tested-by: Nicolas Pitre nico@linaro.org
So, I'm not against removing command line support for starting workloads, and maybe we might have to have that done before we go for unconditional compilation of json. But, I guess that change is part of the second set of patches, right? In that case I guess it is fine to have this here. Maybe we just mention our intents in this changelog.
Thanks,
- Juri
README.in | 7 +------ autogen.sh | 2 +- configure.ac | 17 ++++++++--------- src/Makefile.am | 8 +++----- 4 files changed, 13 insertions(+), 21 deletions(-)
diff --git a/README.in b/README.in index 1883455..9fdaf99 100644 --- a/README.in +++ b/README.in @@ -48,11 +48,6 @@ $ ./configure --with-deadline adds support for SCHED_DEADLINE. There are no compile-time requirements for this feature. -$ ./configure --with-json
- adds support for reading taskset definitions from JSON files
- (and from stdin).
- json-c (libjson.so.0.0.1) is needed to compile this feature.
$ ./configure --prefix=<directory> installs the compiled program in the given directory @@ -67,7 +62,7 @@ cross-compiler, and provide the --host option (e.g., --host=arm). $ rt-app <config_file> where config file is a full/relative path to a json file (look under doc/ for -an example config file) or "-" (without quotes) to read JSON data from stdin. +examples config file) or "-" (without quotes) to read JSON data from stdin. OR you can use commandline to define the taskset. Keep in mind that on commandline it will never be possible to define resources diff --git a/autogen.sh b/autogen.sh index e06db9e..6887018 100755 --- a/autogen.sh +++ b/autogen.sh @@ -7,5 +7,5 @@ echo "----------------------------------------------------------------" echo "Initialized build system. For a common configuration please run:" echo "----------------------------------------------------------------" echo -echo "./configure --with-deadline --with-json" +echo "./configure --with-deadline" echo diff --git a/configure.ac b/configure.ac index dd1c1aa..f157519 100644 --- a/configure.ac +++ b/configure.ac @@ -40,15 +40,14 @@ AS_IF([test "x$with_deadline" != xno], [AC_DEFINE([DLSCHED], [1], [Define if you have SCHED_DEADLINE support]) ]) -AC_ARG_WITH([json],
[AS_HELP_STRING([--with-json],
[Add support for reading json config file]
)
], [], [with_json=no]
)
-AS_IF([test "x$with_json" != "xno"],
[PKG_CHECK_MODULES([LIBJSON], [json-c], [AC_DEFINE([JSON], [1], [Define if you have libjson])])
])
+LIBJSON=
AC_CHECK_LIB([json], [json_object_from_file],
[AC_SUBST([LIBJSON], ["-ljson"])
AC_DEFINE([JSON], [1], [Define if you have libjson])
],
[AC_MSG_FAILURE([libjson test failed (use --without-json to disable or install json-c)])],
[-ljson]
)
AM_CONDITIONAL([AMJSON], [ test x$with_json != xno]) diff --git a/src/Makefile.am b/src/Makefile.am index e9a0ee3..600d468 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,9 +1,7 @@ ACLOCAL_AMFLAGS = -I m4 AM_CPPFLAGS = -I$(srcdir)/../libdl/ bin_PROGRAMS = rt-app -rt_app_SOURCES= rt-app_types.h rt-app_args.h rt-app_utils.h rt-app_utils.c rt-app_args.c rt-app.h rt-app.c -if AMJSON +rt_app_SOURCES= rt-app_types.h rt-app_args.h rt-app_utils.h rt-app_utils.c rt-app_args.c rt-app.h rt-app.c rt_app_SOURCES += rt-app_parse_config.h rt-app_parse_config.c -AM_CPPFLAGS += $(LIBJSON_CFLAGS) -endif -rt_app_LDADD = $(QRESLIB) ../libdl/libdl.a $(LIBJSON_LIBS) +rt_app_LDADD = $(QRESLIB) ../libdl/libdl.a $(LIBJSON)
On 13 April 2015 at 16:01, Juri Lelli juri.lelli@arm.com wrote:
Hi,
subject is confusing, maybe a squash leftover?
On 20/03/15 08:45, pi-cheng.chen wrote:
From: Vincent Guittot vincent.guittot@linaro.org
Signed-off-by: Vincent Guittot vincent.guittot@linaro.org Tested-by: Nicolas Pitre nico@linaro.org
So, I'm not against removing command line support for starting workloads, and maybe we might have to have that done before we go for unconditional compilation of json. But, I guess that change is part of the second set of patches, right? In that case I guess it is fine to have this here. Maybe we just mention our intents in this changelog.
Yes this patch should not be part of this serie. It should be part of another one that will modify rt-app interface and break compatibility interface with legacy
Thanks,
- Juri
README.in | 7 +------ autogen.sh | 2 +- configure.ac | 17 ++++++++--------- src/Makefile.am | 8 +++----- 4 files changed, 13 insertions(+), 21 deletions(-)
diff --git a/README.in b/README.in index 1883455..9fdaf99 100644 --- a/README.in +++ b/README.in @@ -48,11 +48,6 @@ $ ./configure --with-deadline adds support for SCHED_DEADLINE. There are no compile-time requirements for this feature.
-$ ./configure --with-json
adds support for reading taskset definitions from JSON files
(and from stdin).
json-c (libjson.so.0.0.1) is needed to compile this feature.
$ ./configure --prefix=<directory> installs the compiled program in the given directory
@@ -67,7 +62,7 @@ cross-compiler, and provide the --host option (e.g., --host=arm).
$ rt-app <config_file> where config file is a full/relative path to a json file (look under doc/ for -an example config file) or "-" (without quotes) to read JSON data from stdin. +examples config file) or "-" (without quotes) to read JSON data from stdin.
OR you can use commandline to define the taskset. Keep in mind that on commandline it will never be possible to define resources diff --git a/autogen.sh b/autogen.sh index e06db9e..6887018 100755 --- a/autogen.sh +++ b/autogen.sh @@ -7,5 +7,5 @@ echo "----------------------------------------------------------------" echo "Initialized build system. For a common configuration please run:" echo "----------------------------------------------------------------" echo -echo "./configure --with-deadline --with-json" +echo "./configure --with-deadline" echo diff --git a/configure.ac b/configure.ac index dd1c1aa..f157519 100644 --- a/configure.ac +++ b/configure.ac @@ -40,15 +40,14 @@ AS_IF([test "x$with_deadline" != xno], [AC_DEFINE([DLSCHED], [1], [Define if you have SCHED_DEADLINE support]) ])
-AC_ARG_WITH([json],
[AS_HELP_STRING([--with-json],
[Add support for reading json config file]
)
], [], [with_json=no]
)
-AS_IF([test "x$with_json" != "xno"],
[PKG_CHECK_MODULES([LIBJSON], [json-c], [AC_DEFINE([JSON], [1], [Define if you have libjson])])
])
+LIBJSON=
AC_CHECK_LIB([json], [json_object_from_file],
[AC_SUBST([LIBJSON], ["-ljson"])
AC_DEFINE([JSON], [1], [Define if you have libjson])
],
[AC_MSG_FAILURE([libjson test failed (use --without-json to disable or install json-c)])],
[-ljson]
)
AM_CONDITIONAL([AMJSON], [ test x$with_json != xno])
diff --git a/src/Makefile.am b/src/Makefile.am index e9a0ee3..600d468 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,9 +1,7 @@ ACLOCAL_AMFLAGS = -I m4 AM_CPPFLAGS = -I$(srcdir)/../libdl/ bin_PROGRAMS = rt-app -rt_app_SOURCES= rt-app_types.h rt-app_args.h rt-app_utils.h rt-app_utils.c rt-app_args.c rt-app.h rt-app.c -if AMJSON +rt_app_SOURCES= rt-app_types.h rt-app_args.h rt-app_utils.h rt-app_utils.c rt-app_args.c rt-app.h rt-app.c rt_app_SOURCES += rt-app_parse_config.h rt-app_parse_config.c -AM_CPPFLAGS += $(LIBJSON_CFLAGS) -endif -rt_app_LDADD = $(QRESLIB) ../libdl/libdl.a $(LIBJSON_LIBS) +rt_app_LDADD = $(QRESLIB) ../libdl/libdl.a $(LIBJSON)
On 14/04/15 14:50, Vincent Guittot wrote:
On 13 April 2015 at 16:01, Juri Lelli juri.lelli@arm.com wrote:
Hi,
subject is confusing, maybe a squash leftover?
On 20/03/15 08:45, pi-cheng.chen wrote:
From: Vincent Guittot vincent.guittot@linaro.org
Signed-off-by: Vincent Guittot vincent.guittot@linaro.org Tested-by: Nicolas Pitre nico@linaro.org
So, I'm not against removing command line support for starting workloads, and maybe we might have to have that done before we go for unconditional compilation of json. But, I guess that change is part of the second set of patches, right? In that case I guess it is fine to have this here. Maybe we just mention our intents in this changelog.
Yes this patch should not be part of this serie. It should be part of another one that will modify rt-app interface and break compatibility interface with legacy
Ok, this way looks better :).
Thanks,
- Juri
Thanks,
- Juri
README.in | 7 +------ autogen.sh | 2 +- configure.ac | 17 ++++++++--------- src/Makefile.am | 8 +++----- 4 files changed, 13 insertions(+), 21 deletions(-)
diff --git a/README.in b/README.in index 1883455..9fdaf99 100644 --- a/README.in +++ b/README.in @@ -48,11 +48,6 @@ $ ./configure --with-deadline adds support for SCHED_DEADLINE. There are no compile-time requirements for this feature.
-$ ./configure --with-json
adds support for reading taskset definitions from JSON files
(and from stdin).
json-c (libjson.so.0.0.1) is needed to compile this feature.
$ ./configure --prefix=<directory> installs the compiled program in the given directory
@@ -67,7 +62,7 @@ cross-compiler, and provide the --host option (e.g., --host=arm).
$ rt-app <config_file> where config file is a full/relative path to a json file (look under doc/ for -an example config file) or "-" (without quotes) to read JSON data from stdin. +examples config file) or "-" (without quotes) to read JSON data from stdin.
OR you can use commandline to define the taskset. Keep in mind that on commandline it will never be possible to define resources diff --git a/autogen.sh b/autogen.sh index e06db9e..6887018 100755 --- a/autogen.sh +++ b/autogen.sh @@ -7,5 +7,5 @@ echo "----------------------------------------------------------------" echo "Initialized build system. For a common configuration please run:" echo "----------------------------------------------------------------" echo -echo "./configure --with-deadline --with-json" +echo "./configure --with-deadline" echo diff --git a/configure.ac b/configure.ac index dd1c1aa..f157519 100644 --- a/configure.ac +++ b/configure.ac @@ -40,15 +40,14 @@ AS_IF([test "x$with_deadline" != xno], [AC_DEFINE([DLSCHED], [1], [Define if you have SCHED_DEADLINE support]) ])
-AC_ARG_WITH([json],
[AS_HELP_STRING([--with-json],
[Add support for reading json config file]
)
], [], [with_json=no]
)
-AS_IF([test "x$with_json" != "xno"],
[PKG_CHECK_MODULES([LIBJSON], [json-c], [AC_DEFINE([JSON], [1], [Define if you have libjson])])
])
+LIBJSON=
AC_CHECK_LIB([json], [json_object_from_file],
[AC_SUBST([LIBJSON], ["-ljson"])
AC_DEFINE([JSON], [1], [Define if you have libjson])
],
[AC_MSG_FAILURE([libjson test failed (use --without-json to disable or install json-c)])],
[-ljson]
)
AM_CONDITIONAL([AMJSON], [ test x$with_json != xno])
diff --git a/src/Makefile.am b/src/Makefile.am index e9a0ee3..600d468 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,9 +1,7 @@ ACLOCAL_AMFLAGS = -I m4 AM_CPPFLAGS = -I$(srcdir)/../libdl/ bin_PROGRAMS = rt-app -rt_app_SOURCES= rt-app_types.h rt-app_args.h rt-app_utils.h rt-app_utils.c rt-app_args.c rt-app.h rt-app.c -if AMJSON +rt_app_SOURCES= rt-app_types.h rt-app_args.h rt-app_utils.h rt-app_utils.c rt-app_args.c rt-app.h rt-app.c rt_app_SOURCES += rt-app_parse_config.h rt-app_parse_config.c -AM_CPPFLAGS += $(LIBJSON_CFLAGS) -endif -rt_app_LDADD = $(QRESLIB) ../libdl/libdl.a $(LIBJSON_LIBS) +rt_app_LDADD = $(QRESLIB) ../libdl/libdl.a $(LIBJSON)
From: "Ivan T. Ivanov" iivanov@mm-sol.com
Tested-by: Nicolas Pitre nico@linaro.org --- configure.ac | 12 ++++++------ src/rt-app_parse_config.h | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/configure.ac b/configure.ac index f157519..3341259 100644 --- a/configure.ac +++ b/configure.ac @@ -41,13 +41,13 @@ AS_IF([test "x$with_deadline" != xno], ])
LIBJSON= - AC_CHECK_LIB([json], [json_object_from_file], - [AC_SUBST([LIBJSON], ["-ljson"]) - AC_DEFINE([JSON], [1], [Define if you have libjson]) + AC_CHECK_LIB([json-c], [json_object_from_file], + [AC_SUBST([LIBJSON], ["-ljson-c"]) + AC_DEFINE([JSON], [1], [Define if you have libjson-c]) ], - [AC_MSG_FAILURE([libjson test failed (use --without-json to disable or install json-c)])], - [-ljson] - ) + [AC_MSG_FAILURE([libjson-c test failed (use --without-json-c to disable or install json-c)])], + [-ljson-c] + )
AM_CONDITIONAL([AMJSON], [ test x$with_json != xno])
diff --git a/src/rt-app_parse_config.h b/src/rt-app_parse_config.h index 9b89428..45b2bbf 100644 --- a/src/rt-app_parse_config.h +++ b/src/rt-app_parse_config.h @@ -36,7 +36,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #ifdef DLSCHED #include "dl_syscalls.h" #endif -#include <json.h> +#include <json-c/json.h>
#define DEFAULT_THREAD_PRIORITY 10 #define PATH_LENGTH 256
From: Vincent Guittot vincent.guittot@linaro.org
With libjson-c v0.12, json_tokener_errors is no more available. Replace depracated json_object_object_get by json_object_object_get_ex
Signed-off-by: Vincent Guittot vincent.guittot@linaro.org Tested-by: Nicolas Pitre nico@linaro.org --- src/rt-app_parse_config.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/src/rt-app_parse_config.c b/src/rt-app_parse_config.c index cae5f90..2ffc20e 100644 --- a/src/rt-app_parse_config.c +++ b/src/rt-app_parse_config.c @@ -95,10 +95,10 @@ get_in_object(struct json_object *where, int nullable) { struct json_object *to; - to = json_object_object_get(where, what); - if (!nullable && is_error(to)) { - log_critical(PFX "Error while parsing config:\n" PFL - "%s", json_tokener_errors[-(unsigned long)to]); + json_bool ret; + ret = json_object_object_get_ex(where, what, &to); + if (!nullable && !ret) { + log_critical(PFX "Error while parsing config\n" PFL); exit(EXIT_INV_CONFIG); } if (!nullable && strcmp(json_object_to_json_string(to), "null") == 0) { @@ -486,8 +486,7 @@ get_opts_from_json_object(struct json_object *root, rtapp_options_t *opts) struct json_object *global, *tasks, *resources;
if (is_error(root)) { - log_error(PFX "Error while parsing input JSON: %s", - json_tokener_errors[-(unsigned long)root]); + log_error(PFX "Error while parsing input JSON"); exit(EXIT_INV_CONFIG); } log_info(PFX "Successfully parsed input JSON");
On Fri, Mar 20, 2015 at 2:15 PM, pi-cheng.chen pi-cheng.chen@linaro.org wrote:
These series includes fixes/changes that have been done. These patches mainly fixed some typos or moves code but should not change the behavior of rt-app.
Just to make clear, this patchset is directed towards rt-app upstream and a first cut in trying to reduce the delta we have with upstream.
Those patches are also found in the branch: https://git.linaro.org/people/picheng.chen/rt-app.git fix
Chris Muller (1): Update thread name
Ivan T. Ivanov (1): fixup json-c dependencies
Vincent Guittot (12): Minor clean up fix deadline print format consolidate trace and debug point update .gitignore fix inconsistency in delay unit fix cpu affinity string info deadline: set deadline field to deadline parameter reorder the start sequence of threads cleanup of doc directory remove useless json_object_put remove conditional compilation of json Remove useless --with-json rt-app: remove use of deprecated json interface
.gitignore | 8 ++ README.in | 7 +- autogen.sh | 2 +- configure.ac | 17 ++-- doc/taskset.yml | 53 ----------- src/Makefile.am | 8 +- src/rt-app.c | 227 ++++++++++++++++++++++++++-------------------- src/rt-app_args.c | 77 ++++++++-------- src/rt-app_parse_config.c | 51 +++++++---- src/rt-app_parse_config.h | 2 +- src/rt-app_utils.c | 3 + src/rt-app_utils.h | 4 +- 12 files changed, 228 insertions(+), 231 deletions(-) delete mode 100644 doc/taskset.yml
-- 1.9.1
Sched-tools mailing list Sched-tools@lists.linaro.org http://lists.linaro.org/mailman/listinfo/sched-tools
Hi,
On 20/03/15 08:45, pi-cheng.chen wrote:
These series includes fixes/changes that have been done. These patches mainly fixed some typos or moves code but should not change the behavior of rt-app.
Thanks a lot for this! I'm looking forward to review and test them. Unfortunately, I'm quite busy at the moment, so I can't yet start this process. Hope to get back to you soon.
Best,
- Juri
Those patches are also found in the branch: https://git.linaro.org/people/picheng.chen/rt-app.git fix
Chris Muller (1): Update thread name
Ivan T. Ivanov (1): fixup json-c dependencies
Vincent Guittot (12): Minor clean up fix deadline print format consolidate trace and debug point update .gitignore fix inconsistency in delay unit fix cpu affinity string info deadline: set deadline field to deadline parameter reorder the start sequence of threads cleanup of doc directory remove useless json_object_put remove conditional compilation of json Remove useless --with-json rt-app: remove use of deprecated json interface
.gitignore | 8 ++ README.in | 7 +- autogen.sh | 2 +- configure.ac | 17 ++-- doc/taskset.yml | 53 ----------- src/Makefile.am | 8 +- src/rt-app.c | 227 ++++++++++++++++++++++++++-------------------- src/rt-app_args.c | 77 ++++++++-------- src/rt-app_parse_config.c | 51 +++++++---- src/rt-app_parse_config.h | 2 +- src/rt-app_utils.c | 3 + src/rt-app_utils.h | 4 +- 12 files changed, 228 insertions(+), 231 deletions(-) delete mode 100644 doc/taskset.yml