unsigned int sysctl_sched_rt_period = 1000000; int sysctl_sched_rt_runtime = 950000; // 参考: // http://soft.chinabyte.com/os/22/12359522.shtml // http://hi.baidu.com/_kouu/item/0fe32610e493314be75e06d1 // http://blog.chinaunix.net/uid-27052262-id-3239263.html // http://blog.csdn.net/wudongxu/article/details/8574749 // http://lwn.net/Articles/296419/ // 调度初始化 // 函数任务: // 1.初始化rootdomain // rootdomain指示rq可运行的cpu集合 // 2.初始化real-time task对cpu的占有率 // sysctl_sched_rt_period代表rt进程的调度周期 // sysctl_sched_rt_runtime代表rt进程在调度周期中可运行的时间 // 3.初始化per-cpu rq // 3.1 初始化公平调度队列,实时调度队列 // 3.2 初始化cpu负载记录数组 // 3.3 初始化cpu使用的tick hrtimer // 4.初始化current(init_task)为idle task // 4.1 设置current由公平调度管理 1.1 void __init sched_init(void) { int i, j; #ifdef CONFIG_SMP //初始化默认的调度域 init_defrootdomain(); #endif //rt_bandwidth表示实时进程对cpu的占有率 init_rt_bandwidth(&def_rt_bandwidth, global_rt_period(), global_rt_runtime()); //初始化per-cpu rq for_each_possible_cpu(i) { struct rq *rq; //per-cpu 运行队列 rq = cpu_rq(i); raw_spin_lock_init(&rq->lock); rq->nr_running = 0; rq->calc_load_active = 0; rq->calc_load_update = jiffies + LOAD_FREQ; //初始化公平调度策略、实时调度策略队列 init_cfs_rq(&rq->cfs, rq); init_rt_rq(&rq->rt, rq); //调度队列中,实时进程对cpu的占有率 rq->rt.rt_runtime = def_rt_bandwidth.rt_runtime; //分5个等级记录cpu的负载情况 for (j = 0; j < CPU_LOAD_IDX_MAX; j++) rq->cpu_load[j] = 0; #ifdef CONFIG_SMP rq->sd = NULL; rq->rd = NULL; rq->post_schedule = 0; rq->active_balance = 0; rq->next_balance = jiffies; rq->push_cpu = 0; //rq运行的cpu rq->cpu = i; rq->online = 0; rq->migration_thread = NULL; rq->idle_stamp = 0; rq->avg_idle = 2*sysctl_sched_migration_cost; INIT_LIST_HEAD(&rq->migration_queue); rq_attach_root(rq, &def_root_domain); #endif //初始化rq使用的hrtimer init_rq_hrtick(rq); atomic_set(&rq->nr_iowait, 0); } set_load_weight(&init_task); //load balancing软中断 #ifdef CONFIG_SMP open_softirq(SCHED_SOFTIRQ, run_rebalance_domains); #endif atomic_inc(&init_mm.mm_count); //通知底层体系结构不需要切换虚拟地址空间的用户空间部分 enter_lazy_tlb(&init_mm, current); //将当前进程,即init_task更新为idle thread init_idle(current, smp_processor_id()); //下次进行load balancing的时间戳 calc_load_update = jiffies + LOAD_FREQ; //当前进程关联的调度累 current->sched_class = &fair_sched_class; perf_event_init(); //标识调度器开始运行 scheduler_running = 1; } // 参考 http://blog.csdn.net/bullbat/article/details/7160246 1.2 struct rq { raw_spinlock_t lock; //就绪队列中进程数 unsigned long nr_running; #define CPU_LOAD_IDX_MAX 5 //分5个等级记录就绪队列的负载情况 //在系统初始化的时候sched_init把rq的cpu_load array初始化为0,之后通过函数update_cpu_load //公式如下: // cpu_load[0]等于rq中load.weight的值 // cpu_load[1]=(cpu_load[1]*(2-1)+cpu_load[0])/2 // cpu_load[2]=(cpu_load[2]*(4-1)+cpu_load[0])/4 // cpu_load[3]=(cpu_load[3]*(8-1)+cpu_load[0])/8 // cpu_load[4]=(cpu_load[4]*(16-1)+cpu_load[0]/16 //通过this_cpu_load返回的cpu load值是cpu_load[0] //进行cpu blance或migration时,通过调用source_load target_load取得对该处理器cpu_load index值。 unsigned long cpu_load[CPU_LOAD_IDX_MAX]; //本schedule entity的load->weight的总和 struct load_weight load; //scheduler tick中调用update_cpu_load时,这个值就增加一,可以用来反馈目前cpu load更新的次数。 unsig