Archive

Archive for May, 2026

由SnpUniqueFwd和SnpUnique混合使用引发的思考

May 16th, 2026 Administrator No comments

一致性与内存屏障:一场在CHI总线上的花活

前几日,在 xhs 上刷到一则颇有意思的讨论:关于SnpUniqueFwd和SnpUnique混合使用的话题,以及这种混用究竟会在底层引发什么灾难性的影响。在讨论这个哑谜之前,先得理清这两个概念的底牌是什么。


Coherence(缓存一致性)和 Consistency(内存一致性)到底是俩兄弟还是父子,真不好分清。咱们拿《王者荣耀》瞎举个例子:Coherence 就像是红蓝 Buff 的存活状态,不管十个玩家的网络延迟有多大,只要红 Buff 被打掉了,所有人最终看到这个野怪坑位肯定都是空的(死磕单一对象);而 Consistency 关乎的是全图的因果律,它就像是英雄的连招顺序。比如对面打野先“交了闪现(事件 A)”,然后才“放出大招秒人(事件 B)”。如果在你的手机屏幕上看到的画面是:自己突然先掉血被秒了,然后对面打野才从墙外闪现进来,这种违背常理的吃书现象就叫因果律崩溃(它管的是多个独立事件在全局的先后呈现顺序)。这个例子不是非常恰到,这两个毕竟有非常明显的层次关系。


在多核架构的世界里,缓存分布在不同的核心上,依赖监听事务去同步。SnpUnique是一种非转发类型的监听请求(Non-forwarding snoop),为了获取缓存行的独占(Unique)副本,它会严谨地要求系统内所有持有该副本的节点立刻将缓存销毁(作废缓存,强制转换为 Invalid (I) 态)。属于妥...

TLB flush考古、追溯

May 2nd, 2026 Administrator No comments

为什么要刷 TLB?

写在前面,简单说明一些为什么要刷 TLB?能看到这里的小伙伴,大概率是知道什么是 TLB,TLB 就是一块简单的 cache,但是又与 cache 不同,比如一致性。常有 cache coherence(方便描述,后面直接简写成 CC),但是不见有 TLB coherence。最简单来看,支持 CC,我们就理解成硬件会自动同步 cache 中被修改的数据,保证与其他 cache 中的备份数据,以及内存中的数据的一致性。比如 core 0 上的 cache 数据被更新了,硬件会自动失效其他 core 上相同的备份数据。假如 TLB 与 cache 一样,支持 CC,那么如果 core 0 上的 TLB entry 被失效后,硬件会自动失效其他核心上的 TLB entry(这个 CC 看上去,和 Aarch64 上 TLB flush 的硬件实现有点相似)。

回到正题,由于 TLB 并不支持 CC,所以当内存的数据发生变化时,硬件上并不会失效相应的 TLB entry,这些已经过期的 TLB entry,称之为 stale TLB,如果发生读访问,可能会访问到被释放甚至是其他进程的数据,如果发生写操作,轻则进程异常,重则数据丢失。来个严肃的例子,进程A munmap 一段后备是文件的地址(比如表格 A,写全 A),由于某种不知名的原因没有刷 TLB,直接返回,且被切换到其他子线程 B,子线程申请到了刚才虚拟地址写表格 B(写全 B),这个时候可能会出现数据写串的情况,表格 A 里边出现了完全不可能的字母 B...

因此,在修改 PTE 后,且在虚拟地址空间还未再次分配前,尽快刷新 stale TLB,避免 ABA 问题。

最理想的情况,我们清理了一个 PTE,执行一个 TLB flush 指令,硬件会自动取 snoop 相关的 TLB entry 并失效,等下次访问这个...

Categories: technology Tags: ,

内存怪谭

May 1st, 2026 Administrator No comments

写在前面

本系列主要用于记录Linux内核内存BUG相关的故事,以及一些内存奇闻轶事。

shmem - sleep in atomic context

这个BUG在我们龙蜥cloud-kernel的4.19中用stress-ng压测复现。通常情况下,这个BUG对系统稳定性影响并不是很大,仅仅在CONFIG_PREEMPT_COUNT打开的情况下才会,而这个config属于debug类型,一般情况下不会打开。接下来,就分享一下这个怪异的BUG是如何在CONFIG_PREEMPT_COUNT打开的情况下触发的。


首先

#ifdef CONFIG_PREEMPT_COUNT
#define preempt_disable() \
do { \
>-------preempt_count_inc(); \
>-------barrier(); \
} while (0)
#define preempt_enable() \
do { \
>-------barrier(); \
>-------preempt_count_dec(); \...

读《High Performing Cache Hierarchies for Server Workloads》

May 1st, 2026 Administrator No comments

背景

在介绍这篇论文前,先抛出一个问题:Intel平台Haswell到Skylake-SP一个比较重要的变化就是将原来的Inclusive Cache改换为Exclusive Cache,这种调整是出于什么考虑?所以不禁让人想像由于什么原因需要使用Exclusive Cache?当然微架构中的很多问题都是权衡。这篇15年的论文中介绍的背景以及实验就可以理解该演变的其中原因之一。当然先阅读“伴读:Ring Bus VS Mesh”节开胃也未尝不可。


一段Inclusive Cache与Exclusive Cache描述:

  • 包含式Cache(Inclusive Cache):拿L1 L2来举例说明,L1的数据一定在L2中,但L2中的数据不一定在L1中。优点是设计复杂度低,是一个天然的Snoop Filter,缺点是会造成空间浪费,需要保证L2/LLC比例;
  • 独占式Cache(Exclusive Cache):L1和L2中的数据不重叠。设计复杂,同时需要单独设计一个模块充当Snoop Filter;
  • 非包含非独占 NI/NE(Non-inclusive Non-exclusive):没有绝对的Exclusive Cache,表达成Non-inclusive Cache更准确些。

关于NI/NE较详细的说明,这里有一份资料可以参考:http://yuhaozhu.com/CacheMemory.pdf


论文摘要

...

透明代码大页:让数据库也能用上2MB大页!

May 1st, 2026 Administrator No comments

背景

大页技术是操作系统中优化内存访问延迟的一种技术,其优化原理与CPU TLB硬件有直接关系,而其优化效果不仅受CPU TLB硬件影响,还需要看应用访存特点。只考虑arm和x86两种平台,已知的大页技术包括透明大页hugetlbfs16k和64k全局大页。在合适的场景,大页技术可以提升应用性能达10%以上,尤其是针对当前云上应用逐年增长的内存使用趋势,使用大页技术是其中重要的提升“性能-成本”比例的优化手段。透明大页(Transparent Huge Pages,THP)从2011年开始在Linux内核中已经支持起来,其通过一次性分配2M页填充进程页表,避免多次缺页开销,更深层次从硬件角度优化了TLB缺失开销,在最好情况下,对应用的优化效果达到10%左右。除以上优点外,透明大页(主要供堆栈使用)使用过度也会导致严重的内存碎片化、内存膨胀和内存利用率低等问题,这就是当前透明大页没有在数据库中使用的核心原因,只能感叹“卿本巧技,奈何有坑”。

代码大页在透明大页的基础上,将支持扩展到可执行二进制文件,包括进程二进制文件本身、共享库等可执行数据。与透明大页相比,由于代码大页仅将占比较低且有限的可执行文件页部分转换为大页,从根本上避开了内存碎片以及内存不足的问题。与此同时,由于代码类数据和普通堆栈数据访问热度对整体性能影响不同(主要指代码数据或堆栈数据访问缺页一次的性能影响),导致代码类数据使用大页所提升的性能远大于同样分量的透明大页。所以推广和完善代码大页相比透明大页更加简单和容易。


本文主要介绍我们的代码大页方案以及一些实验阶段性能测试。为了方便阅读,在这里简单归纳了一下L...

MAP_DENYWRITE:被Linux内核屏蔽的flag

May 1st, 2026 Administrator No comments

一 背景

谈到MAP_DENYWRITE,可能有些陌生。这个flag很少被用户态开发者关注,其中没有被关注的理由主要是“this flag is ignored by os”,简而言之,操作系统(Linux内核)将会忽略掉用户传入的MAP_DENYWRITE标志。回到MAP_DENYWRITE是什么?与MAP_ANONYMOUS、MAP_SHARED、MAP_PRIVATE等一样,是系统调用mmap()函数为映射目标设置映射方式的一种flag。顾名思义,MAP_DENYWRITE表示这段映射的虚拟地址区间不允许写操作,例如,我们通过open()以可写的方式获取文件句柄,将会返回“ETXTBSY: text file is busy”错误。


本文主要介绍MAP_DENYWRITE相关的内容,例如使用了MAP_DENYWRITE的可执行二进制文件忽略MAP_DENYWRITE的动态共享库。为了描述简单,后面直接使用EXEC和DSO(Dynamic Shared Object)分别表示可执行二进制文件和动态共享库。为了更加清晰的展示MAP_DENYWRITE作用,设计了实验1和实验2来显示用户态可见的差异。同时,借助实验1和实验2也为引出两个疑问:(a)为什么i_writecount会导致“ETXTBSY: text file is busy”;(b)为什么vim“写-存”DSO触发程序“Segment fault”;其答案分别可以在第三节和第四节获取。最后,第五节设计了最后一个实验对实验3进行补充。

二 MAP_DENYWRITE是什么

...