Skip to content

Instantly share code, notes, and snippets.

@ShawnHuang
Last active October 19, 2015 08:01
Show Gist options
  • Save ShawnHuang/30b3b3afef863f7a193b to your computer and use it in GitHub Desktop.
Save ShawnHuang/30b3b3afef863f7a193b to your computer and use it in GitHub Desktop.
Linux project II
  • Score: 115 points.

  • Description:

    • Write a CPU-bound program cpu_bound.c as follows:

             #include <stdio.h>
             main()
             {
                int  a;
      
                while(1)
                  ++a;
             }
      
    • Write an I/O-bound program io_bound.c as follows:

             #include <stdio.h>
             main()
             {
               FILE  *out;
               char  c;
               int   a;
      
               while(1)
               {
                 for(a=0;a>0;)
                   ++a;
      
                if((out=fopen("io_bound.data","w"))!=NULL)
                {
                  c=38;
                  for(a=0; a<10000;a++)
                  {
                    putc(c,out);
                    if(++c>126)
                      c=38;
                  }
                  fclose(out);
                }
                else
                {
                  printf("Cannot open file.\n");
                  exit(0);
                }
               }
             }
      
    • Execute the above two programs in background.

    • Change the kernel so that you can utilize a new system call to learn

      1. How many process switches does the above CPU-bound process make during 3 minutes' execution?
      2. How many process switches does the above I/O-bound process make during 3 minutes' execution?
      3. How long is the CPU bound process idle during the 3 minutes' execution.
      4. How long is the I/O bound process idle during the 3 minutes' execution.
    • Write a program test_process_switch.c as follows to test your new kernel. The program accepts two parameters. The first parameter is the PID of the above CPU-bound process. The second parameter is the PID of the above I/O bound process.

              #include <stdio.h>
              #include <unistd.h>
              #include <stdlib.h>
      
              struct process_switch_info
              {
                unsigned int   counter_cpu, counter_IO;
                struct timeval time_cpu, time_IO;
              };
      
      
              main(int argc, char **argv)
              {
                int                        pid_cpu,pid_IO;
                unsigned long              temp_ul;
                struct process_switch_info ps_info;
      
                
                if(argc<3)
                {
                  printf("Input the PIDs of the CPU-bound process and I/O-bound process as the parameters of this executable.\n");
                  printf("Format: program pid_cpu pid_IO\n");
                  exit(0);
                }
      
                pid_cpu=atoi(argv[1]);
                pid_IO=atoi(argv[2]);
      
                get_process_switch_info(&ps_info,pid_cpu,pid_IO);    //new system call
                /*===========================================================================*/
                /*     prototype of the new system call is as follows                        */
                /*     void get_process_switch_info(struct process_switch_info *, int, int)  */
                /*===========================================================================*/
                temp_ul=(ps_info.time_cpu.tv_sec * 1000000 + ps_info.time_cpu.tv_usec);
                printf("The CPU-bound process has made %ld process switches\n", ps_info.counter_cpu);
                printf("This process has idle %ul usecs\n", temp_ul); 
      
                temp_ul=(ps_info.time_IO.tv_sec * 1000000 + ps_info.time_IO.tv_usec);
                printf("The IO-bound process has made %ld process switches\n", ps_info.counter_IO);
                printf("This process has idle %ul usecs\n", temp_ul); 
              }
      
    • Hint:

      1. You may need to add some fields in the END of the struct task_struct to record related info. The initial values of these fields are 0;
      2. You can add some code at function copy_process() or copy_thread() to set the initial values of the above four fields as 0.
      3. Each time when the schedule() makes a process switch from process 1 to process 2, you need to add the number of process switches of process 2 by 1.
      4. Each time when schedule() makes a process switch from process 1 to process 2, process 1 begins idle until next time schedule() makes a process switch to give CPU control to process 1 again. During the exectuiont of a process, the process may experience process switch several times. Hence the total idle time of a process is the sum of all the above individual idle time.
      5. Inside the kernel, you could call do_gettimeofday() to get a microsecond-resolution timestamp, or getnstimeofday() for nanosecond resolution.
      6. You may need to add a new system call to do project 2.
      • Check the "Referenced Material" part of the Course web site to see how to add a new system call in Linux.
  • Project Submission:

    • The due day of reports submission is 17th Jan. 2015
    • The demo will be held on 19th Jan. 2015, 20th Jan. 2015, and 21st Jan. 2015
    • Contact the TAs to choose your demo time before 16thd Jan. 2015
    • On site demo of this project is required.
    • When demonstrating your projects, the TAs will ask you some questions regarding to your projects. Part of your project grade is determined by your answers to the questions.
    • You need to submit both an electronic version and a hard-copy of your project report to the TAs.
      • The electronic versions could be sent to the TAs through e-mails.
      • Do not forget writing the names and student IDs of all members in your team.
      • Your report should contain:
        • Your source code
        • the execution results
    • Late submission
