当前位置: 首页 > article >正文

【Linux内核】trigger_load_balance(struct rq *rq)内核函数

trigger_load_balance(struct rq *rq) 是 Linux 内核中用于触发负载均衡的关键函数,主要在多处理器(SMP)环境下工作。其主要目的是确保系统中各个 CPU 的负载尽可能均匀,从而提高整体性能和响应能力。以下是对该函数的详细解析。

触发时机

在 Linux 内核中,负载均衡通常在以下情况下被触发:

  • 时钟中断:每当 CPU 接收到时钟中断时,scheduler_tick() 函数会被调用。在这个函数中,如果系统配置了 CONFIG_SMP,则会调用 trigger_load_balance(rq) 来检查是否需要进行负载均衡。
  • 条件判断:在调用 trigger_load_balance() 之前,会检查当前 CPU 是否处于空闲状态,以及是否附加到 NULL 域。如果满足这些条件,则不会进行负载均衡
/*
 * Trigger the SCHED_SOFTIRQ if it is time to do periodic load balancing.
 */
void trigger_load_balance(struct rq *rq)
{
	/*
	 * Don't need to rebalance while attached to NULL domain or
	 * runqueue CPU is not active
	 */
	if (unlikely(on_null_domain(rq) || !cpu_active(cpu_of(rq))))
		return;

	if (time_after_eq(jiffies, rq->next_balance))
		raise_softirq(SCHED_SOFTIRQ);

	nohz_balancer_kick(rq);
}

功能解析

检查条件:首先,函数会检查当前的运行队列(runqueue)是否处于有效状态。如果 CPU 处于空闲状态或不活跃,则直接返回,不进行负载均衡

触发软中断:如果当前时间已经超过了下次负载均衡的预定时间(rq->next_balance),则通过 raise_softirq(SCHED_SOFTIRQ) 触发一个软中断,通知系统执行负载均衡24。
无时钟负载均衡:接着,调用 nohz_balancer_kick(rq) 来处理无时钟(NOHZ)负载均衡的逻辑。这一部分主要用于在 CPU 处于空闲状态时,通过其他活跃 CPU 来唤醒空闲 CPU,以便分担任务13.

负载均衡策略

在 Linux 内核中,负载均衡的策略主要包括:

  • 拉取(Pull):轻负载的 CPU 从重负载的 CPU 中拉取任务,这是最常用的方式。
  • 推送(Push):重负载的 CPU 向轻负载的 CPU 推送任务,这种方式也被称为主动负载均衡(active load balance)

周期性与空闲平衡

  • 周期性负载均衡:通过定期检查和触发 trigger_load_balance() 来实现,确保在有任务运行时进行平衡。
  • 空闲平衡:当某个 CPU 进入空闲状态时,其他 CPU 会尝试唤醒它并分配任务,以避免某些 CPU 长时间处于空闲状态而其他 CPU 却过于繁忙

代码解析

on_null_domain(rq) !cpu_active(cpu_of(rq)) 这两个判断逻辑函数用于检查特定条件,以决定是否进行负载均衡。
以下是对这两个函数的详细解析。

on_null_domain(rq)

#if NR_CPUS > 1
/**
 * num_online_cpus() - Read the number of online CPUs
 *
 * Despite the fact that __num_online_cpus is of type atomic_t, this
 * interface gives only a momentary snapshot and is not protected against
 * concurrent CPU hotplug operations unless invoked from a cpuhp_lock held
 * region.
 */
static inline int on_null_domain(struct rq *rq)
{
	return unlikely(!rcu_dereference_sched(rq->sd));
}
/**
 * rcu_dereference_sched() - fetch RCU-sched-protected pointer for dereferencing
 * @p: The pointer to read, prior to dereferencing
 *
 * Makes rcu_dereference_check() do the dirty work.
 */
#define rcu_dereference_sched(p) rcu_dereference_sched_check(p, 0)

