consider_global_asid是 x86 架构中一个周期性触发的检查函数,用于判断当前进程是否“值得”分配全局 ASID。它并不直接执行分配,而是通过采样机制和阈值判断,决定是否调用use_global_asid来真正分配。
核心逻辑:采样 + 阈值 + 分配
static void consider_global_asid(struct mm_struct *mm) { if (!static_cpu_has(X86_FEATURE_INVLPGB)) return; /* Check every once in a while. */ if ((current->pid & 0x1f) != (jiffies & 0x1f)) return; if (mm_active_cpus_exceeds(mm, 3)) use_global_asid(mm); }代码逐行解析
1. 硬件特性检查
if (!static_cpu_has(X86_FEATURE_INVLPGB)) return;
全局 ASID 机制依赖 AMD 的INVLPGB(广播 TLB 失效)指令。如果 CPU 不支持这个特性,直接返回,无需任何后续检查。
2. 采样检查(关键性能优化)
if ((current->pid & 0x1f) != (jiffies & 0x1f)) return;
这是整个函数最巧妙的设计。& 0x1f相当于取模 32,它比较当前进程 PID 的低 5 位与内核 jiffies 的低 5 位是否相等。由于 jiffies 持续递增,而 PID 是固定的,每个进程平均每 32 个时钟滴答才会通过一次这个检查。
注释直言:“Check every once in a while.” 这个采样机制避免了每个进程在每次调度时都去遍历 CPU 掩码,将检查开销摊薄到几乎可以忽略不计。
3. 阈值判断与分配
if (mm_active_cpus_exceeds(mm, 3)) use_global_asid(mm);
通过采样后,调用mm_active_cpus_exceeds检查该进程是否活跃在超过 3 个 CPU上(即至少 4 个)。这是全局 ASID 分配的“准入门槛”——只有真正在多核上并行运行的多线程进程,才能从硬件广播 TLB 失效中获益。
如果满足条件,调用use_global_asid执行实际的分配。
动态阈值的设计
在后续的补丁版本中,consider_global_asid的阈值判断被进一步细化。meets_global_asid_threshold函数根据全局 ASID 空间的剩余量动态调整阈值:
| ASID 空间剩余 | 活跃 CPU 阈值 |
|---|---|
| > 3/4 | 2 |
| > 1/2 | 4 |
| < 1/3 | 逐步翻倍(8、16、32...) |
这种设计确保在 ASID 空间充足时,更多多线程进程能获得全局 ASID;空间紧张时,只有活跃在大量 CPU 上的“重量级”进程才能获得,从而避免 ASID 空间被过早耗尽。
设计意图:用“抽样”换“效率”
consider_global_asid的核心矛盾在于:全局 ASID 的收益需要多线程进程持续受益才能体现,但检查每个进程是否满足条件的开销不能太高。
采样机制完美解决了这个矛盾:它不需要精确知道每个进程当前的活跃 CPU 数,只需要以极低的频率(每 32 个 jiffies)进行“抽查”。如果一个进程确实在多个 CPU 上活跃,它总会在某个采样点被捕获。这种“概率性检测”用微小的延迟(最多 32 个 jiffies)换取了几乎为零的常规开销。