deadline调度学习

deadline调度学习 本篇通过几个方面来看deadline调度器1、deadline的设置2、deadline的任务的添加3、deadline的任务的调度deadline的设置deadline调度器不允许直接通过kernel_clone的方式创建需要通过sched_setattr的方式将指定pid task修改为deadline调度器并进行必要参加的赋值,大体流程图如下首先通过系统调用sched_setattr主动来设置指定pid task的优先级别SYSCALL_DEFINE3(sched_setattr,pid_t,pid,structsched_attr__user*,uattr,unsignedint,flags){structsched_attrattr;structtask_struct*p;intretval;if(!uattr||pid0||flags)return-EINVAL;retvalsched_copy_attr(uattr,attr);if(retval)returnretval;if((int)attr.sched_policy0)return-EINVAL;if(attr.sched_flagsSCHED_FLAG_KEEP_POLICY)attr.sched_policySETPARAM_POLICY;rcu_read_lock();retval-ESRCH;pfind_process_by_pid(pid);if(likely(p))get_task_struct(p);rcu_read_unlock();if(likely(p)){if(attr.sched_flagsSCHED_FLAG_KEEP_PARAMS)get_params(p,attr);retvalsched_setattr(p,attr);put_task_struct(p);}returnretval;}__setscheduler_params:void__setparam_dl(structtask_struct*p,conststructsched_attr*attr){structsched_dl_entity*dl_sep-dl;dl_se-dl_runtimeattr-sched_runtime;dl_se-dl_deadlineattr-sched_deadline;dl_se-dl_periodattr-sched_period?:dl_se-dl_deadline;dl_se-flagsattr-sched_flagsSCHED_DL_FLAGS;dl_se-dl_bwto_ratio(dl_se-dl_period,dl_se-dl_runtime);dl_se-dl_densityto_ratio(dl_se-dl_deadline,dl_se-dl_runtime);}__setscheduler_prio:staticvoid__setscheduler_prio(structtask_struct*p,intprio){//根据优先级设定调度策略if(dl_prio(prio))p-sched_classdl_sched_class;elseif(rt_prio(prio))p-sched_classrt_sched_class;elsep-sched_classfair_sched_class;p-prioprio;}上述动作做完后就将task加到指定的调度器任务中staticinlinevoidenqueue_task(structrq*rq,structtask_struct*p,intflags){if(!(flagsENQUEUE_NOCLOCK))update_rq_clock(rq);if(!(flagsENQUEUE_RESTORE)){sched_info_enqueue(rq,p);psi_enqueue(p,(flagsENQUEUE_WAKEUP)!(flagsENQUEUE_MIGRATED));}uclamp_rq_inc(rq,p);p-sched_class-enqueue_task(rq,p,flags);if(sched_core_enabled(rq))sched_core_enqueue(rq,p);}deadline的任务的添加大概调用流程如下enqueue_task_dl - enqueue_dl_entity - __enqueue_dl_entity- rb_add_cached这里对调用细节不作论述只关注几个重要点一、deadline的设置在上面已经有相关的配置了但是相对值。还需要转化成需要数据这里需要把设置的相对时间变成绝对截止时间二、deadline核心的任务添加过程从上面可知deadline调用器。使用的红黑二叉树左子树优先级最高。根据deadline值大小进行插入。插入完成后需要对二叉树作相关处理 以满足红黑二叉树特性。deadline的任务的调度在进行任务调度时候如果deadline调度器有任务可供调度则会调用其pick_next_task_dl的回调函数staticstructtask_struct*pick_next_task_dl(structrq*rq){structtask_struct*p;ppick_task_dl(rq);//获取一个优化级最高的task就是上面所说的rb_leftmost//#define rb_first_cached(root) (root)-rb_leftmostif(p)set_next_task_dl(rq,p,true);returnp;}staticvoidset_next_task_dl(structrq*rq,structtask_struct*p,bool first){structsched_dl_entity*dl_sep-dl;structdl_rq*dl_rqrq-dl;p-se.exec_startrq_clock_task(rq);//记录开始执行的时间if(on_dl_rq(p-dl))update_stats_wait_end_dl(dl_rq,dl_se);/* You cant push away the running task */dequeue_pushable_dl_task(rq,p);//将此task从二叉树上移除不能老是占位if(!first)return;if(hrtick_enabled_dl(rq))start_hrtick_dl(rq,p);//启动高精度定时器if(rq-curr-sched_class!dl_sched_class)update_dl_rq_load_avg(rq_clock_pelt(rq),rq,0);deadline_queue_push_tasks(rq);}#ifdefCONFIG_SCHED_HRTICKstaticvoidstart_hrtick_dl(structrq*rq,structtask_struct*p){//定时器的超时时间为runtime也就是说task运行时间为runtime大小hrtick_start(rq,p-dl.runtime);}#else/* !CONFIG_SCHED_HRTICK */staticvoidstart_hrtick_dl(structrq*rq,structtask_struct*p){}#endif下面来看看定时器超时的处理一、定时器的初始化staticvoidhrtick_rq_init(structrq*rq){#ifdefCONFIG_SMPINIT_CSD(rq-hrtick_csd,__hrtick_start,rq);#endifhrtimer_init(rq-hrtick_timer,CLOCK_MONOTONIC,HRTIMER_MODE_REL_HARD);rq-hrtick_timer.functionhrtick;//超时回调函数}staticenumhrtimer_restarthrtick(structhrtimer*timer){structrq*rqcontainer_of(timer,structrq,hrtick_timer);structrq_flagsrf;WARN_ON_ONCE(cpu_of(rq)!smp_processor_id());rq_lock(rq,rf);update_rq_clock(rq);//调用到了调度器的task_tick回调函数rq-curr-sched_class-task_tick(rq,rq-curr,1);rq_unlock(rq,rf);returnHRTIMER_NORESTART;}这里需要注意的是 task_tick这个函数在系统的tick 定时器里面也会调用二、定时器超时处理staticvoidtask_tick_dl(structrq*rq,structtask_struct*p,intqueued){//更新当前状态并修改runtime值大小为剩下时间update_curr_dl(rq);update_dl_rq_load_avg(rq_clock_pelt(rq),rq,1);/* * Even when we have runtime, update_curr_dl() might have resulted in us * not being the leftmost task anymore. In that case NEED_RESCHED will * be set and schedule() will start a new hrtick for the next task. */if(hrtick_enabled_dl(rq)queuedp-dl.runtime0is_leftmost(p,rq-dl))//如果runtime时间大于0则会restart此定时器并使用最新的超时时间start_hrtick_dl(rq,p);}上面的处理比较清晰由于tick定时器会不断触发这里的runtime值为持续减少。如果runtime小于等于0或者调用yield_task_dl回调函数都会将当前处理的task移除二叉树。并重新进行任务调度。deadline任务调度器核心是任务的添加、移除、调度。这里的二叉树的使用策略搞清楚大体就能明白deadline的调度器使用逻辑了