@ShawnHuang
Copy link
Author

static void __sched __schedule(void)
{
    struct task_struct *prev, *next;
    unsigned long *switch_count;
    struct rq *rq;
    int cpu;

need_resched:
    preempt_disable();
    cpu = smp_processor_id();
    rq = cpu_rq(cpu);
    rcu_note_context_switch(cpu);
    prev = rq->curr;

    schedule_debug(prev);

    if (sched_feat(HRTICK))
        hrtick_clear(rq);

    raw_spin_lock_irq(&rq->lock);

    switch_count = &prev->nivcsw;
    if (prev->state && !(preempt_count() & PREEMPT_ACTIVE)) {
        if (unlikely(signal_pending_state(prev->state, prev))) {
            prev->state = TASK_RUNNING;
        } else {
            deactivate_task(rq, prev, DEQUEUE_SLEEP);
            prev->on_rq = 0;

            /*
             * If a worker went to sleep, notify and ask workqueue
             * whether it wants to wake up a task to maintain
             * concurrency.
             */
            if (prev->flags & PF_WQ_WORKER) {
                struct task_struct *to_wakeup;

                to_wakeup = wq_worker_sleeping(prev, cpu);
                if (to_wakeup)
                    try_to_wake_up_local(to_wakeup);
            }
        }
        switch_count = &prev->nvcsw;
    }

    pre_schedule(rq, prev);

    if (unlikely(!rq->nr_running))
        idle_balance(cpu, rq);

    put_prev_task(rq, prev);
    next = pick_next_task(rq);
    clear_tsk_need_resched(prev);
    rq->skip_clock_update = 0;

    if (likely(prev != next)) {
        rq->nr_switches++;
        rq->curr = next;
        ++*switch_count;

        context_switch(rq, prev, next); /* unlocks the rq */
        /*
         * The context switch have flipped the stack from under us
         * and restored the local variables which were saved when
         * this task called schedule() in the past. prev == current
         * is still correct, but it can be moved to another cpu/rq.
         */
        cpu = smp_processor_id();
        rq = cpu_rq(cpu);
    } else
        raw_spin_unlock_irq(&rq->lock);

    post_schedule(rq);

    preempt_enable_no_resched();
    if (need_resched())
        goto need_resched;
}

Copy link

ghost commented Jan 5, 2015

目前結果!!!!
看似很OK..應該吧

明天寫另一支來確定 context_switch 次數會變動的時間總計是 3m,整理好再放上來

samou@samou-Aspire-5750:~/Project_02$ sh test
cpu_bound pid: 6817
io_bound pid : 6821
The CPU-bound process has made 153823 process switches
This process has idle 417748l usecs
The IO-bound process has made 671775 process switches
This process has idle 121624865l usecs
samou@samou-Aspire-5750:~/Project_02$ ./test_process_switch_ori 6817 6821
The CPU-bound process has made 153823 process switches
This process has idle 417748l usecs
The IO-bound process has made 671775 process switches
This process has idle 121624865l usecs
samou@samou-Aspire-5750:~/Project_02$ ./test_process_switch_ori 6817 6821
The CPU-bound process has made 153823 process switches
This process has idle 417748l usecs
The IO-bound process has made 671775 process switches
This process has idle 121624865l usecs
samou@samou-Aspire-5750:~/Project_02$ 

Copy link

ghost commented Jan 8, 2015

include/linux/sched.h

   // add in struct
    unsigned int cs_count;
    unsigned long long during_time;
    struct timeval idle_time, time_value;


// for system call                                                                                                                                                                                             
struct process_switch_info
{
    unsigned int    counter_cpu, counter_IO;
    // for test 3min                                                                                                                                                                                           
    unsigned long long    cpu_during, io_during;
    struct timeval time_cpu, time_IO;
};

