调度子系统6_负载均衡(三)

来源:互联网 发布:python 分析网页 编辑:程序博客网 时间:2024/06/07 03:29
//负载均衡//在sched_domain中进行负载均衡,检查是否可以通过最繁忙的组中迁移一些进程到本cpu//函数参数://this_cpu, 其上执行负载均衡的cpu//this_rq, 其上执行负载均衡的rq//sd, 其上执行负载均衡的sched domain//idle, this_cpu的状态//CPU_SCHED_IDLE,this_cpu空闲//CPU_NOT_IDLE,this_cpu不空闲//balance,sd中是否均衡//函数任务://1.获取当前在线的cpu到本地//2.sched domain中寻找最忙的sched group//3.sched group中寻找最忙的cpu//4.最忙cpu就绪进程数>=2,从最忙cpu移动进程到this_cpu//4.1 关本cpu中断//4.2 获取this_cpu, 最忙cpu的rq的锁//4.3 移动进程到this_cpu//4.4 如果最忙cpu中所有进程均设置亲和性,移动进程失败//4.4.1 从掩码中清除最忙cpu,如果掩码不空,则重复步骤2进行负载均衡//4.5 如果移动进程成功//4.5.1 如果本cpu不是this_cpu,通过ipi唤醒this_cpu重调度//4.5.2 更新domain负载均衡失败次数计数器为 0//5.最忙cpu就绪进程数<=1,或从最忙cpu移动进程失败//5.1 检查是否可以进行主动负载均衡(负载均衡失败次数上限)//5.1.1 设置最忙cpu的active_balance标志//5.1.2 设置最忙cpu的push_cpu为this_cpu,表示是this_cpu向其发起了主动负载均衡//5.1.3 唤醒最忙cpu的migration_thread进程//5.1.4 更新domain负载均衡失败次数计数器为 上限-1//6.调整负载均衡时间间隔//6.1 如果没有发起主动负载均衡,下次尽早到期//6.2 否则,推迟下次负载均衡的时间1.1 static int load_balance(int this_cpu, struct rq *this_rq,struct sched_domain *sd, enum cpu_idle_type idle,int *balance){int ld_moved, all_pinned = 0, active_balance = 0, sd_idle = 0;struct sched_group *group;unsigned long imbalance;struct rq *busiest;unsigned long flags;struct cpumask *cpus = __get_cpu_var(load_balance_tmpmask);//在线的cpucpumask_copy(cpus, cpu_active_mask);//SD_SHARE_CPUPOWER,Domain members share cpu power//SD_POWERSAVINGS_BALANCE, Balance for power savings//cpu空闲,共享cpu power,power saving不进行balanceif (idle != CPU_NOT_IDLE && sd->flags & SD_SHARE_CPUPOWER &&    !test_sd_parent(sd, SD_POWERSAVINGS_BALANCE))sd_idle = 1;redo://在sched domain中寻找最忙的sched groupgroup = find_busiest_group(sd, this_cpu, &imbalance, idle, &sd_idle,   cpus, balance);//sched group之间已经均衡if (*balance == 0)goto out_balanced;//在sched group中寻找最忙的rqbusiest = find_busiest_queue(group, idle, imbalance, cpus);//rq之间已经均衡if (!busiest) {goto out_balanced;}ld_moved = 0;//最忙cpu可运行的进程>=2,从最忙cpu移动进程到本cpuif (busiest->nr_running > 1) {//关本cpu中断local_irq_save(flags);//同时获取本rq和最忙rq的锁double_rq_lock(this_rq, busiest);//从最忙rq移动进程到本rqld_moved = move_tasks(this_rq, this_cpu, busiest, imbalance, sd, idle, &all_pinned);double_rq_unlock(this_rq, busiest);local_irq_restore(flags);//成功移动进程到this_cpu,但运行负载均衡的cpu非当前cpu,唤醒this_cpu,if (ld_moved && this_cpu != smp_processor_id())resched_cpu(this_cpu);//最忙cpu中的进程全部设置亲和性被绑定if (unlikely(all_pinned)) {//不在考虑此最忙的cpucpumask_clear_cpu(cpu_of(busiest), cpus);//继续在sched domain中寻找忙碌的cpuif (!cpumask_empty(cpus))goto redo;//domain中的所有cpu都不能进行负载均衡,退出goto out_balanced;}}//最忙cpu可运行的进程<=1或者移动进程失败if (!ld_moved) {//sd->nr_balance_failed > sd->cache_nice_tries+2时,启动主动负载均衡//主动负载均衡://最忙的cpu主动向空闲cpu搬移进程//步骤://1.从lowest-level scheduling domain遍历每一个CPU GROUP中的cpu//1.1 如果cpu idle,则向其迁移一个进程//1.2 继续寻找idle的cpu//2.当最忙的cpu遍历完该scheduling domain中的每一个CPU GROUP的每一个cpu//2.1 向higher-level scheduling domain,直到其只剩两个进程或者遇到//没有设置SD_LOAD_BALANCE的scheduling domainif (need_active_balance(sd, sd_idle, idle)) {//关中断,获取最忙cpu rq的锁raw_spin_lock_irqsave(&busiest->lock, flags);//this_cpu不在最忙cpu允许的域中if (!cpumask_test_cpu(this_cpu,      &busiest->curr->cpus_allowed)) {raw_spin_unlock_irqrestore(&busiest->lock,    flags);//等价于全部设置了亲和性all_pinned = 1;goto out_one_pinned;}//发起主动负载均衡if (!busiest->active_balance) {//设置最忙cpu的active_balance标志busiest->active_balance = 1;//向其发起主动负载均衡的cpubusiest->push_cpu = this_cpu;active_balance = 1;}raw_spin_unlock_irqrestdore(&busiest->lock, flags);//唤醒最忙cpu的migration_thread进程if (active_balance)wake_up_process(busiest->migration_thread);//重置负载均衡失败次数sd->nr_balance_failed = sd->cache_nice_tries+1;}}else{//成功进行了负载均衡,nr_balance_failed设置为0sd->nr_balance_failed = 0;}//调整负载均衡时间间隔if (likely(!active_balance)) {//没有发起主动负载均衡,下次尽早到期sd->balance_interval = sd->min_interval;} else {//推迟下一次负载均衡的时间if (sd->balance_interval < sd->max_interval)sd->balance_interval *= 2;}if (!ld_moved && !sd_idle && sd->flags & SD_SHARE_CPUPOWER &&    !test_sd_parent(sd, SD_POWERSAVINGS_BALANCE))ld_moved = -1;goto out;out_balanced:schedstat_inc(sd, lb_balanced[idle]);sd->nr_balance_failed = 0;out_one_pinned:if ((all_pinned && sd->balance_interval < MAX_PINNED_INTERVAL) ||(sd->balance_interval < sd->max_interval))sd->balance_interval *= 2;if (!sd_idle && sd->flags & SD_SHARE_CPUPOWER &&    !test_sd_parent(sd, SD_POWERSAVINGS_BALANCE))ld_moved = -1;elseld_moved = 0;out:if (ld_moved)update_shares(sd);return ld_moved;}

1 0
原创粉丝点击