From: Olav Haugan ohaugan@codeaurora.org
Allow setting of cpusets at all levels of the spec.
Signed-off-by: Olav Haugan ohaugan@codeaurora.org Signed-off-by: Stephen Boyd stephen.boyd@linaro.org --- src/rt-app.c | 119 ++++++++++++++++++++++++++++++++++++++++------ src/rt-app_parse_config.c | 62 +++++++++++++++--------- src/rt-app_types.h | 12 ++++- 3 files changed, 155 insertions(+), 38 deletions(-)
diff --git a/src/rt-app.c b/src/rt-app.c index 0f992f5748c4..50922aa2ee03 100644 --- a/src/rt-app.c +++ b/src/rt-app.c @@ -448,6 +448,109 @@ shutdown(int sig) exit(EXIT_SUCCESS); }
+static void create_cpuset_str(cpu_data_t *cpu_data) +{ + unsigned int cpu_count = CPU_COUNT_S(cpu_data->cpusetsize, + cpu_data->cpuset); + unsigned int i; + unsigned int idx = 0; + + /* Assume we can go up to 9999 cpus. Each cpu would take up to 4 + 2 + * bytes (4 for the number and 2 for the comma and space). 2 bytes + * for beginning bracket + space and 2 bytes for end bracket and space + * and finally null-terminator. + */ + unsigned int size_needed = cpu_count * 6 + 2 + 2 + 1; + + cpu_data->cpuset_str = malloc(size_needed); + strcpy(cpu_data->cpuset_str, "[ "); + idx += 2; + + for (i = 0; i < 10000 && cpu_count; ++i) { + unsigned int n; + + if (CPU_ISSET(i, cpu_data->cpuset)) { + --cpu_count; + if (size_needed <= (idx + 1)) { + log_error("Not enough memory for array"); + exit(EXIT_FAILURE); + } + n = snprintf(&cpu_data->cpuset_str[idx], + size_needed - idx - 1, "%d", i); + if (n > 0) { + idx += n; + } else { + log_error("Error creating array"); + exit(EXIT_FAILURE); + } + if (size_needed <= (idx + 1)) { + log_error("Not enough memory for array"); + exit(EXIT_FAILURE); + } + if (cpu_count) { + strncat(cpu_data->cpuset_str, ", ", + size_needed - idx - 1); + idx += 2; + } + } + } + strncat(cpu_data->cpuset_str, " ]", size_needed - idx - 1); +} + +static void set_thread_affinity(thread_data_t *data, cpu_data_t *cpu_data) +{ + int ret; + cpu_data_t *actual_cpu_data = &data->cpu_data; + + if (data->def_cpu_data.cpuset == NULL) { + /* Get default affinity */ + cpu_set_t cpuset; + unsigned int cpu_count; + unsigned int cpu = 0; + + ret = pthread_getaffinity_np(pthread_self(), + sizeof(cpu_set_t), &cpuset); + if (ret != 0) { + errno = ret; + perror("pthread_get_affinity"); + exit(EXIT_FAILURE); + } + cpu_count = CPU_COUNT(&cpuset); + data->def_cpu_data.cpusetsize = CPU_ALLOC_SIZE(cpu_count); + data->def_cpu_data.cpuset = CPU_ALLOC(cpu_count); + memcpy(data->def_cpu_data.cpuset, &cpuset, + data->def_cpu_data.cpusetsize); + create_cpuset_str(&data->def_cpu_data); + data->curr_cpu_data = &data->def_cpu_data; + } + + /* Order of preference: + * 1. Phase cpuset + * 2. Global cpuset + * 3. Default cpuset + */ + if (cpu_data->cpuset != NULL) + actual_cpu_data = cpu_data; + + if (actual_cpu_data->cpuset == NULL) + actual_cpu_data = &data->def_cpu_data; + + if (!CPU_EQUAL(actual_cpu_data->cpuset, data->curr_cpu_data->cpuset)) + { + log_notice("[%d] setting cpu affinity to CPU(s) %s", data->ind, + actual_cpu_data->cpuset_str); + ret = pthread_setaffinity_np(pthread_self(), + actual_cpu_data->cpusetsize, + actual_cpu_data->cpuset); + if (ret < 0) { + errno = ret; + perror("pthread_setaffinity_np"); + exit(EXIT_FAILURE); + } + data->curr_cpu_data = actual_cpu_data; + } +} + void *thread_body(void *arg) { thread_data_t *data = (thread_data_t*) arg; @@ -475,20 +578,6 @@ void *thread_body(void *arg) /* Get the 1st phase's data */ pdata = &data->phases[0];
- /* Set thread affinity */ - if (data->cpuset != NULL) - { - log_notice("[%d] setting cpu affinity to CPU(s) %s", data->ind, - data->cpuset_str); - ret = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), - data->cpuset); - if (ret < 0) { - errno = ret; - perror("pthread_setaffinity_np"); - exit(EXIT_FAILURE); - } - } - /* Set scheduling policy and print pretty info on stdout */ log_notice("[%d] Using %s policy with priority %d", data->ind, data->sched_policy_descr, data->sched_prio); switch (data->sched_policy) @@ -636,6 +725,8 @@ void *thread_body(void *arg) while (continue_running && (i != data->loop)) { struct timespec t_diff, t_rel_start;
+ set_thread_affinity(data, &pdata->cpu_data); + if (opts.ftrace) 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);; diff --git a/src/rt-app_parse_config.c b/src/rt-app_parse_config.c index 83794f35fe97..63f69b0c3a15 100644 --- a/src/rt-app_parse_config.c +++ b/src/rt-app_parse_config.c @@ -631,15 +631,44 @@ parse_thread_phase_data(struct json_object *obj, } }
+static void parse_cpuset_data(struct json_object *obj, cpu_data_t *data) +{ + struct json_object *cpuset_obj, *cpu; + + /* cpuset */ + cpuset_obj = get_in_object(obj, "cpus", TRUE); + if (cpuset_obj) { + struct array_list *cpuset; + unsigned int i; + unsigned int cpu_idx; + + assure_type_is(cpuset_obj, obj, "cpus", json_type_array); + data->cpuset_str = strdup(json_object_to_json_string(cpuset_obj)); + data->cpusetsize = sizeof(cpu_set_t); + data->cpuset = malloc(data->cpusetsize); + cpuset = json_object_get_array(cpuset_obj); + CPU_ZERO(data->cpuset); + for (i = 0; i < json_object_array_length(cpuset_obj); i++) { + cpu = json_object_array_get_idx(cpuset_obj, i); + cpu_idx = json_object_get_int(cpu); + CPU_SET(cpu_idx, data->cpuset); + } + } else { + data->cpuset_str = strdup("-"); + data->cpuset = NULL; + data->cpusetsize = 0; + } + log_info(PIN "key: cpus %s", data->cpuset_str); +} + static void parse_thread_data(char *name, struct json_object *obj, int index, thread_data_t *data, rtapp_options_t *opts) { char *policy; char def_policy[RTAPP_POLICY_DESCR_LENGTH]; - struct array_list *cpuset; - struct json_object *cpuset_obj, *phases_obj, *cpu, *resources, *locks; - int i, cpu_idx, prior_def; + struct json_object *phases_obj, *resources, *locks; + int prior_def;
log_info(PFX "Parsing thread %s [%d]", name, index);
@@ -648,8 +677,11 @@ parse_thread_data(char *name, struct json_object *obj, int index, data->ind = index; data->name = strdup(name); data->lock_pages = opts->lock_pages; - data->cpuset = NULL; - data->cpuset_str = NULL; + data->cpu_data.cpuset = NULL; + data->cpu_data.cpuset_str = NULL; + data->curr_cpu_data = NULL; + data->def_cpu_data.cpuset = NULL; + data->def_cpu_data.cpuset_str = NULL;
/* policy */ policy_to_string(opts->policy, def_policy); @@ -683,23 +715,7 @@ parse_thread_data(char *name, struct json_object *obj, int index, data->deadline = get_int_value_from(obj, "deadline", TRUE, data->period);
/* cpuset */ - cpuset_obj = get_in_object(obj, "cpus", TRUE); - if (cpuset_obj) { - assure_type_is(cpuset_obj, obj, "cpus", json_type_array); - 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); - for (i = 0; i < json_object_array_length(cpuset_obj); i++) { - cpu = json_object_array_get_idx(cpuset_obj, i); - cpu_idx = json_object_get_int(cpu); - CPU_SET(cpu_idx, data->cpuset); - } - } else { - data->cpuset_str = strdup("-"); - data->cpuset = NULL; - } - log_info(PIN "key: cpus %s", data->cpuset_str); + parse_cpuset_data(obj, &data->cpu_data);
/* initial delay */ data->delay = get_int_value_from(obj, "delay", TRUE, 0); @@ -726,6 +742,7 @@ parse_thread_data(char *name, struct json_object *obj, int index, foreach(phases_obj, entry, key, val, idx) { log_info(PIN "Parsing phase %s", key); parse_thread_phase_data(val, &data->phases[idx], opts, (long)data); + parse_cpuset_data(val, &data->phases[idx].cpu_data); }
/* Get loop number */ @@ -735,6 +752,7 @@ parse_thread_data(char *name, struct json_object *obj, int index, data->nphases = 1; data->phases = malloc(sizeof(phase_data_t) * data->nphases); parse_thread_phase_data(obj, &data->phases[0], opts, (long)data); + parse_cpuset_data(obj, &data->phases[0].cpu_data); /* Get loop number */ data->loop = 1; } diff --git a/src/rt-app_types.h b/src/rt-app_types.h index 5b8345fcf6aa..918a2ccc616c 100644 --- a/src/rt-app_types.h +++ b/src/rt-app_types.h @@ -123,10 +123,17 @@ typedef struct _event_data_t { int count; } event_data_t;
+typedef struct _cpu_data_t { + cpu_set_t *cpuset; + char *cpuset_str; + size_t cpusetsize; +} cpu_data_t; + typedef struct _phase_data_t { int loop; event_data_t *events; int nbevents; + cpu_data_t cpu_data; } phase_data_t;
typedef struct _thread_data_t { @@ -135,8 +142,9 @@ typedef struct _thread_data_t { int lock_pages; int duration; rtapp_resource_t **resources; - cpu_set_t *cpuset; - char *cpuset_str; + cpu_data_t cpu_data; /* cpu set information */ + cpu_data_t *curr_cpu_data; /* Current cpu set being used */ + cpu_data_t def_cpu_data; /* Default cpu set for task */
unsigned long runtime, deadline, period;