kernel/fork.c

    // init the valus we add                                                                                                                                                                                   
    p->cs_count = 0;
    p->during_time = 0;
    p->idle_time.tv_sec = 0;
    p->idle_time.tv_usec = 0;
    p->time_value.tv_sec = 0;
    p->time_value.tv_usec = 0;

kernel/sched/core.c

        unsigned long long curtime;                                                                                                                                                                            
        struct timespec ts;                                                                                                                                                                                    

        ktime_get_ts(&ts);                                                                                                                                                                                     
        curtime = timespec_to_ns(&ts);                                                                                                                                                                         

        struct timeval cs_done;//now_value,future_value;                                                                                                                                                       
        unsigned long long temp = (next->start_time.tv_sec * 1000000000 + next->start_time.tv_nsec + 180000000000);                                                                                                                                                                                            
        if (temp > curtime) {                                                                                                                                                                                  
            next->cs_count++;                                                                                                                                                                                  
            if (next->during_time == 0)                                                                                                                                                                        
                next->during_time = temp - curtime;                                                                                                                                                            
        }                                                                                                                                                                                                                 

        context_switch(rq, prev, next); /* unlocks the rq */                                                                                                                                                   
        /*                                                                                                                                                                                                     
         * The context switch have flipped the stack from under us                                                                                                                                             
         * and restored the local variables which were saved when                                                                                                                                              
         * this task called schedule() in the past. prev == current                                                                                                                                            
         * is still correct, but it can be moved to another cpu/rq.                                                                                                                                            
         */                                                                                                                                                                                                    

        do_gettimeofday(&cs_done);                                                                                                                                                                             

        // record the time which prev process turn to sleep                                                                                                                                                    
        prev->idle_time.tv_sec = cs_done.tv_sec;                                                                                                                                                               
        prev->idle_time.tv_usec = cs_done.tv_usec;                                                                                                                                                             

        ktime_get_ts(&ts);                                                                                                                                                                                     
        curtime = timespec_to_ns(&ts);                                                                                                                                                                         

        temp = (next->start_time.tv_sec * 1000000000 + next->start_time.tv_nsec + 180000000000);                                                                                                               

        if((prev->start_time.tv_sec * 1000000000 + prev->start_time.tv_nsec + 180000000000) > curtime) {                                                                                                       
            prev->cs_count++;                                                                                                                                                                                  
            // if next process had been sleep, we calc the time between it sleep and awake                                                                                                                     
            //if (next->idle_time.tv_sec != 0 && next->idle_time.tv_usec != 0)                                                                                                                                 
            if (prev->cs_count > 1) {                                                                                                                                                                          
                next->time_value.tv_sec += cs_done.tv_sec - next->idle_time.tv_sec;
                next->time_value.tv_usec += cs_done.tv_usec - next->idle_time.tv_usec;
            }
            if (prev->during_time == 0)
                prev->during_time = temp - curtime;
        }

Copy link

ghost commented Jan 15, 2015

    // get current time and convert to ns
    unsigned long long curtime;
    struct timespec ts;
    ktime_get_ts(&ts);
    curtime = timespec_to_ns(&ts);

    // save time when cs exec and cs done
    struct timeval cs_enter, cs_done;
    unsigned long long temp = (next->start_time.tv_sec * 1000000000 + next->start_time.tv_nsec + 180000000000);

    if (temp > curtime) {
        next->cs_count++;
        if (next->during_time == 0)
            next->during_time = temp - curtime;
    }

    do_gettimeofday(&cs_enter);
    // record the time when it zZZ
    prev->idle_time.tv_sec = cs_enter.tv_sec; 
    prev->idle_time.tv_usec = cs_enter.tv_usec;

    context_switch(rq, prev, next);

    do_gettimeofday(&cs_done);

    ktime_get_ts(&ts);
    curtime = timespec_to_ns(&ts);

    temp = (prev->start_time.tv_sec * 1000000000 + prev->start_time.tv_nsec + 180000000000);

    if((prev->start_time.tv_sec * 1000000000 + prev->start_time.tv_nsec + 180000000000) > curtime) {
        prev->cs_count++;
        // if next process had been sleep, we calc the time between it sleep and awake
        if (prev->cs_count > 1) { // don't calc sleeping time at first time 
            prev->sleep_time.tv_sec += cs_done.tv_sec - prev->idle_time.tv_sec;
            prev->sleep_time.tv_usec += cs_done.tv_usec - prev->idle_time.tv_usec;
        }
        if (prev->during_time == 0)
            prev->during_time = temp - curtime;
    }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment