From: Vincent Guittot vincent.guittot@linaro.org
Use calibration variable to calculate loop count for load simulation. The CPU on which the calibration will run can be specified in "calibration" parameter in "global object" or an integer can be specified as ns per loop in the same parameter.
E.g. To calibrate on CPU2 set : "calibration" : "CPU2" To force 1234 ns per loop value set "calibration" : 1234
Signed-off-by: Christian Muller christian.muller@linaro.org Signed-off-by: Vincent Guittot vincent.guittot@linaro.org Signed-off-by: Pi-Cheng Chen pi-cheng.chen@linaro.org --- src/rt-app.c | 104 +++++++++++++++++++++++++++++++++++++++------- src/rt-app_parse_config.c | 30 ++++++++++++- src/rt-app_types.h | 2 + src/rt-app_utils.c | 17 ++++++++ src/rt-app_utils.h | 3 ++ 5 files changed, 140 insertions(+), 16 deletions(-)
diff --git a/src/rt-app.c b/src/rt-app.c index d9c3dca..518fe53 100644 --- a/src/rt-app.c +++ b/src/rt-app.c @@ -18,14 +18,18 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+#define _GNU_SOURCE #include <fcntl.h> #include "rt-app.h" #include "rt-app_utils.h" +#include <sched.h> +#include "pthread.h"
static int errno; static volatile int continue_running; static pthread_t *threads; static int nthreads; +static int p_load; rtapp_options_t opts;
static ftrace_data_t ft_data = { @@ -34,29 +38,84 @@ static ftrace_data_t ft_data = { .marker_fd = -1, };
-static inline busywait(struct timespec *to) +/* + * Function: to do some useless operation. + */ +void waste_cpu_cycles(int load_loops) { - struct timespec t_step; - while (1) { - clock_gettime(CLOCK_THREAD_CPUTIME_ID, &t_step); - if (!timespec_lower(&t_step, to)) - break; + double param, result; + double n, i; + + param = 0.95; + n = 4; + for (i = 0 ; i < load_loops ; i++) { + result = ldexp(param , (ldexp(param , ldexp(param , n)))); + result = ldexp(param , (ldexp(param , ldexp(param , n)))); + result = ldexp(param , (ldexp(param , ldexp(param , n)))); + result = ldexp(param , (ldexp(param , ldexp(param , n)))); + } + return; +} + +/* +* calibrate_cpu_cycles() +* collects the time that waste_cycles runs. +*/ +int calibrate_cpu_cycles(int clock) +{ + struct timespec start, stop; + int max_load_loop = 10000; + unsigned int diff; + int nsec_per_loop, avg_per_loop = 0; + int ret, cal_trial = 1000; + + while (cal_trial) { + cal_trial--; + + clock_gettime(clock, &start); + waste_cpu_cycles(max_load_loop); + clock_gettime(clock, &stop); + + diff = (int)timespec_sub_to_ns(&stop, &start); + nsec_per_loop = diff / max_load_loop; + avg_per_loop = (avg_per_loop + nsec_per_loop) >> 1; + + /* collect a critical mass of samples.*/ + if ((abs(nsec_per_loop - avg_per_loop) * 50) < avg_per_loop) + return avg_per_loop; + + /* + * use several loop duration in order to be sure to not + * fall into a specific platform loop duration + *(like the cpufreq period) + */ + /*randomize the number of loops and recheck 1000 times*/ + max_load_loop += 33333; + max_load_loop %= 1000000; } + return 0; +} + +static inline loadwait(struct timespec *exec_time) +{ + unsigned long exec, load_count; + + exec = timespec_to_usec(exec_time); + load_count = (exec * 1000)/p_load; + waste_cpu_cycles(load_count); }
void run(int ind, struct timespec *min, struct timespec *max, rtapp_tasks_resource_list_t *blockages, int nblockages) { int i; - struct timespec t_start, now, t_exec, t_totexec = *max; + struct timespec t_exec; rtapp_resource_access_list_t *lock, *last;
- /* Get the start time */ - clock_gettime(CLOCK_THREAD_CPUTIME_ID, &t_start); + t_exec = *min;
for (i = 0; i < nblockages; i++) { - /* Lock resources */ lock = blockages[i].acl; while (lock != NULL) { @@ -71,14 +130,13 @@ void run(int ind, struct timespec *min, struct timespec *max, }
/* 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)); if (opts.ftrace) log_ftrace(ft_data.marker_fd, "[%d] busywait for %d", ind, timespec_to_usec(&blockages[i].usage)); - busywait(&t_exec); + loadwait(&blockages[i].usage); + t_exec = timespec_sub(&t_exec, &blockages[i].usage);
/* Unlock resources */ lock = last; @@ -94,13 +152,12 @@ 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 %lu", ind, timespec_to_usec(&t_exec)); - busywait(&t_exec); + loadwait(&t_exec); }
static void @@ -446,6 +503,7 @@ int main(int argc, char* argv[]) int i, res; thread_data_t *tdata; char tmp[PATH_LENGTH]; + static cpu_set_t orig_set;
parse_command_line(argc, argv, &opts);
@@ -484,6 +542,22 @@ int main(int argc, char* argv[])
continue_running = 1;
+ /*Needs to calibrate 'calib_cpu' core*/ + if (opts.calib_ns_per_loop == 0) { + cpu_set_t calib_set; + + CPU_ZERO(&calib_set); + CPU_SET(opts.calib_cpu, &calib_set); + sched_getaffinity(0, sizeof(cpu_set_t), &orig_set); + sched_setaffinity(0, sizeof(cpu_set_t), &calib_set); + p_load = calibrate_cpu_cycles(CLOCK_THREAD_CPUTIME_ID); + sched_setaffinity(0, sizeof(cpu_set_t), &orig_set); + log_notice("pLoad = %dns : calib_cpu %d", p_load, opts.calib_cpu); + } else { + p_load = opts.calib_ns_per_loop; + log_notice("pLoad = %dns", p_load); + } + /* Take the beginning time for everything */ clock_gettime(CLOCK_MONOTONIC, &t_start);
diff --git a/src/rt-app_parse_config.c b/src/rt-app_parse_config.c index 4f26c9a..36a68de 100644 --- a/src/rt-app_parse_config.c +++ b/src/rt-app_parse_config.c @@ -451,7 +451,10 @@ parse_tasks(struct json_object *tasks, rtapp_options_t *opts) static void parse_global(struct json_object *global, rtapp_options_t *opts) { - char *policy; + char *policy, *cal_str; + struct json_object *cal_obj; + int scan_cnt; + log_info(PFX "Parsing global section"); opts->spacing = get_int_value_from(global, "spacing", TRUE, 0); opts->duration = get_int_value_from(global, "duration", TRUE, -1); @@ -462,6 +465,31 @@ parse_global(struct json_object *global, rtapp_options_t *opts) log_critical(PFX "Invalid policy %s", policy); exit(EXIT_INV_CONFIG); } + + cal_obj = get_in_object(global, "calibration", TRUE); + if (cal_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)) { + /* integer (no " ") detected. */ + opts->calib_ns_per_loop = json_object_get_int(cal_obj); + log_debug("ns_per_loop %d", opts->calib_ns_per_loop); + } else { + /* Get CPU number */ + cal_str = get_string_value_from(global, "calibration", + TRUE, "CPU0"); + scan_cnt = sscanf(cal_str, "CPU%d", &opts->calib_cpu); + if (!scan_cnt) { + log_critical(PFX "Invalid calibration CPU%d", opts->calib_cpu); + exit(EXIT_INV_CONFIG); + } + log_debug("calibrating CPU%d", opts->calib_cpu); + } + } + opts->logdir = get_string_value_from(global, "logdir", TRUE, NULL); 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 6920e8d..8bec201 100644 --- a/src/rt-app_types.h +++ b/src/rt-app_types.h @@ -125,6 +125,8 @@ typedef struct _rtapp_options_t { char *logdir; char *logbasename; int gnuplot; + int calib_cpu; + int calib_ns_per_loop;
rtapp_resource_t *resources; int nresources; diff --git a/src/rt-app_utils.c b/src/rt-app_utils.c index 9719053..9012261 100644 --- a/src/rt-app_utils.c +++ b/src/rt-app_utils.c @@ -116,6 +116,23 @@ timespec_lower(struct timespec *what, struct timespec *than) return 0; }
+int64_t +timespec_sub_to_ns(struct timespec *t1, struct timespec *t2) +{ + int64_t diff; + + if (t1->tv_nsec < t2->tv_nsec) { + diff = 1E9 * (int64_t)((int) t1->tv_sec - + (int) t2->tv_sec - 1); + diff += ((int) t1->tv_nsec + 1E9 - (int) t2->tv_nsec); + } else { + diff = 1E9 * (int64_t)((int) t1->tv_sec - (int) t2->tv_sec); + diff += ((int) t1->tv_nsec - (int) t2->tv_nsec); + } + return diff; +} + + void log_timing(FILE *handler, timing_point_t *t) { diff --git a/src/rt-app_utils.h b/src/rt-app_utils.h index c7444dc..68f1ef0 100644 --- a/src/rt-app_utils.h +++ b/src/rt-app_utils.h @@ -109,6 +109,9 @@ timespec_sub(struct timespec *t1, struct timespec *t2); int timespec_lower(struct timespec *what, struct timespec *than);
+int64_t +timespec_sub_to_ns(struct timespec *t1, struct timespec *t2); + void log_timing(FILE *handler, timing_point_t *t);