From 5fd42b4dc877890668affe69f8cecc968e277148 Mon Sep 17 00:00:00 2001 From: Namhoon Kim Date: Thu, 8 Jan 2015 14:04:12 -0500 Subject: Added mc2spin --- Makefile | 7 +- bin/mc2spin.c | 541 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ include/litmus.h | 3 + mc2spin | Bin 0 -> 102692 bytes src/syscalls.c | 5 + 5 files changed, 554 insertions(+), 2 deletions(-) create mode 100644 bin/mc2spin.c create mode 100755 mc2spin diff --git a/Makefile b/Makefile index 34c428f..70e79d4 100644 --- a/Makefile +++ b/Makefile @@ -73,7 +73,7 @@ AR := ${CROSS_COMPILE}${AR} all = lib ${rt-apps} rt-apps = cycles base_task rt_launch rtspin release_ts measure_syscall \ - base_mt_task uncache runtests resctrl + base_mt_task uncache runtests resctrl mc2spin .PHONY: all lib clean dump-config TAGS tags cscope help doc @@ -168,7 +168,8 @@ litmus-headers = \ include/litmus/rt_param.h \ include/litmus/fpmath.h \ include/litmus/unistd_32.h \ - include/litmus/unistd_64.h + include/litmus/unistd_64.h \ + include/litmus/mc2_common.h unistd-headers = \ $(foreach file,${unistd-${ARCH}},arch/${include-${ARCH}}/include/$(file)) @@ -236,6 +237,8 @@ lib-measure_syscall = -lm obj-resctrl = resctrl.o +obj-mc2spin = mc2spin.o common.o +lib-mc2spin = -lrt # ############################################################################## # Build everything that depends on liblitmus. diff --git a/bin/mc2spin.c b/bin/mc2spin.c new file mode 100644 index 0000000..1ef3082 --- /dev/null +++ b/bin/mc2spin.c @@ -0,0 +1,541 @@ +#include + +#include +#include +#include +#include +#include +#include +#include + + +#include "litmus.h" +#include "common.h" + + + +static void usage(char *error) { + fprintf(stderr, "Error: %s\n", error); + fprintf(stderr, + "Usage:\n" + " rt_spin [COMMON-OPTS] WCET PERIOD DURATION\n" + " rt_spin [COMMON-OPTS] -f FILE [-o COLUMN] WCET PERIOD\n" + " rt_spin -l\n" + "\n" + "COMMON-OPTS = [-w] [-s SCALE]\n" + " [-p PARTITION/CLUSTER [-z CLUSTER SIZE]] [-c CLASS] [-m CRITICALITY LEVEL]\n" + " [-X LOCKING-PROTOCOL] [-L CRITICAL SECTION LENGTH] [-Q RESOURCE-ID]\n" + " [-i [start,end]:[start,end]...]\n" + "\n" + "WCET and PERIOD are milliseconds, DURATION is seconds.\n" + "CRITICAL SECTION LENGTH is in milliseconds.\n"); + exit(EXIT_FAILURE); +} + +/* + * returns the character that made processing stop, newline or EOF + */ +static int skip_to_next_line(FILE *fstream) +{ + int ch; + for (ch = fgetc(fstream); ch != EOF && ch != '\n'; ch = fgetc(fstream)); + return ch; +} + +static void skip_comments(FILE *fstream) +{ + int ch; + for (ch = fgetc(fstream); ch == '#'; ch = fgetc(fstream)) + skip_to_next_line(fstream); + ungetc(ch, fstream); +} + +static void get_exec_times(const char *file, const int column, + int *num_jobs, double **exec_times) +{ + FILE *fstream; + int cur_job, cur_col, ch; + *num_jobs = 0; + + fstream = fopen(file, "r"); + if (!fstream) + bail_out("could not open execution time file"); + + /* figure out the number of jobs */ + do { + skip_comments(fstream); + ch = skip_to_next_line(fstream); + if (ch != EOF) + ++(*num_jobs); + } while (ch != EOF); + + if (-1 == fseek(fstream, 0L, SEEK_SET)) + bail_out("rewinding file failed"); + + /* allocate space for exec times */ + *exec_times = calloc(*num_jobs, sizeof(*exec_times)); + if (!*exec_times) + bail_out("couldn't allocate memory"); + + for (cur_job = 0; cur_job < *num_jobs && !feof(fstream); ++cur_job) { + + skip_comments(fstream); + + for (cur_col = 1; cur_col < column; ++cur_col) { + /* discard input until we get to the column we want */ + int unused __attribute__ ((unused)) = fscanf(fstream, "%*s,"); + } + + /* get the desired exec. time */ + if (1 != fscanf(fstream, "%lf", (*exec_times)+cur_job)) { + fprintf(stderr, "invalid execution time near line %d\n", + cur_job); + exit(EXIT_FAILURE); + } + + skip_to_next_line(fstream); + } + + assert(cur_job == *num_jobs); + fclose(fstream); +} + +#define NUMS 4096 +static int num[NUMS]; +static char* progname; + +static int loop_once(void) +{ + int i, j = 0; + for (i = 0; i < NUMS; i++) + j += num[i]++; + return j; +} + +static int loop_for(double exec_time, double emergency_exit) +{ + double last_loop = 0, loop_start; + int tmp = 0; + + double start = cputime(); + double now = cputime(); + + while (now + last_loop < start + exec_time) { + loop_start = now; + tmp += loop_once(); + now = cputime(); + last_loop = now - loop_start; + if (emergency_exit && wctime() > emergency_exit) { + /* Oops --- this should only be possible if the execution time tracking + * is broken in the LITMUS^RT kernel. */ + fprintf(stderr, "!!! rtspin/%d emergency exit!\n", getpid()); + fprintf(stderr, "Something is seriously wrong! Do not ignore this.\n"); + break; + } + } + + return tmp; +} + + +static void debug_delay_loop(void) +{ + double start, end, delay; + + while (1) { + for (delay = 0.5; delay > 0.01; delay -= 0.01) { + start = wctime(); + loop_for(delay, 0); + end = wctime(); + printf("%6.4fs: looped for %10.8fs, delta=%11.8fs, error=%7.4f%%\n", + delay, + end - start, + end - start - delay, + 100 * (end - start - delay) / delay); + } + } +} + +static int job(double exec_time, double program_end, int lock_od, double cs_length) +{ + double chunk1, chunk2; + + if (wctime() > program_end) + return 0; + else { + if (lock_od >= 0) { + /* simulate critical section somewhere in the middle */ + chunk1 = drand48() * (exec_time - cs_length); + chunk2 = exec_time - cs_length - chunk1; + + /* non-critical section */ + loop_for(chunk1, program_end + 1); + + /* critical section */ + litmus_lock(lock_od); + loop_for(cs_length, program_end + 1); + litmus_unlock(lock_od); + + /* non-critical section */ + loop_for(chunk2, program_end + 2); + } else { + loop_for(exec_time, program_end + 1); + } + sleep_next_period(); + return 1; + } +} + +struct lt_interval* parse_td_intervals(int num, char* optarg, unsigned int *num_intervals) +{ + int i, matched; + struct lt_interval *slots = malloc(sizeof(slots[0]) * num); + char** arg = (char**)malloc(sizeof(char*) * num); + char *token, *saveptr; + double start, end; + + for (i = 0; i < num; i++) { + arg[i] = (char*)malloc(sizeof(char)*100); + } + + i = 0; + token = strtok_r(optarg, ":", &saveptr); + while(token != NULL) { + sprintf(arg[i++], "%s", token); + token = strtok_r(NULL, ":", &saveptr); + } + + *num_intervals = 0; + + for (i=0; i 0 && slots[i - 1].end >= slots[i].start) { + fprintf(stderr, "interval %s: overlaps with previous interval\n", arg[i]); + exit(5); + } + + (*num_intervals)++; + } + + for (i=0; i period) { + usage("The worst-case execution time must not " + "exceed the period."); + } + + if (!file) + duration = atof(argv[optind + 2]); + else if (file && num_jobs > 1) + duration += period_ms * 0.001 * (num_jobs - 1); + + if (migrate) { + ret = be_migrate_to_domain(cluster); + if (ret < 0) + bail_out("could not migrate to target partition or cluster."); + } + + /* reservation config */ + config.id = gettid(); + + if (hyperperiod%period != 0 ) { + bail_out("hyperperiod must be multiple of period"); + } + + if (mc2_param.crit == CRIT_LEVEL_A) { + config.table_driven_params.major_cycle_length = period; + } + else if (mc2_param.crit == CRIT_LEVEL_B) { + config.polling_params.budget = budget; + config.polling_params.period = period; + config.polling_params.offset = 0; + config.polling_params.relative_deadline = 0; + if (config.polling_params.budget > config.polling_params.period) { + usage("The budget must not exceed the period."); + } + } + + /* create a reservation */ + ret = reservation_create(res_type, &config); + if (ret < 0) { + bail_out("failed to create reservation."); + } + + init_rt_task_param(¶m); + param.exec_cost = wcet; + param.period = period; + param.priority = priority; + param.cls = class; + param.release_policy = TASK_PERIODIC; + param.budget_policy = (want_enforcement) ? + PRECISE_ENFORCEMENT : NO_ENFORCEMENT; + if (migrate) { + param.cpu = gettid(); + } + ret = set_rt_task_param(gettid(), ¶m); + if (ret < 0) + bail_out("could not setup rt task params"); + + mc2_param.pid = gettid(); + mc2_param.hyperperiod = hyperperiod; + ret = set_mc2_task_param(gettid(), &mc2_param); + if (ret < 0) + bail_out("could not setup mc2 task params"); + init_litmus(); + + start = wctime(); + ret = task_mode(LITMUS_RT_TASK); + if (ret != 0) + bail_out("could not become RT task"); + + if (protocol >= 0) { + /* open reference to semaphore */ + lock_od = litmus_open_lock(protocol, resource_id, lock_namespace, &cluster); + if (lock_od < 0) { + perror("litmus_open_lock"); + usage("Could not open lock."); + } + } + + + if (wait) { + ret = wait_for_ts_release(); + if (ret != 0) + bail_out("wait_for_ts_release()"); + start = wctime(); + } + + if (file) { + /* use times read from the CSV file */ + for (cur_job = 0; cur_job < num_jobs; ++cur_job) { + /* convert job's length to seconds */ + job(exec_times[cur_job] * 0.001 * scale, + start + duration, + lock_od, cs_length * 0.001); + } + } else { + do { + if (verbose) { + get_job_no(&job_no); + printf("rtspin/%d:%u @ %.4fms\n", gettid(), + job_no, (wctime() - start) * 1000); + } + /* convert to seconds and scale */ + } while (job(wcet_ms * 0.001 * scale, start + duration, + lock_od, cs_length * 0.001)); + } + + ret = task_mode(BACKGROUND_TASK); + if (ret != 0) + bail_out("could not become regular task (huh?)"); + + if (file) + free(exec_times); + + reservation_destroy(gettid(), config.cpu); + if (mc2_param.crit == CRIT_LEVEL_A) { + free(config.table_driven_params.intervals); + } + return 0; +} diff --git a/include/litmus.h b/include/litmus.h index 3bd6b92..b90a83d 100644 --- a/include/litmus.h +++ b/include/litmus.h @@ -40,6 +40,8 @@ extern "C" { #include "migration.h" +#include "litmus/mc2_common.h" + /** * @private * Number of semaphore protocol object types @@ -420,6 +422,7 @@ int reservation_create(int rtype, void *config); int reservation_destroy(unsigned int reservation_id, int cpu); +int set_mc2_task_param(pid_t pid, struct mc2_task* param); #ifdef __cplusplus } diff --git a/mc2spin b/mc2spin new file mode 100755 index 0000000..00b20c0 Binary files /dev/null and b/mc2spin differ diff --git a/src/syscalls.c b/src/syscalls.c index fbb8604..b07d135 100644 --- a/src/syscalls.c +++ b/src/syscalls.c @@ -96,3 +96,8 @@ int reservation_destroy(unsigned int reservation_id, int cpu) { return syscall(__NR_reservation_destroy, reservation_id, cpu); } + +int set_mc2_task_param(pid_t pid, struct mc2_task *param) +{ + return syscall(__NR_set_mc2_task_param, pid, param); +} \ No newline at end of file -- cgit v1.2.2