CFS调度器根据最小虚拟时间选择下一个进程,为了有效地获取此值,它使用红黑树(rbtree),使用rbtree可以在O(h)的时间内获得最小值,其中h是rbtree的高度。但是,使用min-heap我们可以仅在O(1)时间内获得最小虚拟时间进程。我想知道为什么CFS实现中没有考虑min-heap,以及在内核级别使用min-heap是否存在任何困难?
CFS调度器根据最小虚拟时间选择下一个进程,为了有效地获取此值,它使用红黑树(rbtree),使用rbtree可以在O(h)的时间内获得最小值,其中h是rbtree的高度。但是,使用min-heap我们可以仅在O(1)时间内获得最小虚拟时间进程。我想知道为什么CFS实现中没有考虑min-heap,以及在内核级别使用min-heap是否存在任何困难?
lib/prio_heap.c
和 include/linux/prio_heap.h
,您将会注意到堆是使用heap_init
和kmalloc
分配的。一旦多编程空间变得巨大,维护成千上万个struct sched_entity
就需要大量的连续空间(它运行在几个页面中)。从时间和性能角度来看,人们更喜欢堆,因为一旦选定最小的vruntime
值,堆化操作可以在后台运行,但其空间需求成为瓶颈。rbtree
)已经广泛应用,内核开发人员并没有考虑实现基于指针的堆,实际上也不需要。另一个有趣的点是,如果你有一个任务(进程或线程)从运行状态转换为阻塞状态(等待IO或网络资源),那么你需要将该任务从运行队列中删除,而复杂性如下:
堆的删除操作很慢,所以红黑树更好。
而当我们得到最小的虚拟运行时间时,堆操作实际上并不是O(1),只有在引用根节点而不删除它时才是O(1)。但在CFS中,我们需要
pick_next_entity() -> __pick_first_entity() https://github.com/torvalds/linux/blob/9de1f9c8ca5100a02a2e271bdbde36202e251b4b/kernel/sched/fair.c#L639
pick_next_entity() -> __pick_first_entity() -> (root)->rb_leftmost https://github.com/torvalds/linux/blob/3bc1bc0b59d04e997db25b84babf459ca1cd80b7/include/linux/rbtree.h#L106
调度程序可以尝试从树的root
中访问缓存值。