From: Geunsik Lim <geunsik.lim(a)samsung.com>
when we execute 'make' command, we meet error message as follows.
./rt-app/src/rt-app_parse_config.c:773:
undefined reference to `is_error'
Let's append <json/bits.h> header file into rt-app_parse_config.c
Signed-off-by: Geunsik Lim <geunsik.lim(a)samsung.com>
---
src/rt-app_parse_config.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/rt-app_parse_config.c b/src/rt-app_parse_config.c
index 96e5517..f4ecb61 100644
--- a/src/rt-app_parse_config.c
+++ b/src/rt-app_parse_config.c
@@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-
+#include <json/bits.h>
#include "rt-app_parse_config.h"
#define PFX "[json] "
--
1.7.9.5
-Several minor fixes in the tutorial file
-Remove some compilation warnings
-Reorder and gather the init of data by feature
-Close the log file before exiting the thread body
Signed-off-by: Vincent Guittot <vincent.guittot(a)linaro.org>
---
doc/tutorial.txt | 8 ++++----
src/rt-app.c | 3 ++-
src/rt-app_parse_config.c | 21 +++++++++++----------
3 files changed, 17 insertions(+), 15 deletions(-)
diff --git a/doc/tutorial.txt b/doc/tutorial.txt
index 8341b2e..b2b0971 100644
--- a/doc/tutorial.txt
+++ b/doc/tutorial.txt
@@ -39,8 +39,8 @@ run indefinitly until all threads kill themselves (as an example if a finite
number of loop has been defined in their running pattern) or if a signal
is received to stop the use case.
-* calibration : Text or Integer: A text defines the CPU that will be used to
-calibrate the ns per loop value. "CPU0" is the default value (see run event
+* calibration : String or Integer: A String defines the CPU that will be used
+to calibrate the ns per loop value. "CPU0" is the default value (see run event
section for details about ns per loop value). A integer skips the calibration
step and uses the integer value as ns per loop.
@@ -55,10 +55,10 @@ ensures that your RT thread will not be stalled until a page is moved from swap
to RAM. The lock of the page is only possible for non CFS tasks. Default value
is False.
-* logdir : Text. Path to store the various log files. The default path is
+* logdir : String. Path to store the various log files. The default path is
the current directory (./).
-* log_basename : Text. Prefix used for all log files of the use case.
+* log_basename : String. Prefix used for all log files of the use case.
"rt-app-" is used by default.
* log_size : String or Integer. A Integer defines a fix size in MB of the
diff --git a/src/rt-app.c b/src/rt-app.c
index 805cc35..f14f228 100644
--- a/src/rt-app.c
+++ b/src/rt-app.c
@@ -613,7 +613,7 @@ void *thread_body(void *arg)
log_ftrace(ft_data.marker_fd, "[%d] exiting", data->ind);
log_notice("[%d] Exiting.", data->ind);
-// fclose(data->log_handler);
+ fclose(data->log_handler);
pthread_exit(NULL);
}
@@ -767,6 +767,7 @@ int main(int argc, char* argv[])
"\"%s-%s-%d.log\" u ($5/1000):3 w l"
" title \"thread [%s] (%s)\"",
opts.logbasename, opts.threads_data[i].name,
+ opts.threads_data[i].ind,
opts.threads_data[i].name,
opts.threads_data[i].sched_policy_descr);
diff --git a/src/rt-app_parse_config.c b/src/rt-app_parse_config.c
index 98374cd..f4ac5cf 100644
--- a/src/rt-app_parse_config.c
+++ b/src/rt-app_parse_config.c
@@ -334,7 +334,8 @@ parse_thread_event_data(char *name, struct json_object *obj,
{
rtapp_resource_t *rdata, *ddata;
char unique_name[22];
- const char *ref, *tmp;
+ const char *ref;
+ char *tmp;
int i;
if (!strncmp(name, "run", strlen("run")) ||
@@ -434,23 +435,23 @@ parse_thread_event_data(char *name, struct json_object *obj,
else
data->type = rtapp_sig_and_wait;
- ref = get_string_value_from(obj, "ref", TRUE, "unknown");
- i = get_resource_index(ref, rtapp_wait, opts);
+ tmp = get_string_value_from(obj, "ref", TRUE, "unknown");
+ i = get_resource_index(tmp, rtapp_wait, opts);
/*
* get_string_value_from allocate the string so with have to free it
* once useless
*/
- free(ref);
+ free(tmp);
data->res = i;
- ref = get_string_value_from(obj, "mutex", TRUE, "unknown");
- i = get_resource_index(ref, rtapp_mutex, opts);
+ tmp = get_string_value_from(obj, "mutex", TRUE, "unknown");
+ i = get_resource_index(tmp, rtapp_mutex, opts);
/*
* get_string_value_from allocate the string so with have to free it
* once useless
*/
- free(ref);
+ free(tmp);
data->dep = i;
@@ -754,14 +755,14 @@ parse_global(struct json_object *global, rtapp_options_t *opts)
log_info(PFX " No global section Found: Use default value");
opts->duration = -1;
opts->gnuplot = 0;
- opts->policy = other;
+ opts->policy = other;
opts->calib_cpu = 0;
opts->calib_ns_per_loop = 0;
opts->logdir = strdup("./");
- opts->lock_pages = 1;
opts->logbasename = strdup("rt-app");
opts->logsize = 0;
opts->ftrace = 0;
+ opts->lock_pages = 1;
opts->pi_enabled = 0;
opts->io_device = strdup("/dev/null");
opts->mem_buffer_size = DEFAULT_MEM_BUF_SIZE;
@@ -844,10 +845,10 @@ parse_global(struct json_object *global, rtapp_options_t *opts)
}
opts->logdir = get_string_value_from(global, "logdir", TRUE, "./");
- opts->lock_pages = get_bool_value_from(global, "lock_pages", TRUE, 1);
opts->logbasename = get_string_value_from(global, "log_basename",
TRUE, "rt-app");
opts->ftrace = get_bool_value_from(global, "ftrace", TRUE, 0);
+ opts->lock_pages = get_bool_value_from(global, "lock_pages", TRUE, 1);
opts->pi_enabled = get_bool_value_from(global, "pi_enabled", TRUE, 0);
opts->io_device = get_string_value_from(global, "io_device", TRUE,
"/dev/null");
--
1.9.1
With the new mechanism that is used to describe a scenario, it becomes more
complex to estimate how many logs will be generated during the execution of a
use case. As a result, the record of the logs in temporary buffer had been
disable and the logs were saved directly in files. The potential side effect
of such mecanism is to block threads on io access, which disturbs the use case
behavior.
A new parameter is added to define the saving policy of the logs. You can
now disable the logs, save them directly in a file like previously,
define the size of a temporary buffer but with the risk to lost some logs if
the buffer overflow. You can also ask rt-app to evaluate how many logs will be
generated and allocate the temporary buffer accordingly. This last mode is not
yet implemented and it will be part of a dedicated patch.
Full details of the new parameter is available in the update of the
documentation
Signed-off-by: Vincent Guittot <vincent.guittot(a)linaro.org>
---
doc/tutorial.txt | 15 ++++++++++++++
src/rt-app.c | 34 +++++++++++++++++++++++--------
src/rt-app_parse_config.c | 51 ++++++++++++++++++++++++++++++++++++++---------
src/rt-app_types.h | 1 +
4 files changed, 84 insertions(+), 17 deletions(-)
diff --git a/doc/tutorial.txt b/doc/tutorial.txt
index 12aba47..8341b2e 100644
--- a/doc/tutorial.txt
+++ b/doc/tutorial.txt
@@ -61,6 +61,20 @@ the current directory (./).
* log_basename : Text. Prefix used for all log files of the use case.
"rt-app-" is used by default.
+* log_size : String or Integer. A Integer defines a fix size in MB of the
+temporary buffer (size per thread) that will be used to store the log data
+before saving them in a file. This temporary buffer is used as a cicular
+buffer so the oldest data will be lost in case of overflow. A string is used
+to set a predifined behavior:
+ - "file" will be used to store the log data directly in the file without
+ using a temporary buffer.
+ - "Disable" will disable the log mecahnism.
+ - "Auto" will let rt-app compute the buffer size to not overflow the latter
+ during the use case.
+The use of a temporary buffer prevents the threads of unexpected wait during
+io access. The "Auto" mode is not implemented yet and fallback to "file" mode
+for the moment.
+
* ftrace: Boolean. If enable, rt-app logs in ftrace the main events of the use
case. Default value is False.
@@ -75,6 +89,7 @@ each threads (see gnuplot section for more details). Default value is False.
"pi_enabled" : false,
"lock_pages" : false,
"logdir" : "./",
+ "log_size" : "file",
"log_basename" : "rt-app",
"ftrace" : false,
"gnuplot" : false,
diff --git a/src/rt-app.c b/src/rt-app.c
index 6a27308..805cc35 100644
--- a/src/rt-app.c
+++ b/src/rt-app.c
@@ -391,10 +391,11 @@ void *thread_body(void *arg)
timing_point_t *curr_timing;
timing_point_t *timings;
timing_point_t tmp_timing;
+ unsigned int timings_size, timing_loop;
pid_t tid;
struct sched_attr attr;
unsigned int flags = 0;
- int ret, i, j, loop;
+ int ret, i, j, loop, idx;
/* Set thread name */
ret = pthread_setname_np(pthread_self(), data->name);
@@ -488,6 +489,15 @@ void *thread_body(void *arg)
exit(EXIT_FAILURE);
}
+ if (opts.logsize > 0) {
+ timings = malloc(opts.logsize);
+ timings_size = opts.logsize / sizeof(timing_point_t);
+ } else {
+ timings = NULL;
+ timings_size = 0;
+ }
+ timing_loop = 0;
+
/* Lock pages */
if (data->lock_pages == 1)
{
@@ -502,8 +512,6 @@ void *thread_body(void *arg)
log_notice("[%d] starting thread ...\n", data->ind);
- timings = NULL;
-
fprintf(data->log_handler, "#idx\tperf\trun\tperiod\tstart\t\tend\t\trel_st\n");
if (opts.ftrace)
@@ -526,7 +534,7 @@ void *thread_body(void *arg)
}
}
#endif
- i = j = loop = 0;
+ i = j = loop = idx = 0;
while (continue_running && (i != data->loop)) {
struct timespec t_diff, t_rel_start;
@@ -541,7 +549,7 @@ void *thread_body(void *arg)
clock_gettime(CLOCK_MONOTONIC, &t_end);
if (timings)
- curr_timing = &timings[loop];
+ curr_timing = &timings[idx];
else
curr_timing = &tmp_timing;
@@ -556,7 +564,7 @@ void *thread_body(void *arg)
curr_timing->duration = duration;
curr_timing->perf = perf;
- if (!timings)
+ if (opts.logsize && !timings)
log_timing(data->log_handler, curr_timing);
if (opts.ftrace)
@@ -575,6 +583,12 @@ void *thread_body(void *arg)
pdata = &data->phases[j];
}
+
+ idx++;
+ if (idx >= timings_size) {
+ timing_loop = 1;
+ idx = 0;
+ }
}
param.sched_priority = 0;
@@ -587,9 +601,13 @@ void *thread_body(void *arg)
exit(EXIT_FAILURE);
}
- if (timings)
- for (j=0; j < loop; j++)
+ if (timings) {
+ for (j = idx; timing_loop && (j < timings_size); j++)
+ log_timing(data->log_handler, &timings[j]);
+ for (j = 0; j < idx; j++)
log_timing(data->log_handler, &timings[j]);
+ }
+
if (opts.ftrace)
log_ftrace(ft_data.marker_fd, "[%d] exiting", data->ind);
diff --git a/src/rt-app_parse_config.c b/src/rt-app_parse_config.c
index def3070..98374cd 100644
--- a/src/rt-app_parse_config.c
+++ b/src/rt-app_parse_config.c
@@ -744,8 +744,8 @@ parse_tasks(struct json_object *tasks, rtapp_options_t *opts)
static void
parse_global(struct json_object *global, rtapp_options_t *opts)
{
- char *policy, *cal_str;
- struct json_object *cal_obj;
+ char *policy, *tmp_str;
+ struct json_object *tmp_obj;
int scan_cnt;
log_info(PFX "Parsing global section");
@@ -760,6 +760,7 @@ parse_global(struct json_object *global, rtapp_options_t *opts)
opts->logdir = strdup("./");
opts->lock_pages = 1;
opts->logbasename = strdup("rt-app");
+ opts->logsize = 0;
opts->ftrace = 0;
opts->pi_enabled = 0;
opts->io_device = strdup("/dev/null");
@@ -781,27 +782,27 @@ parse_global(struct json_object *global, rtapp_options_t *opts)
*/
free(policy);
- cal_obj = get_in_object(global, "calibration", TRUE);
- if (cal_obj == NULL) {
+ tmp_obj = get_in_object(global, "calibration", TRUE);
+ if (tmp_obj == NULL) {
/* no setting ? Calibrate CPU0 */
opts->calib_cpu = 0;
opts->calib_ns_per_loop = 0;
log_error("missing calibration setting force CPU0");
} else {
- if (json_object_is_type(cal_obj, json_type_int)) {
+ if (json_object_is_type(tmp_obj, json_type_int)) {
/* integer (no " ") detected. */
- opts->calib_ns_per_loop = json_object_get_int(cal_obj);
+ opts->calib_ns_per_loop = json_object_get_int(tmp_obj);
log_debug("ns_per_loop %d", opts->calib_ns_per_loop);
} else {
/* Get CPU number */
- cal_str = get_string_value_from(global, "calibration",
+ tmp_str = get_string_value_from(global, "calibration",
TRUE, "CPU0");
- scan_cnt = sscanf(cal_str, "CPU%d", &opts->calib_cpu);
+ scan_cnt = sscanf(tmp_str, "CPU%d", &opts->calib_cpu);
/*
* get_string_value_from allocate the string so with have to free it
* once useless
*/
- free(cal_str);
+ free(tmp_str);
if (!scan_cnt) {
log_critical(PFX "Invalid calibration CPU%d", opts->calib_cpu);
exit(EXIT_INV_CONFIG);
@@ -810,6 +811,38 @@ parse_global(struct json_object *global, rtapp_options_t *opts)
}
}
+ tmp_obj = get_in_object(global, "log_size", TRUE);
+ if (tmp_obj == NULL) {
+ /* no size ? use file system */
+ opts->logsize = -2;
+ } else {
+ if (json_object_is_type(tmp_obj, json_type_int)) {
+ /* integer (no " ") detected. */
+ /* buffer size is set in MB */
+ opts->logsize = json_object_get_int(tmp_obj) << 20;
+ log_notice("Log buffer size fixed to %dMB per threads", (opts->logsize >> 20));
+ } else {
+ /* Get CPU number */
+ tmp_str = get_string_value_from(global, "log_size",
+ TRUE, "disable");
+
+ if (strcmp(tmp_str, "disable"))
+ opts->logsize = 0;
+ else if (strcmp(tmp_str, "file"))
+ opts->logsize = -2;
+ else if (strcmp(tmp_str, "auto"))
+ opts->logsize = -2; /* Automatic buffer size computation is not supported yet so we fall back on file system mode */
+
+ log_debug("Log buffer set to %s mode", tmp_str);
+
+ /*
+ * get_string_value_from allocate the string so with have to free it
+ * once useless
+ */
+ free(tmp_str);
+ }
+ }
+
opts->logdir = get_string_value_from(global, "logdir", TRUE, "./");
opts->lock_pages = get_bool_value_from(global, "lock_pages", TRUE, 1);
opts->logbasename = get_string_value_from(global, "log_basename",
diff --git a/src/rt-app_types.h b/src/rt-app_types.h
index aab96a7..2ce9c9d 100644
--- a/src/rt-app_types.h
+++ b/src/rt-app_types.h
@@ -170,6 +170,7 @@ typedef struct _rtapp_options_t {
char *logdir;
char *logbasename;
+ int logsize;
int gnuplot;
int calib_cpu;
int calib_ns_per_loop;
--
1.9.1
If the next wake up date of the timer is already in the past when we execute
the event, we resets the timer.t_next to the current time.
Otherwise, if the delay has been too large, we might never recover it and the
timer will always be in the past.
Signed-off-by: Vincent Guittot <vincent.guittot(a)linaro.org>
---
src/rt-app.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/rt-app.c b/src/rt-app.c
index 37e9892..20383a2 100644
--- a/src/rt-app.c
+++ b/src/rt-app.c
@@ -253,6 +253,8 @@ static int run_event(event_data_t *event, int dry_run,
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);
+ else
+ clock_gettime(CLOCK_MONOTONIC, &rdata->res.timer.t_next);
}
break;
case rtapp_suspend:
--
1.9.1
Hi Linaro Sched team,
I am trying to cross compile rt-app to arm android. I've followed the
steps mentioned in the Readme file. But I am facing some issues while
configuring it to arm.
attached are the config log.
Command issued
export CC=arm-linux-gnueabi-gcc
./configure --host=arm
Also i am using following http://packages.ubuntu.com/trusty/libjson-c-dev
--
Thanks & Regards,
M.Srikanth Kumar.
From: Xunlei Pang <pang.xunlei(a)linaro.org>
DVFS adds a latency in the execution of task because of the time to
decide to move at max freq. We need to measure this latency and check
that the governor stays in an acceptable range.
When rt-app runs a json file, a log file is created for each thread.
This log file records the number of loop that has been executed and
the duration for executing these loops (per phase). We can use these
figures to evaluate to latency that is added by a cpufreq governor
and its "performance efficiency".
We use the run+sleep pattern to do the measurement, for the run time per
loop, the performance governor should run the expected duration as the
CPU stays a max freq. At the opposite, the powersave governor will give
use the longest duration (as it stays at lowest OPP). Other governor will
be somewhere between the 2 previous duration as they will use several OPP
and will go back to max frequency after a defined duration which depends
on its monitoring period.
The formula:
duration of powersave gov - duration of the gov
-------------------------------------------------------- x 100%
duration of powersave gov - duration of performance gov
will give the efficiency of the governor. 100% means as efficient as
the perf governor and 0% means as efficient as the powersave governor.
This patch offers json files and shell scripts to do the measurement.
Usage:
./calibration.sh <cpu>
cpu: cpu number on which you want to run the test
./test.sh <governor> <cpu> <runtime> <sleeptime> [<loops>]
governor: target CPUFreq governor you want to test
cpu: cpu number on which you want to run the test. Be the same
as the one passed to "calibration.sh".
runtime: running time in ms per loop of the workload pattern
sleeptime: sleeping time in ms per loop of the workload pattern
loops: repeat times of the workload pattern. default: 10
Example:
"./calibration.sh 0" means to calculate the computing capacity of CPU0 which
will be used in the following test.
"./test.sh ondemand 0 100 100 20" means to
test "ondemand" on CPU0 with workload pattern "run 100ms + sleep 100ms"(20 loops).
NOTE:
- Make sure there are "sed", "cut", "grep", "rt-app", etc tools on
your test machine, and run the scripts under root privilege.
- Run the test while the system is idle.
- You can change the target governor's parameters after running "calibration.sh",
but before "test.sh".
Signed-off-by: Xunlei Pang <pang.xunlei(a)linaro.org>
---
doc/examples/cpufreq_governor_efficiency/README | 60 ++++++++++++
.../cpufreq_governor_efficiency/calibration.json | 26 ++++++
.../cpufreq_governor_efficiency/calibration.sh | 17 ++++
doc/examples/cpufreq_governor_efficiency/dvfs.json | 27 ++++++
doc/examples/cpufreq_governor_efficiency/dvfs.sh | 38 ++++++++
doc/examples/cpufreq_governor_efficiency/test.sh | 104 +++++++++++++++++++++
6 files changed, 272 insertions(+)
create mode 100755 doc/examples/cpufreq_governor_efficiency/README
create mode 100755 doc/examples/cpufreq_governor_efficiency/calibration.json
create mode 100755 doc/examples/cpufreq_governor_efficiency/calibration.sh
create mode 100755 doc/examples/cpufreq_governor_efficiency/dvfs.json
create mode 100755 doc/examples/cpufreq_governor_efficiency/dvfs.sh
create mode 100755 doc/examples/cpufreq_governor_efficiency/test.sh
diff --git a/doc/examples/cpufreq_governor_efficiency/README b/doc/examples/cpufreq_governor_efficiency/README
new file mode 100755
index 0000000..10482b8
--- /dev/null
+++ b/doc/examples/cpufreq_governor_efficiency/README
@@ -0,0 +1,60 @@
+Measure the efficiency of cpufreq governors using rt-app
+
+BACKGROUND:
+ DVFS adds a latency in the execution of task because of the time to
+ decide to move at max freq. We need to measure this latency and check
+ that the governor stays in an acceptable range.
+
+ When rt-app runs a json file, a log file is created for each thread.
+ This log file records the number of loop that has been executed and
+ the duration for executing these loops (per phase). We can use these
+ figures to evaluate to latency that is added by a cpufreq governor
+ and its "performance efficiency".
+
+ We use the run+sleep pattern to do the measurement, for the run time per
+ loop, the performance governor should run the expected duration as the
+ CPU stays a max freq. At the opposite, the powersave governor will give
+ use the longest duration (as it stays at lowest OPP). Other governor will
+ be somewhere between the 2 previous duration as they will use several OPP
+ and will go back to max frequency after a defined duration which depends
+ on its monitoring period.
+
+ The formula:
+
+ duration of powersave gov - duration of the gov
+ -------------------------------------------------------- x 100%
+ duration of powersave gov - duration of performance gov
+
+ will give the efficiency of the governor. 100% means as efficient as
+ the perf governor and 0% means as efficient as the powersave governor.
+
+ This test offers json files and shell scripts to do the measurement.
+
+Usage:
+ ./calibration.sh <cpu>
+ cpu: cpu number on which you want to run the test
+
+ ./test.sh <governor> <cpu> <runtime> <sleeptime> [<loops>]
+ governor: target CPUFreq governor you want to test
+ cpu: cpu number on which you want to run the test. Be the same
+ as the one passing to "calibration.sh".
+ runtime: running time in ms per loop of the workload pattern
+ sleeptime: sleeping time in ms per loop of the workload pattern
+ loops: repeat times of the workload pattern. default: 10
+
+Example:
+ "./calibration.sh 0" means to calculate the computing capacity of CPU0 which
+ will be used in the following test.
+
+ "./test.sh ondemand 0 100 100 20" means to
+ test "ondemand" on CPU0 with workload pattern "run 100ms + sleep 100ms"(20 loops).
+
+NOTE:
+ - Make sure there are "sed", "cut", "grep", "rt-app", etc tools on
+ your test machine, and run the scripts under root privilege.
+
+ - Run the test while the system is idle.
+
+ - You can change the target governor's parameters after running "calibration.sh",
+ but before "test.sh".
+
diff --git a/doc/examples/cpufreq_governor_efficiency/calibration.json b/doc/examples/cpufreq_governor_efficiency/calibration.json
new file mode 100755
index 0000000..2d5870c
--- /dev/null
+++ b/doc/examples/cpufreq_governor_efficiency/calibration.json
@@ -0,0 +1,26 @@
+{
+ "tasks" : {
+ "thread" : {
+ "instance" : 1,
+ "loop" : 1,
+ "phases" : {
+ "run" : {
+ "loop" : 1,
+ "run" : 2000,
+ },
+ "sleep" : {
+ "loop" : 1,
+ "sleep" : 2000,
+ }
+ }
+ }
+ },
+ "global" : {
+ "default_policy" : "SCHED_FIFO",
+ "calibration" : "CPU0",
+ "lock_pages" : true,
+ "ftrace" : false,
+ "logdir" : "./",
+ }
+}
+
diff --git a/doc/examples/cpufreq_governor_efficiency/calibration.sh b/doc/examples/cpufreq_governor_efficiency/calibration.sh
new file mode 100755
index 0000000..a217487
--- /dev/null
+++ b/doc/examples/cpufreq_governor_efficiency/calibration.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+set -e
+
+if [ ! $1 ] ; then
+ echo "Please input one cpu"
+ exit
+fi
+
+echo performance > /sys/devices/system/cpu/cpu$1/cpufreq/scaling_governor
+
+sleep 1
+
+sed 's/"calibration" : "CPU.*",/"calibration" : "CPU'$1'",/' -i calibration.json
+pLoad=$(rt-app calibration.json 2>&1 |grep pLoad |sed 's/.*= \(.*\)ns.*/\1/')
+sed 's/"calibration" : .*,/"calibration" : '$pLoad',/' -i dvfs.json
+echo CPU$1\'s pLoad is $pLoad
diff --git a/doc/examples/cpufreq_governor_efficiency/dvfs.json b/doc/examples/cpufreq_governor_efficiency/dvfs.json
new file mode 100755
index 0000000..c8447df
--- /dev/null
+++ b/doc/examples/cpufreq_governor_efficiency/dvfs.json
@@ -0,0 +1,27 @@
+{
+ "tasks" : {
+ "thread" : {
+ "instance" : 1,
+ "cpus" : [0],
+"loop" : 21,
+ "phases" : {
+ "running" : {
+ "loop" : 1,
+ "run" : 100,
+ },
+ "sleeping" : {
+ "loop" : 1,
+ "sleep" : 100,
+ }
+ }
+ }
+ },
+ "global" : {
+ "default_policy" : "SCHED_OTHER",
+ "calibration" : 90,
+ "lock_pages" : true,
+ "ftrace" : false,
+ "logdir" : "./",
+ }
+}
+
diff --git a/doc/examples/cpufreq_governor_efficiency/dvfs.sh b/doc/examples/cpufreq_governor_efficiency/dvfs.sh
new file mode 100755
index 0000000..00ce81d
--- /dev/null
+++ b/doc/examples/cpufreq_governor_efficiency/dvfs.sh
@@ -0,0 +1,38 @@
+#!/bin/sh
+
+# $1 $2 $3 $4 $5: governor cpu run sleep loops
+set -e
+
+echo $1 > /sys/devices/system/cpu/cpu$2/cpufreq/scaling_governor
+#echo $1 > /sys/devices/system/cpu/cpu1/cpufreq/scaling_governor
+sed 's/"cpus" : \[.*\],/"cpus" : \['$2'\],/' -i dvfs.json
+sleep 3
+
+if [ $3 ] ; then
+ sed 's/"run" : .*,/"run" : '$3',/' -i dvfs.json
+fi
+
+if [ $4 ] ; then
+ sed 's/"sleep" : .*,/"sleep" : '$4',/' -i dvfs.json
+fi
+
+if [ $5 ] ; then
+ sed 's/^"loop" : .*,/"loop" : '$5',/' -i dvfs.json
+fi
+
+rt-app dvfs.json 2> /dev/null
+
+if [ $1 ] ; then
+ mv -f rt-app-thread-0.log rt-app_$1_run$3us_sleep$4us.log
+
+ sum=0
+ loop=0
+ for i in $(cat rt-app_$1_run$3us_sleep$4us.log | sed 'n;d' | sed '1d' |cut -f 3); do
+ loop=$(expr $loop + 1)
+ sum=$(expr $sum + $i)
+ done
+ sum=$(expr $sum / $loop)
+ echo $sum
+ rm -f rt-app_$1_run$3us_sleep$4us.log
+fi
+
diff --git a/doc/examples/cpufreq_governor_efficiency/test.sh b/doc/examples/cpufreq_governor_efficiency/test.sh
new file mode 100755
index 0000000..0160952
--- /dev/null
+++ b/doc/examples/cpufreq_governor_efficiency/test.sh
@@ -0,0 +1,104 @@
+#!/bin/sh
+
+set -e
+
+test_efficiency() {
+
+ FILENAME="results_$RANDOM$$.txt"
+
+ if [ -e /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors ]; then
+ for i in $(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors); do
+ if [ $i = $1 ] ; then
+ gov_target=$i
+ fi
+ export gov_$i=$(echo $i)
+ done
+ else
+ echo "cpufreq sysfs is not available!"
+ exit
+ fi
+
+ if [ ! $gov_target ] ; then
+ echo " Can't find $1 governor!"
+ exit
+ fi
+
+ if [ ! $gov_performance ] ; then
+ echo "Can't find performance governor!"
+ exit
+ fi
+
+ if [ ! $gov_powersave ] ; then
+ echo "Can't find powersave governor!"
+ exit
+ fi
+
+ if [ $gov_target = $gov_performance ] || [ $gov_target = $gov_powersave ] ; then
+ echo "Please input a governor other than \"performance\" or \"powersave\""
+ exit
+ fi
+
+ # Get target gov data first
+ dvfs.sh $1 $2 $3 $4 $5 > $FILENAME
+ target=$(cat $FILENAME |sed -n '1p')
+
+ # Get powersave data
+ dvfs.sh powersave $2 $3 $4 $5 > $FILENAME
+ powersave=$(cat $FILENAME |sed -n '1p')
+
+ # Get performance data
+ dvfs.sh performance $2 $3 $4 $5 > $FILENAME
+ performance=$(cat $FILENAME |sed -n '1p')
+
+ if [ $performance -ge $powersave ] ; then
+ echo "powersave: $powersave"
+ echo "performance: $performance"
+ echo "Error! performance spent more time than powersave!"
+ exit
+ fi
+
+ echo "\"powersave\" efficiency: 0%"
+ echo "\"performance\" efficiency: 100%"
+
+ denominator=$(expr $powersave - $performance)
+
+ if [ $powersave -le $target ]; then
+ target=0
+ else
+ numerator=$(expr $powersave - $target)
+ numerator=$(expr $numerator \* 100)
+ target=$(expr $numerator / $denominator)
+ if [ $target -gt 100 ]; then
+ target=100
+ fi
+ fi
+
+ echo "\"$gov_target\" efficiency: $target%"
+
+ rm -f $FILENAME
+}
+
+if [ $# -lt 4 ]; then
+ echo "Usage: ./test.sh <governor> <cpu> <runtime> <sleeptime> [<loops>]"
+ echo "governor: target CPUFreq governor you want to test"
+ echo "cpu: cpu number on which you want to run the test"
+ echo "runtime: running time in ms per loop of the workload pattern"
+ echo "sleeptime: sleeping time in ms per loop of the workload pattern"
+ echo "loops: repeat times of the workload pattern. default: 10"
+ echo "\nExample:\n\"./test.sh ondemand 0 100 100 20\" means\nTest \"ondemand\" on CPU0 with workload pattern \"run 100ms + sleep 100ms\"(20 loops).\n"
+ exit
+fi
+
+if [ $# = 4 ]; then
+ loops=10
+else
+ loops=$5
+fi
+
+echo "Test \"$1\" on CPU$2 with workload pattern \"run $3ms + sleep $4ms\"($loops loops)."
+
+sleep 1
+PATH=$PATH:.
+
+test_efficiency $1 $2 $(expr $3 \* 1000) $(expr $4 \* 1000) $loops
+
--
1.9.1