1. Process Selection
When CFS is deciding what process to run next , it picks the process with the smallest vruntime. This is the core of CFS's scheduling algotithm: Pick the task with the smallest vruntime.
CFS uses a red-black tree to manage the list of runnable processes and efficiently find the process with the smallest vruntiome.
2. Pick the Next Task
static struct sched_entyty *_pick_next_entity(struct cfs_rq *cfs_rq)
{
struct rb_node *left = cfs_rq->rb_leftmost;
if (!left)
return NULL;
return rb_entry(left, struct sched_entity, run_node);
}
3. adding processes to the tree
这个发生在一个进程变成runnable状态或者第一次通过fork()创建
cfs_rq: CFS-related fields in a runqueue
310struct cfs_rq { 311 struct load_weight load; 312 unsigned long nr_running; 313 314 u64 exec_clock; 315 u64 min_vruntime; 316 317 struct rb_root tasks_timeline; 318 struct rb_node *rb_leftmost; 319 320 struct list_head tasks; 321 struct list_head *balance_iterator; 322 323 /* 324 * 'curr' points to currently running entity on this cfs_rq. 325 * It is set to NULL otherwise (i.e when none are currently running). 326 */ 327 struct sched_entity *curr, *next, *last; 328 329 unsigned int nr_spread_over; 330 331#ifdef CONFIG_FAIR_GROUP_SCHED 332 struct rq *rq; /* cpu runqueue to which this cfs_rq is attached */ 333 334 /* 335 * leaf cfs_rqs are those that hold tasks (lowest schedulable entity in 336 * a hierarchy). Non-leaf lrqs hold other higher schedulable entities 337 * (like users, containers etc.) 338 * 339 * leaf_cfs_rq_list ties together list of leaf cfs_rq's in a cpu. This 340 * list is used during load balance. 341 */ 342 int on_list; 343 struct list_head leaf_cfs_rq_list; 344 struct task_group *tg; /* group that "owns" this runqueue */ 345 346#ifdef CONFIG_SMP 347 /* 348 * the part of load.weight contributed by tasks 349 */ 350 unsigned long task_weight; 351 352 /* 353 * h_load = weight * f(tg) 354 * 355 * Where f(tg) is the recursive weight fraction assigned to 356 * this group. 357 */ 358 unsigned long h_load; 359 360 /* 361 * Maintaining per-cpu shares distribution for group scheduling 362 * 363 * load_stamp is the last time we updated the load average 364 * load_last is the last time we updated the load average and saw load 365 * load_unacc_exec_time is currently unaccounted execution time 366 */ 367 u64 load_avg; 368 u64 load_period; 369 u64 load_stamp, load_last, load_unacc_exec_time; 370 371 unsigned long load_contribution; 372#endif 373#endif 374};
966static void 967enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags) 968{ 969 /* 970 * Update the normalized vruntime before updating min_vruntime 971 * through callig update_curr(). 972 */ 973 if (!(flags & ENQUEUE_WAKEUP) || (flags & ENQUEUE_WAKING)) 974 se->vruntime += cfs_rq->min_vruntime; 975 976 /* 977 * Update run-time statistics of the 'current'. 978 */ 979 update_curr(cfs_rq); 980 update_cfs_load(cfs_rq, 0); 981 update_cfs_shares(cfs_rq, se->load.weight); 982 account_entity_enqueue(cfs_rq, se); 983 984 if (flags & ENQUEUE_WAKEUP) { 985 place_entity(cfs_rq, se, 0); 986 enqueue_sleeper(cfs_rq, se); 987 } 988 989 update_stats_enqueue(cfs_rq, se); 990 check_spread(cfs_rq, se); 991 if (se != cfs_rq->curr) 992 __enqueue_entity(cfs_rq, se); 993 se->on_rq = 1; 994 995 if (cfs_rq->nr_running == 1) 996 list_add_leaf_cfs_rq(cfs_rq); 997} 998
370/* 371 * Enqueue an entity into the rb-tree: 372 */ 373static void __enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se) 374{ 375 struct rb_node **link = &cfs_rq->tasks_timeline.rb_node; 376 struct rb_node *parent = NULL; 377 struct sched_entity *entry; 378 s64 key = entity_key(cfs_rq, se); 379 int leftmost = 1; 380 381 /* 382 * Find the right place in the rbtree: 383 */ 384 while (*link) { 385 parent = *link; 386 entry = rb_entry(parent, struct sched_entity, run_node); 387 /* 388 * We dont care about collisions. Nodes with 389 * the same key stay together. 390 */ 391 if (key < entity_key(cfs_rq, entry)) { 392 link = &parent->rb_left; 393 } else { 394 link = &parent->rb_right; 395 leftmost = 0; 396 } 397 } 398 399 /* 400 * Maintain a cache of leftmost tree entries (it is frequently 401 * used): 402 */ 403 if (leftmost) 404 cfs_rq->rb_leftmost = &se->run_node; 405 406 rb_link_node(&se->run_node, parent, link); 407 rb_insert_color(&se->run_node, &cfs_rq->tasks_timeline); 408}