调度子系统4_负载均衡(一)

来源:互联网 发布:php环境文件管理器 编辑:程序博客网 时间:2024/06/05 11:14
//参考:http://blog.csdn.net/dog250/article/details/5303561//负载均衡//当rq->next_balance到时,触发负载均衡//调用路径:scheduler_tick->trigger_load_balance//注://nohz.cpu_mask中的cpu表示停用了周期时钟//函数任务://1.如果进入tick的时候rq变得有事可做,并且之前由本cpu执行idle load balance//1.1 不再做idle load balance//1.2 nohz.cpu_mask中选择一个cpu负责idle load balance//1.3 通过ipi通知彼cpu负责ilb//2.如果所有cpu均处于idle状态,之前由本cpu做idle load balance//2.1 没有必要再做idb,通知本cpu停止idle load balance//3.如果本cpu处于idle状态,其他cpu做idle load balance//3.1 ilb的cpu会代此cpu执行load balance,不需要raise SCHED_SOFTIRQ//4.本cpu没有加入到任何domain,则不需要在domain间load balance//5.如果到达执行load balance时间点//5.1 raise SCHED_SOFTIRQ1.1 static inline void trigger_load_balance(struct rq *rq, int cpu){#ifdef CONFIG_NO_HZ//rq->idle_at_tick = 0表示rq上运行的非idle进程//rq->in_nohz_recently表示最近关闭了周期时钟if (rq->in_nohz_recently && !rq->idle_at_tick) {rq->in_nohz_recently = 0;//如果之前由本cpu执行idle load balanceif (atomic_read(&nohz.load_balancer) == cpu) {//nohz.cpu_mask中的cpu表示停用了周期时钟,在select_nohz_load_balancer中被加入cpumask_clear_cpu(cpu, nohz.cpu_mask);//进入tick的时候rq变得有事可做,则不再做idle load balanceatomic_set(&nohz.load_balancer, -1);}//从nohz.cpu_mask中选择一个cpu做idle load balance if (atomic_read(&nohz.load_balancer) == -1) {int ilb = find_new_ilb(cpu);if (ilb < nr_cpu_ids){//向该cpu发送ipiresched_cpu(ilb);}}}//如果所有cpu均处于idle状态,本cpu做idle load balance,则通知本cpu停止idle load balanceif (rq->idle_at_tick && atomic_read(&nohz.load_balancer) == cpu &&    cpumask_weight(nohz.cpu_mask) == num_online_cpus()) {resched_cpu(cpu);return;}//如果本cpu处于idle状态,其他cpu做idle load balance,则不需要raise其SCHED_SOFTIRQif (rq->idle_at_tick && atomic_read(&nohz.load_balancer) != cpu &&    cpumask_test_cpu(cpu, nohz.cpu_mask))return;#endif//本cpu没有加入到任何domain,则不需要raise其SCHED_SOFTIRQif (time_after_eq(jiffies, rq->next_balance) &&    likely(!on_null_domain(cpu))){//raise其SCHED_SOFTIRQraise_softirq(SCHED_SOFTIRQ);}}//负载均衡软中断//由trigger_load_balance函数触发//函数任务://1.自下而上遍历cpu所属的sched domain,对其进行负载均衡//2.如果本cpu负责idle load balance,代停用周期时钟的cpu执行load balance//2.1 遍历nohz.cpu_mask中所有的idle cpu//2.2.1 代其执行步骤1//2.2.2 如果这这段时间内本cpu有非idle进程就绪,退出ilb,下一次负载均衡时发生时再ilb//2.2.3 如果idle cpu下一次进行负载均衡的时间戳大于本cpu//2.2.3.1 更新idle cpu下一次负载均衡的时间为本cpu进行负载均衡的时间戳2.1 static void run_rebalance_domains(struct softirq_action *h){int this_cpu = smp_processor_id();struct rq *this_rq = cpu_rq(this_cpu);//cpu当前状态//如果rq上当前运行的为idle task则cpu为idle状态enum cpu_idle_type idle = this_rq->idle_at_tick ?CPU_IDLE : CPU_NOT_IDLE;//为cpu在同一个domain内执行load balancerebalance_domains(this_cpu, idle);#ifdef CONFIG_NO_HZ//如果本cpu负责idle load balance,代停用周期时钟的cpu执行load balanceif (this_rq->idle_at_tick &&    atomic_read(&nohz.load_balancer) == this_cpu) {struct rq *rq;int balance_cpu;for_each_cpu(balance_cpu, nohz.cpu_mask) {if (balance_cpu == this_cpu)continue;//非idle进程就绪,不在执行idle load balance,下一次load balance发生时再ilbif (need_resched())break;//代idle的cpu执行load balancerebalance_domains(balance_cpu, CPU_IDLE);//更新本rq下一次load balance的时间为所有被代理rq执行load balance中最早的rq = cpu_rq(balance_cpu);if (time_after(this_rq->next_balance, rq->next_balance))this_rq->next_balance = rq->next_balance;}}#endif}//负载均衡//在cpu所属的sched domain层次结构上执行load balance//调用路径:run_rebalance_domains->rebalance_domains//函数参数://idle,cpu处于的状态//CPU_IDLE,cpu上运行的idle task//CPU_NOT_IDLE,cpu上运行的非idle task//函数任务://1.自上而下遍历rq所属的所有sched domain//1.1 如果此domain不需要执行load balance(没有设置SD_LOAD_BALANCE),则跳过//1.2 计算domain执行load balance的时间间隔//1.2.1 由domain的balance_interval指定load balance在domain上执行的时间间隔//1.2.2 降低非idle状态的cpu通过放大时间间隔降低load balance执行的频率//1.2.3 在HZ*NR_CPUS/10时间内,必须对domain执行一次load balance//1.3 如果domain的load balance需要串行执行,则获取balance锁//1.4 如果当前时间到达domain load balance执行的时间点//1.4.1 从同一个domain的其他cpu拉进程到本cpu执行//1.4.2 如果成功从其他cpu上拉进程到本cpu,则设置cpu不再为idle状态//1.5 如果domain的load balance需要串行执行,则释放balance锁//1.6 通过next_balance记录rq下一次执行load balance的时间为其所属domain中//最近的load balance时间//1.7 如果返回值balance=0,说明已经完成了负载均衡,退出遍历,否则继续1.1//2.更新rq下一次执行load balance的时间为其所属domain中最近的load balance时间3.1 static void rebalance_domains(int cpu, enum cpu_idle_type idle){int balance = 1;struct rq *rq = cpu_rq(cpu);unsigned long interval;struct sched_domain *sd;//rebalance执行最近的时间unsigned long next_balance = jiffies + 60*HZ;int update_next_balance = 0;int need_serialize;//遍历cpu所属的所有sched domainfor_each_domain(cpu, sd) {//此domain不需要load balanceif (!(sd->flags & SD_LOAD_BALANCE))continue;//domain执行load balance的时间间隔interval = sd->balance_interval;//降低非idle状态cpu的load balance的执行频率//通过放大load balance执行的最小间隔达到降低频率的目的if (idle != CPU_IDLE)interval *= sd->busy_factor;interval = msecs_to_jiffies(interval);if (unlikely(!interval))interval = 1;//最大间隔为HZ*NR_CPUS/10if (interval > HZ*NR_CPUS/10)interval = HZ*NR_CPUS/10;//此domain的load balance需要串行执行need_serialize = sd->flags & SD_SERIALIZE;if (need_serialize) {//试图获取串行load balance失败,则放弃此次load balanceif (!spin_trylock(&balancing))goto out;}//如果当前时间到达domain load balance执行的时间点if (time_after_eq(jiffies, sd->last_balance + interval)) {//从同一个domain的其他cpu拉进程到本cpu执行if (load_balance(cpu, rq, sd, idle, &balance)) {//由于已经从其他cpu上拉来了进程,因此本cpu不在是idle状态idle = CPU_NOT_IDLE;}//更新domain上一次load balance的时间为当前jiffiessd->last_balance = jiffies;}if (need_serialize)spin_unlock(&balancing);out:if (time_after(next_balance, sd->last_balance + interval)) {//next_balance记录下一次执行load balance最近的时间next_balance = sd->last_balance + interval;update_next_balance = 1;}//完成均衡if (!balance)break;}//更新rq下一次load balance执行时间为所属domain中下一次load balance最早的时间if (likely(update_next_balance))rq->next_balance = next_balance;}

0 0
原创粉丝点击