thread-context
QEMU 源码树里的util/thread-context.c。这个文件是QEMU 7.2 引入、后续版本一直保留的“线程上下文对象”实现作者是 Red Hat 的 David Hildenbrand专门用来解决“内存后端预分配线程如何吃上 NUMA 亲和性”这个问题。它到底是干什么的thread-context.c实现了一个 QOM 用户可创建对象thread-context本质就是“一个常驻的后台线程专门用来生孩子建新线程”。核心机制看thread_context_run()就懂它自己起一个持久线程叫 context thread外界通过thread_context_create_thread()让它代建新线程Linux 上新线程会继承创建者的 CPU affinity所以只要把 context thread 绑到某组 CPU所有经它生出来的线程比如touch_pages预分配线程自动继承同一亲和性它暴露的属性cpu-affinity直接指定宿主机 CPU 列表node-affinity写宿主 NUMA node 号内部用numa_node_to_cpus()展开成 CPU 列表仅写不能回读thread-id把自身 tid 暴露出去让 libvirt 等上层在 QEMU 开 sandbox/seccomp 前或外部手动taskset/sched_setaffinityprealloc-context是挂在memory-backend-*上的引用不是本文件属性和 NUMA 功能实现的关系要分两层看别和-numa混了1. 它不实现“虚拟机 NUMA 拓扑”-numa node,memdevxxx,cpusxx那套 guest 侧 NUMA 是别处softmmu/vl.c、hw/core/numa.c等的事thread-context.c完全不碰 guest NUMA。2. 它是“宿主机侧 NUMA 感知预分配”的粘合层当你这样配-object memory-backend-memfd,idmem0,size64G,host-nodes0,policybind,preallocon,prealloc-threads8,prealloc-contexttc0 -object thread-context,idtc0,node-affinity0host-nodes0,policybind决定内存从宿主 node 0 分配preallocon会起若干touch_pages线程去踩页大页/巨页场景很慢这些预分配线程本来是 QEMU 按需建的短命线程调度器可能把它们扔到 node 1 的 CPU 上跨节点踩 node 0 的内存启动慢且抖动大prealloc-contexttc0让后端通过 tc0 建预分配线程 → 线程继承 tc0绑 node 0 CPU的 affinity → 踩页线程本地化到 node 0实测 256G 大页 VM 启动预分配从 ~25s 降到 ~10s就是这么来的。为什么非要单独搞个文件/对象而不是 QEMU 直接sched_setaffinityQEMU 开-sandbox后 seccomp 禁了sched_setaffinity类 syscall自己设不了预分配线程是运行时懒建的libvirt 来不及挨个抓 tid 绑于是“先建一个带亲和性的 context 线程以后都从它肚子生线程”是最干净的绕过办法在 QEMU里定位路径util/thread-context.c 头文件include/qemu/thread-context.h调用方backends/hostmem.c内存后端prealloc-context解析、os_mem_prealloc里用thread_context_create_thread替代裸qemu_thread_create、util/oslib-posix.c的预分配逻辑。libvirt 侧检测到host-nodes时会自动帮你生成配对thread-context并填prealloc-context不用手敲。一句话总结thread-context.c不是 NUMA 本身而是“让 QEMU 内部短命工作线程主要是内存预分配线程能继承宿主 NUMA CPU 亲和性”的线程工厂是宿主侧 NUMA 化内存后端预分配的加速与本地化手段。
