static inline busywait(__u64 len) { struct timespec t_len, t_now, t_exec, t_step; __u64 real_exec = (len / 100) * RTIME_URUN; t_len = nsec_to_timespec(&real_exec); clock_gettime(CLOCK_THREAD_CPUTIME_ID, &t_now); t_exec = timespec_add(&t_now, &t_len); while (1) { clock_gettime(CLOCK_THREAD_CPUTIME_ID, &t_step); if (!timespec_lower(&t_step, &t_exec)) break; } }
int main(int argc, char* argv[]) { pid_t pid; long long period, budget, exec; char* token; struct sched_attr dl_attr; int ret; unsigned int flags = 0; struct sigaction sa; struct itimerval timer; memset(&task, 0, sizeof(task)); memset(&task_rst, 0, sizeof(task_rst)); ret = atexit(bye); if (ret != 0) { perror("atexit"); exit(1); } if (argc >= 3) { pid = getpid(); printf("%d\t===pid===\n", (int)pid); printf("lock pages in memory\n"); ret = mlockall(MCL_CURRENT | MCL_FUTURE); if (ret < 0) { perror("mlockall"); exit(1); } token = strtok(argv[1], ":"); period = strtoll(token, NULL, 10); token = strtok(NULL, ":"); budget = strtoll(token, NULL, 10); token = strtok(NULL, ":"); exec = strtoll(token, NULL, 10); printf("period = %lld ns, budget = %lld ns, exec = %lld ns\n", period, budget, exec); if (exec == 0) { pure_overhead = 1; } else { pure_overhead = 0; } //duration is a must duration = atoi(argv[2]); clock_gettime(CLOCK_REALTIME, &task_rst.t_exit); memcpy((void*)&task_rst.t_middle, (void*)&task_rst.t_exit, sizeof(task_rst.t_middle)); task_rst.t_exit.tv_sec = task_rst.t_exit.tv_sec + duration; task_rst.t_middle.tv_sec = task_rst.t_middle.tv_sec + duration / 2;//set halfway timestamp if (argc >= 4) { g_log = atoi(argv[3]); } if (argc >= 5) { g_scheduler = atoi(argv[4]); } //set deadline scheduling pid = 0; assert(period >= budget && budget >= exec); // task_rst.dl_period = usec_to_timespec(period); // task_rst.dl_budget = usec_to_timespec(budget); // task_rst.dl_exec = usec_to_timespec(exec); task_rst.dl_period = nsec_to_timespec((unsigned long long)period); task_rst.dl_budget = nsec_to_timespec((unsigned long long)budget); task_rst.dl_exec = nsec_to_timespec((unsigned long long)exec); dl_attr.size = sizeof(dl_attr); dl_attr.sched_flags = 0; dl_attr.sched_policy = SCHED_DEADLINE; dl_attr.sched_priority = 0; dl_attr.sched_runtime = timespec_to_nsec(&task_rst.dl_budget); dl_attr.sched_deadline = timespec_to_nsec(&task_rst.dl_period); dl_attr.sched_period = timespec_to_nsec(&task_rst.dl_period); task_rst.correct_cnt =(int)((int64_t)(duration * 1E9) / timespec_to_nsec(&task_rst.dl_period)); task_rst.i_corrent_whole_thread_runtime = (int64_t)task_rst.correct_cnt * timespec_to_nsec(&task_rst.dl_exec); if (g_scheduler == 0) { printf("using sched_deadline\n"); ret = sched_setattr(pid, &dl_attr, flags); if (ret != 0) { perror("sched_setattr"); exit(1); } } else if (g_scheduler == 1) { printf("using cfs\n"); } else { printf("not implemented\n"); exit(1); } #if 0 memset(&sa, 0, sizeof(sa)); sa.sa_handler = &signal_handler; sigaction(SIGALRM, &sa, NULL); sigaction(SIGINT, &sa, NULL); timer.it_value.tv_sec = dl_period.tv_sec; timer.it_value.tv_usec = dl_period.tv_nsec / 1000; timer.it_interval.tv_sec = dl_period.tv_sec; timer.it_interval.tv_usec = dl_period.tv_nsec / 1000; setitimer(ITIMER_REAL, &timer, NULL); #endif struct timespec t_exec; clock_gettime(CLOCK_REALTIME, &task.t_period); task.t_period = timespec_add(&task.t_period, &task_rst.dl_period);//start from next period task.t_deadline = timespec_add(&task.t_period, &task_rst.dl_period); clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &task.t_period, NULL); clock_gettime(CLOCK_THREAD_CPUTIME_ID, &task_rst.t_whole_thread_start); while(1) { clock_gettime(CLOCK_REALTIME, &task.t_begin); clock_gettime(CLOCK_THREAD_CPUTIME_ID, &task.t_thread_start); t_exec = timespec_add(&task.t_thread_start, &task_rst.dl_exec); if (!pure_overhead) { busy_wait(&t_exec, &task.t_deadline); } clock_gettime(CLOCK_THREAD_CPUTIME_ID, &task.t_thread_finish); clock_gettime(CLOCK_REALTIME, &task.t_end); task.t_thread_run = timespec_sub(&task.t_thread_finish, &task.t_thread_start); task.t_thread_remain = timespec_sub(&t_exec, &task.t_thread_finish); task.t_diff = timespec_sub(&task.t_end, &task.t_begin); task.t_slack = timespec_sub(&task.t_deadline, &task.t_end); task.t_offset = timespec_sub(&task.t_begin, &task.t_period); process_log(&task, &task_rst); task.t_period = timespec_add(&task.t_period, &task_rst.dl_period); task.t_deadline = timespec_add(&task.t_deadline, &task_rst.dl_period); //check total test time struct timespec t_now; clock_gettime(CLOCK_REALTIME, &t_now); if (duration && timespec_lower(&task_rst.t_exit, &t_now)) { print_result_exit(&t_now, &task, &task_rst); } clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &task.t_period, NULL); } } else { printf("usage: rt_task <period>:<budget>:<exec> <duration> [<log_switch>] [<scheduler>]\n"); } return 0; }
void *t_1(void *thread_params) { struct sched_param2 dl_params; struct timespec t_next, t_period, t_start, t_stop, ran_for, t_now, t_crit, t_exec; long tid = gettid(); int retval, i; cpu_set_t mask; __u64 crit, run1, runtime, deadline, period; /* * t_1 should go in budget overflow while in critical section */ run1 = 8U * NSEC_PER_MSEC; crit = 12U * NSEC_PER_MSEC; runtime = run1 + crit + (8U * NSEC_PER_MSEC); deadline = 40U * NSEC_PER_MSEC; period = deadline; t_period = nsec_to_timespec(&period); t_crit = nsec_to_timespec(&crit); signal(SIGHUP, sighandler); signal(SIGINT, sighandler); signal(SIGQUIT, sighandler); CPU_ZERO(&mask); CPU_SET(0, &mask); retval = sched_setaffinity(0, sizeof(mask), &mask); if (retval) { fprintf(stderr, "WARNING: could not set task affinity\n"); exit(-1); } memset(&dl_params, 0, sizeof(dl_params)); dl_params.sched_priority = 0; dl_params.sched_runtime = runtime; dl_params.sched_deadline = deadline; dl_params.sched_period = period; ftrace_write(marker_fd, "[thread %ld (t_1)]: setting rt=%llums dl=%llums\n", tid, runtime/NSEC_PER_MSEC, deadline/NSEC_PER_MSEC); retval = sched_setscheduler2(0, SCHED_DEADLINE, &dl_params); if (retval) { fprintf(stderr, "WARNING: could not set SCHED_DEADLINE" " policy!\n"); exit(-1); } clock_gettime(CLOCK_MONOTONIC, &t_next); for (i = 0; i < NRUN; i++) { ftrace_write(marker_fd, "[t_1] run starts\n"); clock_gettime(CLOCK_MONOTONIC, &t_start); ftrace_write(marker_fd, "[t_1] exec for %lluns\n", run1); busywait(run1); ftrace_write(marker_fd, "[t_1] locks mutex\n"); pthread_mutex_lock(&my_mutex); ftrace_write(marker_fd, "[t_1] exec for %lluns\n", crit); busywait(crit); ftrace_write(marker_fd, "[t_1] unlocks mutex\n"); pthread_mutex_unlock(&my_mutex); clock_gettime(CLOCK_MONOTONIC, &t_stop); t_next = timespec_add(&t_next, &t_period); ran_for = timespec_sub(&t_stop, &t_start); printf("[thread %ld]: run %d for %lluus\n", tid, i, timespec_to_usec(&ran_for)); ftrace_write(marker_fd, "[t_1] run ends\n"); clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &t_next, NULL); } retval = sched_setscheduler2(0, SCHED_OTHER, &dl_params); if (retval) { fprintf(stderr, "WARNING: could not set SCHED_OTHER" "policy!\n"); exit(-1); } }