/**
 * rcu_dereference_sched_check() - rcu_dereference_sched with debug checking
 * @p: The pointer to read, prior to dereferencing
 * @c: The conditions under which the dereference will take place
 *
 * This is the RCU-sched counterpart to rcu_dereference_check().
 * However, please note that starting in v5.0 kernels, vanilla RCU grace
 * periods wait for preempt_disable() regions of code in addition to
 * regions of code demarked by rcu_read_lock() and rcu_read_unlock().
 * This means that synchronize_rcu(), call_rcu, and friends all take not
 * only rcu_read_lock() but also rcu_read_lock_sched() into account.
 */
#define rcu_dereference_sched_check(p, c) \
	__rcu_dereference_check((p), __UNIQUE_ID(rcu), \
				(c) || rcu_read_lock_sched_held(), \
				__rcu)

函数用于检查当前运行队列(runqueue)是否处于“空域”状态。具体来说,它判断当前 CPU 是否不属于任何有效的调度域。

空域(Null Domain):在多核系统中,调度域用于组织和管理 CPU 之间的负载均衡。当一个 CPU 被标记为在空域时,意味着它不参与任何负载均衡策略。这通常发生在 CPU 被禁用或未被配置为参与调度时。

影响:如果 CPU 在空域中,则不需要进行负载均衡,因为没有其他 CPU 可以与之进行任务分配。

!cpu_active(cpu_of(rq))

#else
static inline bool cpu_active(unsigned int cpu)
{
	return cpumask_test_cpu(cpu, cpu_active_mask);
}
static inline bool cpu_active(unsigned int cpu)
{
	return cpu == 0;
}

功能

!cpu_active(cpu_of(rq)) 用于检查当前运行队列所对应的 CPU 是否处于活动状态。这个判断确保只有在 CPU 活跃的情况下才会进行负载均衡。

逻辑

CPU 活动状态:Linux 内核维护了一个关于每个 CPU 状态的位图,其中包括“活动”(active)状态。只有处于活动状态的 CPU 才能接收和执行任务。

影响:如果对应的 CPU 不活跃(即没有正在运行的进程),则负载均衡操作将被跳过,因为没有必要将任务分配给一个不活跃的 CPU。

综合分析

这两个判断逻辑结合在一起,确保了系统在进行负载均衡时的高效性和准确性:

  • 避免无效操作:如果当前 CPU 在空域或不活跃,则触发负载均衡是没有意义的,这样可以减少不必要的调度开销。
  • 优化资源利用:通过确保只有活跃且有效的 CPU 参与负载均衡,可以更好地利用系统资源,提高整体性能。

http://www.kler.cn/a/385932.html

相关文章:

  • vue3 element el-table实现表格动态增加/删除/编辑表格行,带有校验规则
  • hive表名重命名、rename重命名
  • 【解决】Layout 下创建槽位后,执行 Image 同步槽位位置后表现错误的问题。
  • 深入理解 source 和 sh、bash 的区别
  • QT QLineEdit失去焦点事件问题与解决
  • 【代码大模型】Is Your Code Generated by ChatGPT Really Correct?论文阅读
  • C 语言学习-05【数组】
  • multiprocessing
  • [MySQL]索引
  • RK3568平台开发系列讲解(字符设备驱动篇)创建设备节点实验
  • ENAS和DARTs的比较
  • 1、了解家庭网络历史
  • InfluxDB性能优化指南
  • 用 Collections.synchronizedSet 创建线程安全的 HashSet
  • 健尔康在A股上市:市值84亿元,陈国平、陈麒宇父女成大赢家
  • 机器学习之集成学习算法
  • Mac M1下运行端到端语音模型Mini-Omni
  • 虚拟化数据恢复—XenServer虚拟机中SQL Server数据库数据恢复案例
  • STM32 BootLoader 刷新项目 (九) 跳转指定地址-命令0x55
  • GEE 案例——利用哨兵-2 图像时间序列和谷歌地球引擎云计算自动绘制和监测香港海洋水质参数
  • 蓝桥杯 Python组-神奇闹钟(datetime库)
  • 深入了解 curl:使用和功能详解
  • Android OpenGL ES详解——纹理过滤GL_NEAREST和GL_LINEAR的区别
  • 数据分析-41-时间序列预测之机器学习方法XGBoost
  • Spark Plan 之 SQLMetric
  • 电影插曲《牧羊曲》