#include #include #include #include #include #include #include #include #include #include #include #include "litmus.h" #include "common.h" #define PAGE_SIZE (4096) static int verbose = 0; #define UNCACHE_DEV "/dev/litmus/uncache" 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]] [-m CRITICALITY LEVEL]\n" " [-k WSS] [-l LOOPS] [-b BUDGET]\n" "\n" "WCET and PERIOD are milliseconds, DURATION is seconds.\n"); exit(EXIT_FAILURE); } #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 int job(double exec_time, double program_end) { if (wctime() > program_end) return 0; else { loop_for(exec_time, program_end + 1); sleep_next_period(); return 1; } } #define OPTSTR "p:wm:i:v" int main(int argc, char** argv) { int ret; lt_t wcet, period, budget; double wcet_ms, period_ms; unsigned int priority = LITMUS_NO_PRIORITY; int migrate = 0; int cluster = 0; int opt; int wait = 0; double duration = 0, start = 0; struct rt_task param; struct mc2_task mc2_param; struct reservation_config config; int res_type = PERIODIC_POLLING; /* default for reservation */ config.id = 0; config.priority = LITMUS_NO_PRIORITY; /* use EDF by default */ config.cpu = -1; mc2_param.crit = CRIT_LEVEL_C; progname = argv[0]; while ((opt = getopt(argc, argv, OPTSTR)) != -1) { switch (opt) { case 'w': wait = 1; break; case 'p': cluster = atoi(optarg); migrate = 1; config.cpu = cluster; break; case 'm': mc2_param.crit = atoi(optarg); if ((mc2_param.crit >= CRIT_LEVEL_A) && (mc2_param.crit <= CRIT_LEVEL_C)) { res_type = PERIODIC_POLLING; } else usage("Invalid criticality level."); break; case 'i': config.priority = atoi(optarg); break; case 'v': verbose = 1; break; case ':': usage("Argument missing."); break; case '?': default: usage("Bad argument."); break; } } srand(getpid()); /* * We need three parameters */ if (argc - optind < 3) usage("Arguments missing."); wcet_ms = atof(argv[optind + 0]); period_ms = atof(argv[optind + 1]); wcet = ms2ns(wcet_ms); period = ms2ns(period_ms); budget = ms2ns(wcet_ms+1); if (wcet <= 0) usage("The worst-case execution time must be a " "positive number."); if (period <= 0) usage("The period must be a positive number."); if (wcet > period) { usage("The worst-case execution time must not " "exceed the period."); } duration = atof(argv[optind + 2]); if (mc2_param.crit == CRIT_LEVEL_C) { migrate = 0; config.cpu = -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(); 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 = RT_CLASS_HARD; param.release_policy = TASK_PERIODIC; param.budget_policy = 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.res_id = gettid(); ret = set_mc2_task_param(gettid(), &mc2_param); if (ret < 0) bail_out("could not setup mc2 task params"); ret = init_litmus(); if (ret != 0) bail_out("init_litmus() failed\n"); start = wctime(); ret = task_mode(LITMUS_RT_TASK); if (ret != 0) bail_out("could not become RT task"); if (wait) { ret = wait_for_ts_release(); if (ret != 0) bail_out("wait_for_ts_release()"); start = wctime(); } do { if (verbose) { printf("rtspin:%u @ %.4fms\n", gettid(), (wctime() - start) * 1000); } } while (job(wcet_ms * 0.001, start + duration)); ret = task_mode(BACKGROUND_TASK); if (ret != 0) bail_out("could not become regular task (huh?)"); reservation_destroy(gettid(), config.cpu); return 0; }