#include #include #include #include #include #include #include #include #include #include #include #include "litmus.h" #include "common.h" #include "cache_common.h" #define PAGE_SIZE (4096) #define CACHELINE_SIZE 32 #define INTS_IN_CACHELINE (CACHELINE_SIZE/sizeof(int)) #define CACHELINES_IN_1KB (1024 / sizeof(cacheline_t)) #define INTS_IN_1KB (1024 / sizeof(int)) #define INTS_IN_CACHELINE (CACHELINE_SIZE/sizeof(int)) static int loops = 100; static cacheline_t* arena = NULL; static int verbose = 0; struct timeval t1,t2; #define UNCACHE_DEV "/dev/litmus/uncache" /* Random walk around the arena in cacheline-sized chunks. Cacheline-sized chucks ensures the same utilization of each hit line as sequential read. (Otherwise, our utilization would only be 1/INTS_IN_CACHELINE.) */ static int random_walk(cacheline_t *mem, int wss, int write_cycle) { /* a random cycle among the cache lines was set up by init_arena(). */ int sum, i, next; int numlines = wss * CACHELINES_IN_1KB; sum = 0; /* contents of arena is structured s.t. offsets are all w.r.t. to start of arena, so compute the initial offset */ next = mem - arena; if (write_cycle == 0) { for (i = 0; i < numlines; i++) { /* every element in the cacheline has the same value */ next = arena[next].line[0]; sum += next; } } else { int w, which_line; for (i = 0, w = 0; i < numlines; i++) { which_line = next; next = arena[next].line[0]; if((w % write_cycle) != (write_cycle - 1)) { sum += next; } else { ((volatile cacheline_t*)arena)[which_line].line[0] = next; } } } return sum; } static cacheline_t* random_start(int wss) { return arena + randrange(0, ((wss * 1024)/sizeof(cacheline_t))); } static volatile int dont_optimize_me = 0; 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); } static int loop_once(int wss) { cacheline_t *mem; int temp; mem = random_start(wss); temp = random_walk(mem, wss, 1); //mem = sequential_start(wss); //temp = sequential_walk(mem, wss, 0); dont_optimize_me = temp; return dont_optimize_me; } static int job(int wss, double exec_time, double program_end) { if (wctime() > program_end) return 0; else { register unsigned int iter = 0; register cycles_t t; t = get_cycles(); while(iter++ < loops) { loop_once(wss); } t = get_cycles() - t; if (verbose) printf("%ld cycles\n", t); sleep_next_period(); return 1; } } #define OPTSTR "p:wl:m:i:b:k:vs:" int main(int argc, char** argv) { int ret, i; lt_t wcet, period, budget; double wcet_ms, period_ms, budget_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; size_t arena_sz; int wss = 1; uint32_t mode_mask; /* default for reservation */ config.id = 0; config.priority = LITMUS_NO_PRIORITY; /* use EDF by default */ config.cpu = -1; mc2_param.crit = CRIT_LEVEL_C; budget_ms = 1000; 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 'l': loops = atoi(optarg); break; case 's': wss = atoi(optarg); break; case 'k': mode_mask = atoi(optarg); 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 'b': budget_ms = atof(optarg); 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(budget_ms); 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."); } if (wss == 0) { usage("You need to specify a WSS (-k option)."); } duration = atof(argv[optind + 2]); 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 */ for(i = 0; i < 32; i++){ if ( !( (1 << i) & mode_mask) ) continue; config.mode = i; 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(); //param.cpu = config.cpu; } ret = set_rt_task_param(gettid(), ¶m); if (ret < 0) bail_out("could not setup rt task params"); mc2_param.res_id = gettid(); mc2_param.mode_mask = mode_mask; ret = set_mc2_task_param(gettid(), &mc2_param); if (ret < 0) bail_out("could not setup mc2 task params"); arena_sz = wss*1024; arena = alloc_arena(arena_sz, 0, 0); init_arena(arena, arena_sz); mlockall(MCL_CURRENT | MCL_FUTURE); 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 (mc2_param.crit == CRIT_LEVEL_C) set_page_color(-1); else set_page_color(config.cpu); mlockall(MCL_CURRENT | MCL_FUTURE); if (wait) { ret = wait_for_ts_release(); if (ret != 0) bail_out("wait_for_ts_release()"); start = wctime(); } while (job(wss, wcet_ms * 0.001, start + duration)) {}; //set_page_color(config.cpu); //test_call(0); ret = task_mode(BACKGROUND_TASK); if (ret != 0) bail_out("could not become regular task (huh?)"); reservation_destroy(gettid(), config.cpu); dealloc_arena(arena, arena_sz); printf("%s finished.\n", argv[0]); //test_call(1); return 0; }