diff --git a/doc/tutorial.txt b/doc/tutorial.txt index 07dfa56e..bab9c8c2 100644 --- a/doc/tutorial.txt +++ b/doc/tutorial.txt @@ -272,6 +272,38 @@ inherit the affinity from the task level): } } +*** Core Scheduling + +* core_scheduling_family: Integer. If two or more tasks have the same family, they will share their Core Scheduling Cookie. +* core_scheduling_families_count: Integer. Number of core scheduling families to be created. + +"core_scheduling_family" can only be specified at task level. +"core_scheduling_families_count" is a global parameter. +In the example below it creates 2 threads with different core scheduling cookie. +"tasks" : { + "thread1" : { + "core_scheduling_family" : 1, + "phases" : { + "phase1" : { + "run" : 10, + "sleep" : 10 + } + } + } + "thread2" : { + "core_scheduling_family" : 2, + "phases" : { + "phase1" : { + "run" : 10, + "sleep" : 10 + } + } + } +}, +"global":{ + "core_scheduling_families_count": 2 +} + *** Utilization Clamping util_min: Integer. Can be specified at task level or phase level. Sets the min diff --git a/src/rt-app.c b/src/rt-app.c index 673df444..d8080e83 100644 --- a/src/rt-app.c +++ b/src/rt-app.c @@ -38,6 +38,24 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include #include +/* Core scheduling libraries */ +#include +#include +#include +#include +#include +#include + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(5,16,0) + +typedef enum {PIDTYPE_PID,PIDTYPE_TGID,PIDTYPE_PGID,PIDTYPE_SID,PIDTYPE_MAX}pid_type; + +#define PR_SCHED_CORE_SCOPE_THREAD 0 +#define PR_SCHED_CORE_SCOPE_THREAD_GROUP 1 +#define PR_SCHED_CORE_SCOPE_PROCESS_GROUP 2 + +#endif + #include "config.h" #include "rt-app_utils.h" #include "rt-app_args.h" @@ -63,6 +81,9 @@ static pthread_barrier_t threads_barrier; static pthread_mutex_t joining_mutex; static pthread_mutex_t fork_mutex; +static pid_t *core_scheduling_first_threads; +static pthread_mutex_t core_scheduling_mutex; + static ftrace_data_t ft_data = { .debugfs = "/sys/kernel/debug", .marker_fd = -1, @@ -736,6 +757,7 @@ static void __shutdown(bool force_terminate) free(threads[i].data); } + free(core_scheduling_first_threads); log_ftrace(ft_data.marker_fd, FTRACE_MAIN, "rtapp_main: event=end"); @@ -745,7 +767,6 @@ static void __shutdown(bool force_terminate) } remove_cgroups(); - /* * If we unlock the joining_mutex here we could risk a late SIGINT * causing us to re-enter this loop. Since we are calling exit() to @@ -1144,7 +1165,33 @@ void *thread_body(void *arg) perror("pthread_setname_np thread name over 16 characters"); } - /* Get the 1st phase's data */ + /* Set core scheduling family */ + if (data->core_scheduling_family != 0) { + if (opts.core_scheduling_families_count >= data->core_scheduling_family) { + pthread_mutex_lock(&core_scheduling_mutex); + if (core_scheduling_first_threads[data->core_scheduling_family-1] != 0) { + if (prctl(PR_SCHED_CORE, PR_SCHED_CORE_SHARE_FROM, + core_scheduling_first_threads[data->core_scheduling_family-1], + PR_SCHED_CORE_SCOPE_THREAD, 0)) { + perror("Error copying core scheduling cookie"); + } + } else { + core_scheduling_first_threads[data->core_scheduling_family-1] = gettid(); + if (prctl(PR_SCHED_CORE, PR_SCHED_CORE_CREATE, + gettid(), PR_SCHED_CORE_SCOPE_THREAD, 0)) { + perror("Error creating core scheduling cookie"); + } + } + pthread_mutex_unlock(&core_scheduling_mutex); + } + + u_long test; + prctl(PR_SCHED_CORE, PR_SCHED_CORE_GET, gettid(), PR_SCHED_CORE_SCOPE_THREAD, &test); + log_notice("[%d] Core scheduling cookie set to %lu, family %d", + data->ind, test, data->core_scheduling_family); + } + + /* Get the 1st phase's data */ pdata = &data->phases[0]; /* Init timing buffer */ @@ -1507,7 +1554,7 @@ static void setup_main_gnuplot(void) int main(int argc, char* argv[]) { - int i, res, nresources; + int i, k, res, nresources; rtapp_resource_t *rdata; static cpu_set_t orig_set; struct stat sb; @@ -1597,6 +1644,20 @@ int main(int argc, char* argv[]) /* Sync timer resources with start time */ clock_gettime(CLOCK_MONOTONIC, &t_start); + /* Setup core scheduling */ + if (opts.core_scheduling_families_count == -1) { + for (k = 0; k < opts.num_tasks; k++) { + if (opts.threads_data[k].core_scheduling_family > opts.core_scheduling_families_count) { + opts.core_scheduling_families_count = opts.threads_data[k].core_scheduling_family; + } + } + } + core_scheduling_first_threads = malloc(sizeof (pid_t) * opts.core_scheduling_families_count); + for (i = 0; i < opts.core_scheduling_families_count; i++) { + core_scheduling_first_threads[i] = 0; + } + pthread_mutex_init(&core_scheduling_mutex, NULL); + /* Start the use case */ int ind = 0; for (i = 0; i < opts.num_tasks; i++) { @@ -1620,6 +1681,14 @@ int main(int argc, char* argv[]) goto exit_err; } + if((tdata_orig->core_scheduling_family > 0 && + tdata_orig->core_scheduling_family > opts.core_scheduling_families_count) || + tdata_orig->core_scheduling_family < 0) { + log_error("Thread core_scheduling_family (%d) bigger then core_scheduling_families_count (%d)", + tdata_orig->core_scheduling_family, opts.core_scheduling_families_count); + goto exit_err; + } + for (j = 0; j < tdata_orig->num_instances; j++) { int ret = create_thread(tdata_orig, ind++, 0, 0); if (ret) { diff --git a/src/rt-app_parse_config.c b/src/rt-app_parse_config.c index 09dbd9b5..c88b487e 100644 --- a/src/rt-app_parse_config.c +++ b/src/rt-app_parse_config.c @@ -1083,7 +1083,10 @@ parse_task_data(char *name, struct json_object *obj, int index, data->forked = 0; data->num_instances = get_int_value_from(obj, "instance", TRUE, 1); - /* Get phases */ + /* Get core scheduling cookie if set */ + data->core_scheduling_family = get_int_value_from(obj, "core_scheduling_family", TRUE, 0); + + /* Get phases */ phases_obj = get_in_object(obj, "phases", TRUE); if (phases_obj) { /* used in the foreach macro */ @@ -1211,6 +1214,8 @@ parse_global(struct json_object *global, rtapp_options_t *opts) } opts->duration = get_int_value_from(global, "duration", TRUE, -1); + opts->core_scheduling_families_count = get_int_value_from(global, "core_scheduling_families_count", + TRUE, -1); opts->gnuplot = get_bool_value_from(global, "gnuplot", TRUE, 0); policy = get_string_value_from(global, "default_policy", TRUE, "SCHED_OTHER"); diff --git a/src/rt-app_types.h b/src/rt-app_types.h index bed8fa38..4bebf005 100644 --- a/src/rt-app_types.h +++ b/src/rt-app_types.h @@ -242,6 +242,8 @@ typedef struct _thread_data_t { rtapp_resources_t *local_resources; rtapp_resources_t **global_resources; + + int core_scheduling_family; } thread_data_t; typedef struct _pthread_data_t { @@ -289,6 +291,8 @@ typedef struct _rtapp_options_t { char *io_device; int cumulative_slack; + + int core_scheduling_families_count; } rtapp_options_t; typedef struct _timing_point_t {