void* timer_main(void* arg){ gd_thread_data_t *tdata = (gd_thread_data_t *) arg; thread_common(pthread_self(), tdata); long duration_usec = (tdata->duration * 1e6); int nperiods = (int) ceil( duration_usec / (double) timespec_to_usec(&tdata->period)); int period = 0; struct timespec t_next, t_now; t_next = tdata->main_start; int subframe_id; while(running && (period < nperiods)){ subframe_id = period%(num_cores_bs); t_next = timespec_add(&t_next, &tdata->period); clock_gettime(CLOCK_MONOTONIC, &t_now); common_time[subframe_id] = t_now; common_time_ref = t_now; common_time_next = t_next; if (timespec_lower(&t_now, &t_next)){ // sleep for remaining time clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &t_next, NULL); }else{ printf("timer is screwed\n"); } period++; } running = 0; pthread_exit(NULL); }
static inline int busy_wait(struct timespec *to, struct timespec *dl) { struct timespec t_step, t_wall; while(1) { clock_gettime(CLOCK_THREAD_CPUTIME_ID, &t_step); if (!timespec_lower(&t_step, to)) { return 0; } clock_gettime(CLOCK_REALTIME, &t_wall); if (!timespec_lower(&t_wall, dl)) { return 1; } } }
static inline busywait(struct timespec *to) { struct timespec t_step; while (1) { clock_gettime(CLOCK_THREAD_CPUTIME_ID, &t_step); if (!timespec_lower(&t_step, to)) break; } }
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; } }
static inline void process_log(task_data_t *p_task, task_result_t *p_rst) { static int first = 1; int64_t i_offset, i_diff, i_slack, i_thread_run, i_thread_remain; int after_middle; i_offset = timespec_to_nsec(&p_task->t_offset); i_diff = timespec_to_nsec(&p_task->t_diff); i_slack = timespec_to_nsec(&p_task->t_slack); i_thread_run = timespec_to_nsec(&p_task->t_thread_run); i_thread_remain = timespec_to_nsec(&p_task->t_thread_remain); after_middle = timespec_lower(&p_rst->t_middle, &p_task->t_begin); ++p_rst->cnt; if (after_middle) { ++p_rst->cnt_after_middle; } if (i_thread_remain > 0) { ++p_rst->lack_cnt; } if (i_slack < 0) { ++p_rst->miss_cnt; if (after_middle) { ++p_rst->miss_cnt_after_middle; } } p_rst->i_whole_thread_runtime += i_thread_run; if (first) { printf("%12s\t%12s\t%12s\t%12s\t%12s\n", "offset", "diff", "slack", "exec_time", "unfinished"); first = 0; } if (g_log) { printf("%12lld\t%12lld\t%12lld\t%12lld\t%12lld\n", i_offset, i_diff, i_slack, i_thread_run, i_thread_remain); } }
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* trans_main(void* arg){ gd_thread_data_t *tdata = (gd_thread_data_t *) arg; int id = tdata->ind; thread_common(pthread_self(), tdata); unsigned long abs_period_start = timespec_to_usec(&tdata->main_start); gd_timing_meta_t *timings; long duration_usec = (tdata->duration * 1e6); int nperiods = (int) ceil( duration_usec / (double) timespec_to_usec(&tdata->period)); timings = (gd_timing_meta_t*) malloc ( nperiods * sizeof(gd_timing_meta_t)); gd_timing_meta_t* timing; struct timespec t_next, t_deadline, trans_start, trans_end, t_temp, t_now; t_next = tdata->main_start; int period = 0; int bs_id = ((int)(id/num_ants)); int subframe_id; while(running && (period < nperiods)){ subframe_id = period%(num_cores_bs); // get current deadline and next period t_deadline = timespec_add(&t_next, &tdata->deadline); t_next = timespec_add(&t_next, &tdata->period); clock_gettime(CLOCK_MONOTONIC, &trans_start); /******* Main transport ******/ if (debug_trans==1) { int j, k; for(j=0; j <60000; j++){k=k+1;} } else { gd_trans_read(tdata->conn_desc); } /******* Main transport ******/ pthread_mutex_lock(&subframe_mutex[bs_id*num_cores_bs + subframe_id]); // subframe_avail[bs_id*num_cores_bs + subframe_id] = (subframe_avail[bs_id*num_cores_bs + subframe_id]+1)%(num_ants); subframe_avail[bs_id*num_cores_bs + subframe_id] ++; // printf("subframe_avail:%d %d\n",bs_id*num_cores_bs + subframe_id,subframe_avail[bs_id*num_cores_bs + subframe_id]); // hanging fix -- if trans misses a proc, reset the subframe available counter if (subframe_avail[bs_id*num_cores_bs + subframe_id] == (num_ants+1)) { subframe_avail[bs_id*num_cores_bs + subframe_id] = 1; } pthread_cond_signal(&subframe_cond[bs_id*num_cores_bs + subframe_id]); pthread_mutex_unlock(&subframe_mutex[bs_id*num_cores_bs + subframe_id]); clock_gettime(CLOCK_MONOTONIC, &trans_end); /*****************************/ timing = &timings[period]; timing->ind = id; timing->period = period; timing->abs_period_time = timespec_to_usec(&t_next); timing->rel_period_time = timing->abs_period_time - abs_period_start; timing->abs_start_time = timespec_to_usec(&trans_start); timing->rel_start_time = timing->abs_start_time - abs_period_start; timing->abs_end_time = timespec_to_usec(&trans_end); timing->rel_end_time = timing->abs_end_time - abs_period_start; timing->abs_deadline = timespec_to_usec(&t_deadline); timing->rel_deadline = timing->abs_deadline - abs_period_start; timing->actual_duration = timing->rel_end_time - timing->rel_start_time; timing->miss = (timing->rel_deadline - timing->rel_end_time >= 0) ? 0 : 1; if (timing->actual_duration > 1000){ // log_critical("Transport overload. Thread[%d] Duration= %lu us. Reduce samples or increase threads", // tdata->ind, timing->actual_duration); } clock_gettime(CLOCK_MONOTONIC, &t_now); // check if deadline was missed if (timespec_lower(&t_now, &t_next)){ // sleep for remaining time clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &t_next, NULL); }else{ printf("Transport %d is too slow\n", id); } period ++; } clock_gettime(CLOCK_MONOTONIC, &t_temp); log_notice("Trans thread [%d] ran for %f s", id, ((float) (timespec_to_usec(&t_temp)-abs_period_start))/1e6); fprintf(tdata->log_handler, "#idx\t\tabs_period\t\tabs_deadline\t\tabs_start\t\tabs_end" "\t\trel_period\t\trel_start\t\trel_end\t\tduration\t\tmiss\n"); int i; for (i=0; i < nperiods; i++){ log_timing(tdata->log_handler, &timings[i]); } fclose(tdata->log_handler); log_notice("Exit trans thread %d", id); running = 0; for (i=0;i<proc_nthreads;i++) { pthread_mutex_lock(&subframe_mutex[i]); subframe_avail[i]=-1; pthread_cond_signal(&subframe_cond[i]); pthread_mutex_unlock(&subframe_mutex[i]); } pthread_exit(NULL); }