理解進程調(diào)度時機跟蹤分析進程調(diào)度與進程切換的過程

實驗

準備環(huán)境


進行調(diào)試


進程上下文切換相關代碼分析

#define switch_to(prev, next, last)                   
do {                                 
  /*                             
   * Context-switching clobbers all registers, so we clobber  
   * them explicitly, via unused output variables.     
   * (EAX and EBP is not listed because EBP is saved/restored  
   * explicitly for wchan access and EAX is the return value of   
   * __switch_to())                     
   */                                
  unsigned long ebx, ecx, edx, esi, edi;                
                                  
  asm volatile("pushfl\n\t"      /* save    flags */   
           "pushl %%ebp\n\t"        /* save    EBP   */ 
           "movl %%esp,%[prev_sp]\n\t"  /* save    ESP   */ 
           "movl %[next_sp],%%esp\n\t"  /* restore ESP   */ 
           "movl $1f,%[prev_ip]\n\t"    /* save    EIP   */ 
           "pushl %[next_ip]\n\t"   /* restore EIP   */    
           __switch_canary                   
           "jmp __switch_to\n"  /* regparm call  */ 
           "1:\t"                        
           "popl %%ebp\n\t"     /* restore EBP   */    
           "popfl\n"         /* restore flags */  
                                  
           /* output parameters */                
           : [prev_sp] "=m" (prev->thread.sp),     
             [prev_ip] "=m" (prev->thread.ip),        
             "=a" (last),                 
                                  
             /* clobbered output registers: */     
             "=b" (ebx), "=c" (ecx), "=d" (edx),      
             "=S" (esi), "=D" (edi)             
                                       
             __switch_canary_oparam                
                                  
             /* input parameters: */                
           : [next_sp]  "m" (next->thread.sp),        
             [next_ip]  "m" (next->thread.ip),       
                                       
             /* regparm parameters for __switch_to(): */  
             [prev]     "a" (prev),              
             [next]     "d" (next)               
                                  
             __switch_canary_iparam                
                                  
           : /* reloaded segment registers */           
          "memory");                  
} while (0)

分析switch_to中的匯編代碼:
-保存flags
-保存esp
-重置esp
-保存eip
-重置eip
-轉(zhuǎn)跳至__switch_to
-恢復ebp
-恢復flags

為了控制進程的執(zhí)行,內(nèi)核必須有能力掛起正在CPU上執(zhí)行的進程,并恢復以前掛起的某個進程的執(zhí)行,這叫做進程切換、任務切換、上下文切換;

掛起正在CPU上執(zhí)行的進程,與中斷時保存現(xiàn)場是不同的,中斷前后是在同一個進程上下文中,只是由用戶態(tài)轉(zhuǎn)向內(nèi)核態(tài)執(zhí)行;

進程上下文包含了進程執(zhí)行需要的所有信息

-用戶地址空間:?包括程序代碼,數(shù)據(jù),用戶堆棧等

-控制信息?:進程描述符,內(nèi)核堆棧等

-硬件上下文(注意中斷也要保存硬件上下文只是保存的方法不同)

分析總結

不同類型的進程有不同的調(diào)度需求
-I/O-bound
--頻繁的進行I/O
--通常會花費很多時間等待I/O操作的完成
-CPU-bound
--計算密集型
--需要大量的CPU時間進行運算
需要不同的算法來使得系統(tǒng)運行更加高效,將CPU資源得到最大限度的使用
-批處理進程batch process
--不必與用戶交互,通常在后臺運行
--不必很快響應
--典型的批處理程序:編譯程序、科學計算
-實時進程real-time process
--有實時需求,不應被低優(yōu)先級的進程阻塞
--響應時間要短、要穩(wěn)定
--典型的實時進程:視頻、音頻、機械控制等
-交互式進程interactive process
--需要經(jīng)常與用戶交互,因此要花很多時間等待用戶輸入操作
--響應時間要快,平均延遲要低于50~150ms
--典型交互式程序:shell、文本編輯器、圖形應用程序等
有不同的需求應用存在,就需要有不同的調(diào)度應用策略
調(diào)度策略是一組規(guī)則,決定什么時候以怎樣的方式選擇一個新進程運行
linux的調(diào)度基于分時和優(yōu)先級
linux在不同版本更新,調(diào)度策略發(fā)生了不同的變化
-linux的進程根據(jù)優(yōu)先級排隊,根據(jù)特定的算法計算出進程的優(yōu)先級,用一個值表示把進程如何適當?shù)姆峙浣oCPU
-linux中進程的優(yōu)先級是動態(tài)的,調(diào)度程序會根據(jù)進程的行為周期性的調(diào)整進程的優(yōu)先級,較長時間未分配到CPU的進程優(yōu)先級通常增高,已經(jīng)在CPU上運行了較長時間的進程通常優(yōu)先級降低
用來配置優(yōu)先級的調(diào)用
-nice
-getpriority/setpriority
-sched_getscheduler/sched_setscheduler
-sched_getparam/sched_setparam
-sched_yield
-sched_get_priority_min/sched_get_priority_max
-sched_rr_get_interval
調(diào)度策略只是一種算法,內(nèi)核中的調(diào)度算法相關代碼使用了類似OOD中的策略模式
將調(diào)度算法與其他部分解耦合
理解整個系統(tǒng),在于理解進程調(diào)度的時機
schedule函數(shù)用于實現(xiàn)調(diào)度
-目的:在運行隊列中找到一個進程,把CPU分配給它
-調(diào)用方法:-直接調(diào)用schedule();-松散調(diào)用,根據(jù)need_resched標記
進程調(diào)度的時機
-中斷處理過程(包括時鐘中斷、I/O中斷、系統(tǒng)調(diào)用和異常)中,直接調(diào)用schedule(),或者返回用戶態(tài)時根據(jù)need_resched標記調(diào)用schedule();用戶態(tài)進程只能被動調(diào)度
-內(nèi)核線程可以直接調(diào)用schedule()進行進程切換,也可以在中斷處理過程中進行調(diào)度,也就是說內(nèi)核線程作為一類的特殊的進程可以主動調(diào)度,也可以被動調(diào)度;內(nèi)核線程是只有內(nèi)核態(tài)沒有用戶態(tài)的特殊進程;內(nèi)核現(xiàn)成可以主動調(diào)度可以被動調(diào)動
-用戶態(tài)進程無法實現(xiàn)主動調(diào)度,僅能通過陷入內(nèi)核態(tài)后的某個時機點進行調(diào)度,即在中斷處理過程中進行調(diào)度。

王瀟洋
原創(chuàng)作品轉(zhuǎn)載請注明出處《Linux內(nèi)核分析》MOOC課程[http://mooc.study.163.com/course/USTC-1000029000]

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容