Lab 7: The Scheduler
Feb. 21/22, 2007
[153 Home]     [Simulator]     [Kernel Coding]     [User Program]     [Turn-in]     [Resources]

The Scheduler Simulator
I wrote a scheduler simulator to explain the fair-share scheduling policy. The output can be downloaded here.

The basic configuration is:
GID 1024 1024 1024 1025 1026 1026
PID 0 1 2 3 4 5
Time Quantum 250 100 100 260 200 180


Kernel Coding in More Detail
  1. In <include/linux/sched.h>:
    • Add a macro definition for SCHED_GFS:
      #define SCHED_GFS 4
    • Change the macro definition has_rt_policy:
      #define has_rt_policy(p) \
      unlikely((p)->policy != SCHED_NORMAL && (p)->policy != SCHED_BATCH && (p)->policy != SCHED_GFS)


  2. In <kernel/sched.c>:
    • In sched_fork() between lines 1593 and 1594 when local irq is disabled:
      if (current->gid >= 1024)
      {
          p->policy = SCHED_GFS;
          p->static_prio = p->normal_prio = p->prio = MAX_PRIO - 1;
          p->time_slice = DEF_TIMESLICE;
          enqueue_GFS(p);
      }
      Goal: Add a task to the group queue when it is created

    • In schedule() CHANGE line 3315 TO:
      {
          prev->state = EXIT_DEAD;
          if (prev->policy == SCHED_GFS)
              dequeue_GFS(prev);
      }
      Goal: Remove a task from the group queue when it exits

    • In __normal_prio() between lines 716 and 717:
      if (p->policy == SCHED_GFS)
          return p->static_prio;
      Goal: Keep the same priority

    • In wake_up_new_task() CHANGE line 1628 TO:
      if (!(clone_flags & CLONE_VM) && p->policy != SCHED_GFS)
      Goal: Let the parent fork all its children before any of the children can start executing.

    • In scheduler_tick() between lines 3033 and 3034 when rq is locked:
      if (p->policy == SCHED_GFS)
      {
          --p->time_slice;
          if (p->time_slice == 0)
          {
              p->time_slice = DEF_TIMESLICE;
              p->first_time_slice = 0;
              set_tsk_need_resched(p);
              requeue_GFS(p);
          }
          goto out_unlock;
      }
      Goal: Decrement the timeslice. If it drops to 0, reassign it and move the task to the tail of the group queue.

    • In schedule() between lines 3357 and 3358:
      if (prev->policy == SCHED_GFS && prev->time_slice < DEF_TIMESLICE)
          next_group = last_group;

      if (next->policy == SCHED_GFS)
      {
          for (i = 0; i < NUM_GROUPS; i++)
          {
              if (!group[next_group].num_tasks)
                  next_group = (next_group + 1) % NUM_GROUPS;
              else
                  break;
          }
          next = group[next_group].head;
          last_group = next_group;
          next_group = (next_group + 1) % NUM_GROUPS;;
      }
      Goal: Choose the next runnable SCHED_GFS task based on the fair-sharing algorithm. If the task is preempted, we should continue execution using the preempted task of the last_group. last_group is also a global variable, used to remember the group ID of the preempted task.

  3. I've implemented the scheduler, and printed some information from the kernel. Take a look at here. In this sample output, six tasks of three groups are created: parent is 832, group 1024 has three tasks (833, 834, 835), group 1025 has one task (836), group 1026 has two tasks (837, 838). Other comments are inserted at the top of the file. Lines starting with "GID=..." is printed from the user program. The scheduling sequence would be: 833, 836, 837; 834, 836, 838; 835, 836, 837; 833, 836, 838; ... At last, 836 should be the first one to exit.

User Program in More Detail
  1. Test Program Code Structure:
    for (i = 0; i < NUM_GROUPS; i++)
    {
        while (num_procs[j]--)
        {
            pid = fork();
            if (!pid)
            {
                start = time(NULL);
                // loop body
                ...
                stop = time(NULL);
                // read /proc/pid/stat
                ...
                printf("%d %d usertime=%lu", gid, pid, utime);
                printf("%d %d duration=%lu", gid, pid, stop-start);
                ...
                return 0;
            }
        }
    }
  2. A sample output can be downloaded here.
  3. The output should include both the program running time (utime + stime) and the duration (stop - start). Compare the result between your scheduler and the default Linux scheduler.

What to turn in?
  1. Kernel Code: sched.h, sched.c
  2. Test Program: test.c Makefile
  3. Report: Readme.txt (design description and result analysis)

Resources
  1. Online Source Code (2.6.18): Cross-Referencing Linux
  2. Online Book: Understanding the Linux Kernel, 3rd Edition
  3. Lab Manual: p.24-31, p.55-65, p.155-166