【内核调度、负载均衡】【detach_tasks】

detach_tasks

在load balance中会将busiest cpu上的task detach掉,然后atach在local cpu上。返回值为detach的task的数量

/*
 * detach_tasks() -- tries to detach up to imbalance weighted load from
 * busiest_rq, as part of a balancing operation(操作) within domain "sd".
 *
 * Returns number of detached tasks if successful and 0 otherwise.
 */
 // 返回值为detach的task的数量
static int detach_tasks(struct lb_env *env, struct rq_flags *rf)
{
	//src_rq是busiest的rq
	struct list_head *tasks = &env->src_rq->cfs_tasks;
	struct task_struct *p;
	unsigned long load;
	int detached = 0;

	lockdep_assert_held(&env->src_rq->lock);

	if (env->imbalance <= 0)
		return 0;
	/* (7.6.1) 遍历busiest rq中的进程 */
	while (!list_empty(tasks)) {
		/*
		 * We don't want to steal all, otherwise we may be treated likewise,
		 * which could at worst lead to a livelock crash.
		 */
		 /* (7.6.2) 如果dest cpu不是idle,不能将busiest cpu迁移到idle状态 */  
		if (env->idle != CPU_NOT_IDLE && env->src_rq->nr_running <= 1)
			break;

		p = list_first_entry(tasks, struct task_struct, se.group_node);

		env->loop++;
		/* We've more or less seen every task there is, call it quits */
		/* (7.6.3) 遍历任务最多不超过sysctl_sched_nr_migrate(32) */
		if (env->loop > env->loop_max)
			break;

		/* take a breather every nr_migrate tasks */
		/* (7.6.4) 每sched_nr_migrate_break个任务遍历需要跳出休息一下,
         如果没有达到env->loop_max,后面会重来*/
		if (env->loop > env->loop_break) {
			env->loop_break += sched_nr_migrate_break;
			env->flags |= LBF_NEED_BREAK;
			break;
		}
		/* (7.6.5) 判断任务是否支持迁移? */
		if (!can_migrate_task(p, env))
			goto next;
		/* (7.6.6) 获取p进程相对顶层cfs_rq的负载, 
					根据负载判断进程是否适合迁移*/
		load = task_h_load(p);
		// LB_MIN 定义的是false
		if (sched_feat(LB_MIN) && load < 16 && !env->sd->nr_balance_failed)
			goto next;

		if ((load / 2) > env->imbalance)
			goto next;
		// 把task加到env的list里面
		detach_task(p, env, rf);
		list_add(&p->se.group_node, &env->tasks);

		detached++;
		env->imbalance -= load;

#ifdef CONFIG_PREEMPT
### PyTorch `detach` 与 `detach_` 的用法及区别 #### 1. **`detach()` 方法** `detach()` 是一种非原地操作 (out-of-place operation),它会返回一个新的张量,该张量与原始张量共享相同的底层数据存储,但新张量不再属于原有的计算图的一部分[^3]。这意味着新的张量不会记录任何对其的操作,也不会参与到梯度计算中。 以下是 `detach()` 的主要特点: - 不会影响原始张量的计算图。 - 新张量的 `requires_grad` 属性始终为 `False`,无论原始张量是否有梯度需求。 - 如果需要修改分离后的张量的数据而不影响原始张量的梯度流,则应使用此方法。 示例代码如下: ```python import torch x = torch.tensor([2.0, 3.0], requires_grad=True) y = x * 3 z = y.detach() # 创建了一个脱离计算图的新张量 z print("z requires_grad:", z.requires_grad) # 输出 False ``` --- #### 2. **`detach_()` 方法** `detach_()` 则是一种原地操作 (in-place operation)[^4],它会在原有张量的基础上直接将其从计算图中移除,并将自身的 `requires_grad` 属性设置为 `False`。由于它是原地操作,因此会对调用它的张量本身造成永久性的更改——即将其从计算图中完全剥离。 需要注意的是,一旦执行了 `detach_()`,原本指向同一块内存区域的所有变量都会受到影响,它们都将失去对原来计算图的连接关系。 具体表现可以通过下面的例子来说明: ```python import torch x = torch.tensor([2.0, 3.0], requires_grad=True) y = x * 3 y.detach_() # 将 y 自身从计算图中移除 print("y after detach_: ", y.requires_grad) # 输出 False try: y.sum().backward() except RuntimeError as e: print(e) # 报错提示:element 0 of tensors does not require grad and does not have a grad_fn ``` 在这里可以看到,在应用 `detach_()` 后再尝试进行反向传播时会发生错误,因为此时已经没有任何路径能够追溯回输入端以完成链式法则所需的导数累积过程。 --- #### 3. **两者的主要差异总结** | 特性 | `detach()` | `detach_()` | |-------------------------|-------------------------------------|-----------------------------------| | 是否改变原对象 | 否 | 是 | | 返回值 | 新的对象 | None | | 计算图状态 | 复制一份独立于现有计算图之外的新实例 | 当前对象被标记为不需要跟踪历史 | | 性能考虑 | 更安全(无副作用),适合复杂场景 | 效率更高但在简单调整中有风险 | 当决定采用哪种方式取决于实际应用场景以及个人偏好等因素综合考量之后才能做出最佳选择。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值