summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorvingu-linaro <vincent.guittot@linaro.org>2016-11-29 12:20:44 +0100
committerGitHub <noreply@github.com>2016-11-29 12:20:44 +0100
commit51a4fba0a17e23fd8dfe7fff23c8cacffb615a6d (patch)
treeafb9de6e7da8507e1c0c19e07ca86a0675f3bb67
parentfa353e15a8b01196a8aee3a7e909004862a20f6f (diff)
parenta1f04ee39b900957538b90f51ade0d71c6a894ff (diff)
Merge pull request #12 from scheduler-tools/merge-arm-deltas
Align Linaro's and ARM's rt-app trees
-rwxr-xr-xdoc/examples/cpufreq_governor_efficiency/dvfs.sh2
-rw-r--r--doc/tutorial.txt139
-rw-r--r--libdl/dl_syscalls.h4
-rw-r--r--src/rt-app.c140
-rw-r--r--src/rt-app_args.h3
-rw-r--r--src/rt-app_parse_config.c13
-rw-r--r--src/rt-app_parse_config.h2
-rw-r--r--src/rt-app_types.h18
-rw-r--r--src/rt-app_utils.c27
-rw-r--r--src/rt-app_utils.h6
10 files changed, 295 insertions, 59 deletions
diff --git a/doc/examples/cpufreq_governor_efficiency/dvfs.sh b/doc/examples/cpufreq_governor_efficiency/dvfs.sh
index 7caee7d..ac69a53 100755
--- a/doc/examples/cpufreq_governor_efficiency/dvfs.sh
+++ b/doc/examples/cpufreq_governor_efficiency/dvfs.sh
@@ -32,7 +32,7 @@ if [ $1 ] ; then
sum=0
loop=0
overrun=0
- for i in $(cat rt-app_$1_run$3us_sleep$4us.log | sed '1d;n;d' | sed '1d' |cut -f 3); do
+ for i in $(cat rt-app_$1_run$3us_sleep$4us.log | sed '1d;n;d' | sed '1d' | awk '{print $3}'); do
loop=$(expr $loop + 1)
sum=$(expr $sum + $i)
if [ $4 -le $i ] ; then
diff --git a/doc/tutorial.txt b/doc/tutorial.txt
index 100a2df..54488a0 100644
--- a/doc/tutorial.txt
+++ b/doc/tutorial.txt
@@ -43,6 +43,31 @@ export ac_cv_lib_json_c_json_object_from_file=yes
./configure --host=aarch64-linux-gnu LDFLAGS=" --static -L<path to parent of json repo>/json-c/. libs/" CFLAGS="-I<path to parent of json repo>" --with-deadline
make
+e.g, with a directory structure like the following:
+
+$ tree -d
+.
+├── autom4te.cache
+├── build
+├── build-aux
+├── doc
+│   └── examples
+│   ├── cpufreq_governor_efficiency
+│   ├── merge
+│   └── tutorial
+├── json-c
+│   ├── autom4te.cache
+│   ├── doc
+│   │   └── html
+│   └── tests
+├── libdl
+├── m4
+└── src
+
+the configure step becomes
+
+./configure --host=aarch64-linux-gnu LDFLAGS="--static -L./../json-c/." CFLAGS="-I./.." --with-deadline
+
**** json file skeleton ****
The json file that describes a workload is made on 3 main objects: tasks,
@@ -112,6 +137,10 @@ Default value is "/dev/null".
used to create IO-bounded and memory-bounded busy loop. Default value is
4194304(4MB).
+* cumulative_slack : Boolean. Accumulate slack (see below) measured during
+ successive timer events in a phase. Default value is False (time between the
+ end of last event and the end of the phase).
+
*** default global object:
"global" : {
"duration" : -1,
@@ -125,7 +154,8 @@ used to create IO-bounded and memory-bounded busy loop. Default value is
"ftrace" : false,
"gnuplot" : false,
"io_device" : "/dev/null"
- "mem_buffer_size" : 4194304
+ "mem_buffer_size" : 4194304,
+ "cumulative_slack" : false
}
**** tasks object ****
@@ -175,6 +205,9 @@ class. Default value is period. The unit is usec.
* cpus: Array of Integer. Define the CPU affinity of the thread. Default
value is all CPUs of the system. An example : "cpus" : [0, 2, 3]
+* delay: Integer. Initial delay before a thread starts execution. The unit
+is usec.
+
* phases: Object. The phases object described TBF
If there is only 1 phase, the sequence of events can be directly put in the
@@ -293,6 +326,70 @@ below:
}
}
+Timers can work with a "relative" or an "absolute" reference. By default they
+work in "relative" mode, but this mode can also be explicity specified as the
+following:
+
+ "phases" : {
+ "phase0" : {
+ "loop" : 10,
+ "run0" : 10000,
+ "timer0" : { "ref" : "unique", "period" : 20000, "mode" : "relative" },
+ }
+
+"relative" mode means that the reference for setting the next timer event is
+relative to the end of the current phase. This in turn means that if, for some
+reason (i.e., clock frequency was too low), events in a certain phase took too
+long to execute and the timer of that phase couldn't actually fire at all, the
+next phase won't be affected. For example:
+
+ +---- + +-----+ +-------------------+-----+ +---
+ |r0 | |r0 | |r0 |r0 | |r0
+ | | | | | | | |
+ o-----------o-----------o-------------------o-----------o------->
+ 0 10 20 30 40 50 60 70 80 100 120
+ ^ ^ ^ ^
+ | | | MISS! |
+ + + + +
+ Timer0 Timer0 Timer0 Timer0
+
+In this example character "o" denotes when phases finish/start. Third
+activation of Timer0 is missed, since r0 executed for more that 20ms. However
+the next phase is not affected as Timer0 was set considering the instant of
+time when the misbehaving r0 finished executing.
+
+"absolute" mode is specified as the following:
+
+ "phases" : {
+ "phase0" : {
+ "loop" : 10,
+ "run0" : 10000,
+ "timer0" : { "ref" : "unique", "period" : 20000, "mode" : "absolute" },
+ }
+
+"absolute" mode means that the reference for setting the next timer event is
+fixed and always consider the starting time of the first phase. This means that
+if, for some reason (i.e., clock frequency was too low), events in a certain
+phase took too long to execute and the timer of that phase couldn't actually
+fire at all, the next phase (and potentially other subsequent phases) _will_ be
+affected. For example, considering again the example above:
+
+ +---- + +-----+ +-------------------+-----+-----+ +---
+ |r0 | |r0 | |r0 |r0 |r0 | |r0
+ | | | | | | | | |
+ o-----------o-----------o-------------------o-----o---------o---->
+ 0 10 20 30 40 50 60 70 80 100 120
+ ^ ^ ^ ^ ^
+ | | | MISS! | MISS! |
+ + + + + +
+ Timer0 Timer0 Timer0 Timer0 Timer0
+
+Third activation of Timer0 is missed, since r0 executed for more that 20ms.
+Even if 4th activation of r0 executes for 10ms (as specified in the
+configuration), 4th Timer0 is still missed because the reference didn't change.
+In this example 5th activation of r0 then managed to recover, but in general it
+depends on how badly a certain phase misbehaves.
+
* lock : String. Lock the mutex defined by the string value.
* unlock : String. Unlock the mutex defined by the string value.
@@ -405,20 +502,42 @@ metrics are:
- run: time spent by the thread to execute the run events
- period: duration to execute the complte phase
- start/end : absolute start and end time of a phase. Same time base is used in
-ftrace
+ ftrace
- rel_st: start time of a phase relatively to the beg of the use case
+- slack: if global option "cumulative_slack" (see above) is false, time between
+ the end of last event and the end of the phase, e.g.
+
+ taskA ...|-- run5 --|- sleep5 -|-- run5--|..timer20.|-- run5 --|- sleep5 -|-- run6 --|.timer20.|
+ <--------------- period 20 --------------> <--------------- period 20 -------------->
+ <-slack5-> <slack4->
+
+ it can also be negative if the execution of a phases' events overshoots the
+ current period, e.g.
+
+ taskA ...|-- run5 --|- sleep5 -|------- run30 ------xxxxxxxxxx|
+ <--------------- period 20 -------------->
+ <slack-5>
+
+ if global option "cumulative_slack" is true, all the intermediate slacks of a
+ phase with multiple timers are accumulated and reported when the phase
+ completes
+
+- c_duration: sum of the configured duration of run/runtime events
+- c_period: sum of the timer(s) period(s)
+- wu_lat: sum of wakeup latencies after timer events
Below is an extract of a log:
# Policy : SCHED_OTHER priority : 0
-#idx perf run period start end rel_st
-0 500000 34382 114492 175604833899 175604948391 785
-0 500000 29786 109863 175604948437 175605058300 115323
-0 500000 26977 107077 175605058336 175605165413 225223
-0 500000 28667 108771 175605165458 175605274229 332344
-0 500000 26644 106745 175605274274 175605381019 441160
-0 500000 26745 106867 175605381061 175605487928 547947
-0 500000 29513 109620 175605487974 175605597595 654860
+#idx perf run period start end rel_st slack c_duration c_period wu_lat
+ 0 92164 19935 98965 504549567051 504549666016 2443 78701 20000 100000 266
+ 0 92164 19408 99952 504549666063 504549766015 101455 80217 20000 100000 265
+ 0 92164 19428 99952 504549766062 504549866014 201454 80199 20000 100000 264
+ 0 92164 19438 99955 504549866060 504549966015 301452 80190 20000 100000 265
+ 0 92164 19446 99952 504549966061 504550066013 401453 80093 20000 100000 264
+ 0 92164 19415 99953 504550066060 504550166013 501452 80215 20000 100000 263
+ 0 92164 19388 99954 504550166059 504550266013 601451 80242 20000 100000 264
+ 0 92164 19444 99956 504550266060 504550366015 701452 80185 20000 100000 265
Some gnuplot files are also created to generate charts based on the log files
for each thread and for each kind of metrics. The format of the chart that
diff --git a/libdl/dl_syscalls.h b/libdl/dl_syscalls.h
index 27cbfe1..ca07503 100644
--- a/libdl/dl_syscalls.h
+++ b/libdl/dl_syscalls.h
@@ -17,7 +17,9 @@
#define __DL_SYSCALLS__
#include <linux/kernel.h>
-#include <linux/unistd.h>
+#define _GNU_SOURCE
+#include <unistd.h>
+#include <sys/syscall.h>
#include <time.h>
#include <linux/types.h>
diff --git a/src/rt-app.c b/src/rt-app.c
index 5283ac7..a7a1eb4 100644
--- a/src/rt-app.c
+++ b/src/rt-app.c
@@ -35,10 +35,11 @@ static int nthreads;
static volatile sig_atomic_t running_threads;
static int p_load;
rtapp_options_t opts;
+static struct timespec t_zero;
+static pthread_barrier_t threads_barrier;
static ftrace_data_t ft_data = {
.debugfs = "/sys/kernel/debug",
- .trace_fd = -1,
.marker_fd = -1,
};
@@ -46,10 +47,11 @@ static ftrace_data_t ft_data = {
* Function: to do some useless operation.
* TODO: improve the waste loop with more heavy functions
*/
-void waste_cpu_cycles(int load_loops)
+void waste_cpu_cycles(unsigned long long load_loops)
{
double param, result;
- double n, i;
+ double n;
+ unsigned long long i;
param = 0.95;
n = 4;
@@ -170,10 +172,27 @@ int calibrate_cpu_cycles(int clock)
}
-static inline loadwait(unsigned long exec)
+static inline unsigned long loadwait(unsigned long exec)
{
unsigned long load_count;
+ unsigned long secs;
+ int i;
+
+ /*
+ * If exec is still too big, let's run it in bursts
+ * so that we don't overflow load_count.
+ */
+ secs = exec / 1000000;
+ for (i = 0; i < secs; i++) {
+ load_count = 1000000000/p_load;
+ waste_cpu_cycles(load_count);
+ exec -= 1000000;
+ }
+
+ /*
+ * Run for the remainig exec (if any).
+ */
load_count = (exec * 1000)/p_load;
waste_cpu_cycles(load_count);
@@ -217,7 +236,8 @@ static void memload(unsigned long count, struct _rtapp_iomem_buf *iomem)
}
static int run_event(event_data_t *event, int dry_run,
- unsigned long *perf, unsigned long *duration, rtapp_resource_t *resources)
+ unsigned long *perf, rtapp_resource_t *resources,
+ struct timespec *t_first, log_data_t *ldata)
{
rtapp_resource_t *rdata = &(resources[event->res]);
rtapp_resource_t *ddata = &(resources[event->dep]);
@@ -267,11 +287,12 @@ static int run_event(event_data_t *event, int dry_run,
{
struct timespec t_start, t_end;
log_debug("run %d ", event->duration);
+ ldata->c_duration += event->duration;
clock_gettime(CLOCK_MONOTONIC, &t_start);
*perf += loadwait(event->duration);
clock_gettime(CLOCK_MONOTONIC, &t_end);
t_end = timespec_sub(&t_end, &t_start);
- *duration += timespec_to_usec(&t_end);
+ ldata->duration += timespec_to_usec(&t_end);
}
break;
case rtapp_runtime:
@@ -280,6 +301,7 @@ static int run_event(event_data_t *event, int dry_run,
int64_t diff_ns;
log_debug("runtime %d ", event->duration);
+ ldata->c_duration += event->duration;
clock_gettime(CLOCK_MONOTONIC, &t_start);
do {
@@ -291,27 +313,39 @@ static int run_event(event_data_t *event, int dry_run,
} while ((diff_ns / 1000) < event->duration);
t_end = timespec_sub(&t_end, &t_start);
- *duration += timespec_to_usec(&t_end);
+ ldata->duration += timespec_to_usec(&t_end);
}
break;
case rtapp_timer:
{
- struct timespec t_period, t_now;
+ struct timespec t_period, t_now, t_wu, t_slack;
log_debug("timer %d ", event->duration);
t_period = usec_to_timespec(event->duration);
+ ldata->c_period += event->duration;
if (rdata->res.timer.init == 0) {
rdata->res.timer.init = 1;
- clock_gettime(CLOCK_MONOTONIC, &rdata->res.timer.t_next);
+ rdata->res.timer.t_next = *t_first;
}
rdata->res.timer.t_next = timespec_add(&rdata->res.timer.t_next, &t_period);
clock_gettime(CLOCK_MONOTONIC, &t_now);
- if (timespec_lower(&t_now, &rdata->res.timer.t_next))
- clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &rdata->res.timer.t_next, NULL);
+ t_slack = timespec_sub(&rdata->res.timer.t_next, &t_now);
+ if (opts.cumulative_slack)
+ ldata->slack += timespec_to_usec_long(&t_slack);
else
- clock_gettime(CLOCK_MONOTONIC, &rdata->res.timer.t_next);
+ ldata->slack = timespec_to_usec_long(&t_slack);
+ if (timespec_lower(&t_now, &rdata->res.timer.t_next)) {
+ clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &rdata->res.timer.t_next, NULL);
+ clock_gettime(CLOCK_MONOTONIC, &t_now);
+ t_wu = timespec_sub(&t_now, &rdata->res.timer.t_next);
+ ldata->wu_latency += timespec_to_usec(&t_wu);
+ } else {
+ if (rdata->res.timer.relative)
+ clock_gettime(CLOCK_MONOTONIC, &rdata->res.timer.t_next);
+ ldata->wu_latency = 0UL;
+ }
}
break;
case rtapp_suspend:
@@ -347,8 +381,11 @@ static int run_event(event_data_t *event, int dry_run,
return lock;
}
-int run(int ind, phase_data_t *pdata, unsigned long *duration,
- rtapp_resource_t *resources)
+int run(int ind,
+ phase_data_t *pdata,
+ rtapp_resource_t *resources,
+ struct timespec *t_first,
+ log_data_t *ldata)
{
event_data_t *events = pdata->events;
int nbevents = pdata->nbevents;
@@ -358,14 +395,15 @@ int run(int ind, phase_data_t *pdata, unsigned long *duration,
for (i = 0; i < nbevents; i++)
{
if (!continue_running && !lock)
- return;
+ return perf;
log_debug("[%d] runs events %d type %d ", ind, i, events[i].type);
if (opts.ftrace)
log_ftrace(ft_data.marker_fd,
"[%d] executing %d",
ind, i);
- lock += run_event(&events[i], !continue_running, &perf, duration, resources);
+ lock += run_event(&events[i], !continue_running, &perf,
+ resources, t_first, ldata);
}
return perf;
@@ -396,10 +434,8 @@ shutdown(int sig)
}
if (opts.ftrace) {
- log_notice("stopping ftrace");
log_ftrace(ft_data.marker_fd, "main ends\n");
- log_ftrace(ft_data.trace_fd, "0");
- close(ft_data.trace_fd);
+ log_notice("deconfiguring ftrace");
close(ft_data.marker_fd);
}
@@ -410,10 +446,11 @@ void *thread_body(void *arg)
{
thread_data_t *data = (thread_data_t*) arg;
phase_data_t *pdata;
+ log_data_t ldata;
struct sched_param param;
- struct timespec t_start, t_end;
+ struct timespec t_start, t_end, t_first;
unsigned long t_start_usec;
- unsigned long perf, duration;
+ long slack;
timing_point_t *curr_timing;
timing_point_t *timings;
timing_point_t tmp_timing;
@@ -536,9 +573,27 @@ void *thread_body(void *arg)
}
}
+ if (data->ind == 0) {
+ /*
+ * Only first thread sets t_zero. Other threads sync with this
+ * timestamp.
+ */
+ clock_gettime(CLOCK_MONOTONIC, &t_zero);
+ if (opts.ftrace)
+ log_ftrace(ft_data.marker_fd,
+ "[%d] sets zero time",
+ data->ind);
+ }
+
+ pthread_barrier_wait(&threads_barrier);
+ t_first = t_zero;
+
log_notice("[%d] starting thread ...\n", data->ind);
- fprintf(data->log_handler, "#idx\tperf\trun\tperiod\tstart\t\tend\t\trel_st\n");
+ fprintf(data->log_handler, "%s %8s %8s %8s %15s %15s %15s %10s %10s %10s %10s\n",
+ "#idx", "perf", "run", "period",
+ "start", "end", "rel_st", "slack",
+ "c_duration", "c_period", "wu_lat");
if (opts.ftrace)
log_ftrace(ft_data.marker_fd, "[%d] starts", data->ind);
@@ -560,6 +615,16 @@ void *thread_body(void *arg)
}
}
#endif
+
+ if (data->delay > 0) {
+ struct timespec delay = usec_to_timespec(data->delay);
+
+ log_debug("initial delay %d ", data->delay);
+ t_first = timespec_add(&t_first, &delay);
+ clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &t_first,
+ NULL);
+ }
+
i = j = loop = idx = 0;
while (continue_running && (i != data->loop)) {
@@ -569,9 +634,10 @@ void *thread_body(void *arg)
log_ftrace(ft_data.marker_fd, "[%d] begins loop %d phase %d step %d", data->ind, i, j, loop);
log_debug("[%d] begins loop %d phase %d step %d", data->ind, i, j, loop);;
- duration = 0;
+ memset(&ldata, 0, sizeof(ldata));
clock_gettime(CLOCK_MONOTONIC, &t_start);
- perf = run(data->ind, pdata, &duration, *(data->resources));
+ ldata.perf = run(data->ind, pdata, *(data->resources),
+ &t_first, &ldata);
clock_gettime(CLOCK_MONOTONIC, &t_end);
if (timings)
@@ -587,10 +653,14 @@ void *thread_body(void *arg)
curr_timing->start_time = timespec_to_usec_ull(&t_start);
curr_timing->end_time = timespec_to_usec_ull(&t_end);
curr_timing->period = timespec_to_usec(&t_diff);
- curr_timing->duration = duration;
- curr_timing->perf = perf;
-
- if (opts.logsize && !timings)
+ curr_timing->duration = ldata.duration;
+ curr_timing->perf = ldata.perf;
+ curr_timing->wu_latency = ldata.wu_latency;
+ curr_timing->slack = ldata.slack;
+ curr_timing->c_period = ldata.c_period;
+ curr_timing->c_duration = ldata.c_duration;
+
+ if (opts.logsize && !timings && continue_running)
log_timing(data->log_handler, curr_timing);
if (opts.ftrace)
@@ -660,7 +730,7 @@ int main(int argc, char* argv[])
/* allocated threads */
nthreads = opts.nthreads;
threads = malloc(nthreads * sizeof(pthread_t));
- running_threads = 0;
+ pthread_barrier_init(&threads_barrier, NULL, nthreads);
/* install a signal handler for proper shutdown */
signal(SIGQUIT, shutdown);
@@ -673,21 +743,14 @@ int main(int argc, char* argv[])
log_notice("configuring ftrace");
strcpy(tmp, ft_data.debugfs);
strcat(tmp, "/tracing/tracing_on");
- ft_data.trace_fd = open(tmp, O_WRONLY);
- if (ft_data.trace_fd < 0) {
- log_error("Cannot open trace_fd file %s", tmp);
- exit(EXIT_FAILURE);
- }
-
strcpy(tmp, ft_data.debugfs);
strcat(tmp, "/tracing/trace_marker");
ft_data.marker_fd = open(tmp, O_WRONLY);
- if (ft_data.trace_fd < 0) {
+ if (ft_data.marker_fd < 0) {
log_error("Cannot open trace_marker file %s", tmp);
exit(EXIT_FAILURE);
}
- log_ftrace(ft_data.trace_fd, "1");
log_ftrace(ft_data.marker_fd, "main creates threads\n");
}
@@ -877,10 +940,7 @@ int main(int argc, char* argv[])
}
if (opts.ftrace) {
- log_notice("stopping ftrace");
log_ftrace(ft_data.marker_fd, "main ends\n");
- log_ftrace(ft_data.trace_fd, "0");
- close(ft_data.trace_fd);
close(ft_data.marker_fd);
}
exit(EXIT_SUCCESS);
diff --git a/src/rt-app_args.h b/src/rt-app_args.h
index 9bbde38..23ba50c 100644
--- a/src/rt-app_args.h
+++ b/src/rt-app_args.h
@@ -36,10 +36,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#ifdef DLSCHED
#include "dl_syscalls.h"
#endif
-
-#ifdef JSON
#include "rt-app_parse_config.h"
-#endif
#define DEFAULT_THREAD_PRIORITY 10
#define PATH_LENGTH 256
diff --git a/src/rt-app_parse_config.c b/src/rt-app_parse_config.c
index c59b562..2b27f64 100644
--- a/src/rt-app_parse_config.c
+++ b/src/rt-app_parse_config.c
@@ -181,6 +181,7 @@ static int init_timer_resource(rtapp_resource_t *data, const rtapp_options_t *op
{
log_info(PIN3 "Init: %s timer", data->name);
data->res.timer.init = 0;
+ data->res.timer.relative = 1;
}
static int init_cond_resource(rtapp_resource_t *data, const rtapp_options_t *opts)
@@ -489,6 +490,11 @@ parse_thread_event_data(char *name, struct json_object *obj,
rdata = &(opts->resources[data->res]);
ddata = &(opts->resources[data->dep]);
+ tmp = get_string_value_from(obj, "mode", TRUE, "relative");
+ if (!strncmp(tmp, "absolute", strlen("absolute")))
+ rdata->res.timer.relative = 0;
+ free(tmp);
+
log_info(PIN2 "type %d target %s [%d] period %d", data->type, rdata->name, rdata->index, data->duration);
return;
}
@@ -689,6 +695,11 @@ parse_thread_data(char *name, struct json_object *obj, int index,
}
log_info(PIN "key: cpus %s", data->cpuset_str);
+ /* initial delay */
+ data->delay = get_int_value_from(obj, "delay", TRUE, 0);
+ if (data->delay < 0)
+ data->delay = 0;
+
/* Get phases */
phases_obj = get_in_object(obj, "phases", TRUE);
if (phases_obj) {
@@ -773,6 +784,7 @@ parse_global(struct json_object *global, rtapp_options_t *opts)
opts->pi_enabled = 0;
opts->io_device = strdup("/dev/null");
opts->mem_buffer_size = DEFAULT_MEM_BUF_SIZE;
+ opts->cumulative_slack = 0;
return;
}
@@ -861,6 +873,7 @@ parse_global(struct json_object *global, rtapp_options_t *opts)
"/dev/null");
opts->mem_buffer_size = get_int_value_from(global, "mem_buffer_size",
TRUE, DEFAULT_MEM_BUF_SIZE);
+ opts->cumulative_slack = get_bool_value_from(global, "cumulative_slack", TRUE, 0);
}
diff --git a/src/rt-app_parse_config.h b/src/rt-app_parse_config.h
index 023cabd..9b0e5fa 100644
--- a/src/rt-app_parse_config.h
+++ b/src/rt-app_parse_config.h
@@ -45,5 +45,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
void
parse_config(const char *filename, rtapp_options_t *opts);
+void
+parse_config_stdin(rtapp_options_t *opts);
#endif // _RTAPP_PARSE_CONFIG_H
diff --git a/src/rt-app_types.h b/src/rt-app_types.h
index 57fb80d..1eb9467 100644
--- a/src/rt-app_types.h
+++ b/src/rt-app_types.h
@@ -87,6 +87,7 @@ struct _rtapp_signal {
struct _rtapp_timer {
struct timespec t_next;
int init;
+ int relative;
};
struct _rtapp_iomem_buf {
@@ -149,6 +150,8 @@ typedef struct _thread_data_t {
char sched_policy_descr[RTAPP_POLICY_DESCR_LENGTH];
int sched_prio;
+ unsigned long delay;
+
#ifdef DLSCHED
struct sched_attr dl_params;
#endif
@@ -160,6 +163,15 @@ typedef struct _ftrace_data_t {
int marker_fd;
} ftrace_data_t;
+typedef struct _log_data_t {
+ unsigned long perf;
+ unsigned long duration;
+ unsigned long wu_latency;
+ unsigned long c_duration;
+ unsigned long c_period;
+ long slack;
+} log_data_t;
+
typedef struct _rtapp_options_t {
int lock_pages;
@@ -184,6 +196,8 @@ typedef struct _rtapp_options_t {
int die_on_dmiss;
int mem_buffer_size;
char *io_device;
+
+ int cumulative_slack;
} rtapp_options_t;
typedef struct _timing_point_t {
@@ -191,6 +205,10 @@ typedef struct _timing_point_t {
unsigned long perf;
unsigned long duration;
unsigned long period;
+ unsigned long c_duration;
+ unsigned long c_period;
+ unsigned long wu_latency;
+ long slack;
__u64 start_time;
__u64 end_time;
__u64 rel_start_time;
diff --git a/src/rt-app_utils.c b/src/rt-app_utils.c
index c4840db..f12f48c 100644
--- a/src/rt-app_utils.c
+++ b/src/rt-app_utils.c
@@ -19,6 +19,8 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+#include <errno.h>
+#include <string.h>
#include "rt-app_utils.h"
unsigned long
@@ -33,6 +35,12 @@ timespec_to_usec_ull(struct timespec *ts)
return llround((ts->tv_sec * 1E9 + ts->tv_nsec) / 1000.0);
}
+long
+timespec_to_usec_long(struct timespec *ts)
+{
+ return round((ts->tv_sec * 1E9 + ts->tv_nsec) / 1000.0);
+}
+
#ifdef DLSCHED
__u64
timespec_to_nsec(struct timespec *ts)
@@ -132,14 +140,18 @@ void
log_timing(FILE *handler, timing_point_t *t)
{
fprintf(handler,
- "%d\t%lu\t%lu\t%lu\t%llu\t%llu\t%llu",
+ "%4d %8lu %8lu %8lu %15llu %15llu %15llu %10ld %10lu %10lu %10lu",
t->ind,
t->perf,
t->duration,
t->period,
t->start_time,
t->end_time,
- t->rel_start_time
+ t->rel_start_time,
+ t->slack,
+ t->c_duration,
+ t->c_period,
+ t->wu_latency
);
fprintf(handler, "\n");
}
@@ -253,7 +265,7 @@ resource_to_string(resource_t resource, char *resource_name)
void ftrace_write(int mark_fd, const char *fmt, ...)
{
va_list ap;
- int n, size = BUF_SIZE;
+ int n, size = BUF_SIZE, ret;
char *tmp, *ntmp;
if (mark_fd < 0) {
@@ -274,8 +286,15 @@ void ftrace_write(int mark_fd, const char *fmt, ...)
/* If it worked return success */
if (n > -1 && n < size) {
- write(mark_fd, tmp, n);
+ ret = write(mark_fd, tmp, n);
free(tmp);
+ if (ret < 0) {
+ log_error("Cannot write mark_fd: %s\n",
+ strerror(errno));
+ exit(EXIT_FAILURE);
+ } else if (ret < n) {
+ log_debug("Cannot write all bytes at once into mark_fd\n");
+ }
return;
}
diff --git a/src/rt-app_utils.h b/src/rt-app_utils.h
index 64f97f6..6a8d921 100644
--- a/src/rt-app_utils.h
+++ b/src/rt-app_utils.h
@@ -28,6 +28,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
+#define _GNU_SOURCE
+#include <unistd.h>
+#include <sys/syscall.h>
#include "rt-app_types.h"
#ifndef LOG_PREFIX
@@ -89,6 +92,9 @@ timespec_to_usec(struct timespec *ts);
unsigned long long
timespec_to_usec_ull(struct timespec *ts);
+long
+timespec_to_usec_long(struct timespec *ts);
+
struct timespec
usec_to_timespec(unsigned long usec);