pcid support in upstream kernel

asid在x86中最多可以用4096个,内核维护者们也尝试了不同的方法来利用pcid,比如上一篇中提到的方法,还有的尝试给每一个进程分配一个asid,这种方式在一些特殊的系统里没有效果,比如光cpu就有上千个的系统,总之各有利弊。最终内核维护者Andy Lutomirski 开发了一个新的思路。


给每个cpu分配6个槽来缓存6个最近被调度的进程上下文,每个槽一个ctx_id和tlb_gen。ctx_id是一个全局唯一的变量表示进程用,tlb_gen表示进程的tlb的时间戳。也就是说每个cpu的tlb中最多缓存6个进程的tlb表项,当一个进程被调入时会查找是否有缓存,有的话比较时间戳是否已经变旧,变旧说明进程在其它地方更改了页表,需要刷新当前cpu的tlb,如果没有变旧,那切换页表也不用刷新tlb。如果没有缓存那就分配一个槽,并始终刷新tlb。在这种设计下也不用给lazy模式的cpu发送ipi,因为lazy模式运行内核线程,不会访问用户空间。有个例外就是进程释放页表以后,这时候会给所有相关cpu发送ipi包括lazy模式的cpu,因为cpu的猜测执行机制还是有可能会访问用户态空间即使执行的是内核线程。而页表中有可能放的是垃圾数据,如果不幸访问到外设空间的话就会是一场灾难,你有可能会碰到无法解释的io error,或者系统在某个时刻突然crash却难以找到根源。这个问题一度困扰了我,于是发邮件给社区寻求帮助,作者的解释很清楚地说明了原因。
https://lkml.org/lkml/2019/5/29/573

 

如果打开PTI的话,那TLB中最多缓存12个页表上下文,如果每个cpu上活跃进程不超过6个,那进程切换,用户态内核态切换都不会刷新tlb,极大的优化了性能。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章