當前位置:首頁 » 操作系統 » linux內核源碼分析

linux內核源碼分析

發布時間: 2023-05-07 12:51:37

❶ 看linux內核源代碼情景分析之前要看什麼書我完全是菜鳥。看第一章預備知識cpu定址方式就看不懂了。

先看看王爽的《匯編語言》,了解一下CPU基本原理和實模式下的寄存器和定址方式吧,然後建議看看深入理解LINUX內核,講得詳細一些。

《Linux內核源代碼情景分析》定址方面直接講的保護模式的定址方法,沒基礎的話一下子是看不懂的,等你了解了實模式的定址方式,對寄存器、內存分段管理有一定了解後,就比較容易看懂了。

❷ Linux內核源碼解析-list.h

開頭就說明了這里的 list.h 文件來自 Linux Kernel ( */include/linux/list.h ),只是去除了列表項的硬體預載入部分。

進行宏替換後就是

Note: 沒搞懂這里為什麼加個 osn 前綴,原本是 list_add ,現在是 osn_list_add 。

可以看到就是個簡單的鏈表節點刪除過程,同時把刪除節點的前後指針設為無法訪問

刪除節點後初始化,前後指針都指向自己

從A鏈表刪除後頭插法插入B鏈表

從A鏈表刪除後尾插法插入B鏈表

先對 list 判空,非空就把 list 鏈表除頭節點外裁剪到 head 頭節點在的鏈表中。函數不安全, list 節點可以繼續訪問其他節點。

多了一步 list 重新初始化的過程。

(unsigned long)(&((type *)0)->member))) 將0x0地址強制轉換為 type * 類型,然後取 type 中的成員 member 地址,因為起始地址為0,得到的 member 的地址就直接是該成員相對於 type 對象的偏移地址了。
所以該語句的功能是:得到 type 類型對象中 member 成員的地址偏移量。
先將 ptr 強制轉換為 char * 類型(因為 char * 類型進行加減的話,加減量為 sizeof(char)*offset , char 佔一個位元組空間,這樣指針加減的步長就是1個位元組,實現加一減一。)
整句話的意思就是:得到指向 type 的指針,已知成員的地址,然後減去這個成員相對於整個結構對象的地址偏移量,得到這個數據對象的地址。

就是從前往後,從後往前的區別

Note: 從head節點開始(不包括head節點!)遍歷它的每一個節點!它用n先將下一個要遍歷的節點保存起來,防止刪除本節點後,無法找到下一個節點,而出現錯誤!

已知指向某個結構體的指針pos,以及指向它中member成員的指針head,從下一個結構體開始向後遍歷這個結構體鏈

Note: 同理,先保存下一個要遍歷的節點!從head下一個節點向後遍歷鏈表。

list.h使用說明
linux內核list.h分析(一)
linux內核list.h分析(二)
【Linux內核數據結構】最為經典的鏈表list

❸ Linux 內核 net/bridge/netfilter源代碼分析求助

netfilter這種專業級問題,就別來知道了,我們研究這玩意 都刻意迴避外傳,一個勁往svn里合呢,你還上來問! 你看看有論壇啥的沒,那些版主啦 有空的技術牛人能寫博客,你搜搜去吧。

❹ 想學linux內核看哪些入門書籍好呢

如果初入Linux內核,建議買一本叫《深入理解Linux內核》的書籍,鉛洞它相比較書籍《Linux內核設計與現實》要簡槐友枯單些!也可以看看,告春《Linux內核源代碼分析》

❺ 如何linux內核報告問題

Linux Kernel BUG:soft lockup CPU#1 stuck分析
1.線上內核bug日誌
kernel: Deltaway too big! 18428729675200069867 ts=18446743954022816244 write stamp =18014278822746377
kernel:------------[ cut here ]------------
kernel:WARNING: at kernel/trace/ring_buffer.c:1988 rb_reserve_next_event+0x2ce/0x370()(Not tainted)
kernel:Hardware name: ProLiant DL360 G7
kernel:Moles linked in: fuse ipv6 power_meter bnx2 sg microcode serio_raw iTCO_wdtiTCO_vendor_support hpilo hpwdt i7core_edac edac_core shpchp ext4 mbcache jbd2sd_mod crc_t10dif hpsa radeon ttm drm_kms_helper drm i2c_algo_bit i2c_coredm_mirror dm_region_hash dm_log dm_mod [last unloaded: scsi_wait_scan]
kernel: Pid:5483, comm: master Not tainted 2.6.32-220.el6.x86_64 #1
kernel: CallTrace:
kernel:[<ffffffff81069b77>] ? warn_slowpath_common+0x87/0xc0
kernel:[<ffffffff81069bca>] ? warn_slowpath_null+0x1a/0x20
kernel:[<ffffffff810ea8ae>] ? rb_reserve_next_event+0x2ce/0x370
kernel:[<ffffffff810eab02>] ? ring_buffer_lock_reserve+0xa2/0x160
kernel:[<ffffffff810ec97c>] ? trace_buffer_lock_reserve+0x2c/0x70
kernel:[<ffffffff810ecb16>] ? trace_current_buffer_lock_reserve+0x16/0x20
kernel:[<ffffffff8107ae1e>] ? ftrace_raw_event_hrtimer_cancel+0x4e/0xb0
kernel:[<ffffffff81095e7a>] ? hrtimer_try_to_cancel+0xba/0xd0
kernel:[<ffffffff8106f634>] ? do_setitimer+0xd4/0x220
kernel:[<ffffffff8106f88a>] ? alarm_setitimer+0x3a/0x60
kernel:[<ffffffff8107c27e>] ? sys_alarm+0xe/0x20
kernel:[<ffffffff8100b308>] ? tracesys+0xd9/0xde
kernel: ---[end trace 4d0a1ef2e62cb1a2 ]---
abrt-mp-oops: Reported 1 kernel oopses to Abrt
kernel: BUG: softlockup - CPU#11 stuck for 4278190091s! [qmgr:5492]
kernel:Moles linked in: fuse ipv6 power_meter bnx2 sg microcode serio_raw iTCO_wdtiTCO_vendor_support hpilo hpwdt i7core_edac edac_core shpchp ext4 mbcache jbd2sd_mod crc_t10dif hpsa radeon ttm drm_kms_helper drm i2c_algo_bit i2c_coredm_mirror dm_region_hash dm_log dm_mod [last unloaded: scsi_wait_scan]
kernel: CPU 11
kernel:Moles linked in: fuse ipv6 power_meter bnx2 sg microcode serio_raw iTCO_wdtiTCO_vendor_support hpilo hpwdt i7core_edac edac_core shpchp ext4 mbcache jbd2sd_mod crc_t10dif hpsa radeon ttm drm_kms_helper drm i2c_algo_bit i2c_coredm_mirror dm_region_hash dm_log dm_mod [last unloaded: scsi_wait_scan]
kernel:
kernel: Pid:5492, comm: qmgr Tainted: G W ---------------- 2.6.32-220.el6.x86_64 #1 HPProLiant DL360 G7
kernel: RIP:0010:[<ffffffff8106f730>] [<ffffffff8106f730>]do_setitimer+0x1d0/0x220
kernel: RSP:0018:ffff88080a661ef8 EFLAGS: 00000286
kernel: RAX:ffff88080b175a08 RBX: ffff88080a661f18 RCX: 0000000000000000
kernel: RDX:0000000000000000 RSI: 0000000000000082 RDI: ffff88080c8c4c40
kernel: RBP:ffffffff8100bc0e R08: 0000000000000000 R09: 0099d7270e01c3f1
kernel: R10:0000000000000000 R11: 0000000000000246 R12: ffffffff810ef9a3
kernel: R13:ffff88080a661e88 R14: 0000000000000000 R15: ffff88080a65a544
kernel: FS:00007f10b245f7c0(0000) GS:ffff88083c4a0000(0000) knlGS:0000000000000000
kernel: CS:0010 DS: 0000 ES: 0000 CR0: 000000008005003b
kernel: CR2:00007ff955977380 CR3: 000000100a80b000 CR4: 00000000000006e0
kernel: DR0:0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
kernel: DR3:0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
kernel:Process qmgr (pid: 5492, threadinfo ffff88080a660000, task ffff880809577500)
kernel: Stack:
kernel:00007f10b323def0 00007f10b248ead0 00007f10b26d0f78 00007f10b248ede0
kernel:<0> ffff88080a661f68 ffffffff8106f88a 0000000000000000 0000000000000000
kernel:<0> 000000000000014c 00000000000f423d 0000000000000000 0000000000000000
kernel: CallTrace:
kernel:[<ffffffff8106f88a>] ? alarm_setitimer+0x3a/0x60
kernel:[<ffffffff8107c27e>] ? sys_alarm+0xe/0x20
kernel:[<ffffffff8100b308>] ? tracesys+0xd9/0xde
kernel: Code:89 ef e8 74 66 02 00 83 3d 15 69 b5 00 00 75 37 49 8b 84 24 70 07 00 00 48 0508 08 00 00 66 ff 00 66 66 90 fb 66 0f 1f 44 00 00 <31> c0 e9 64 fe ff ff49 8b 84 24 68 07 00 00 48 c7 80 d0 00 00
kernel: CallTrace:
kernel:[<ffffffff8106f769>] ? do_setitimer+0x209/0x220
kernel:[<ffffffff8106f88a>] ? alarm_setitimer+0x3a/0x60
kernel:[<ffffffff8107c27e>] ? sys_alarm+0xe/0x20
kernel:[<ffffffff8100b308>] ? tracesys+0xd9/0xde
abrt-mp-oops: Reported 1 kernel oopses to Abrt

2.內核軟死鎖(soft lockup)bug原因分析
Soft lockup名稱解釋:所謂,soft lockup就是說,這個bug沒有讓系統徹底死機,但是若干個進程(或者kernel thread)被鎖死在了某個狀態(一般在內核區域),很多情況下這個是由於內核鎖的使用的問題。
Linux內核對於每一個cpu都有一個監控進程,在技術界這個叫做watchdog(看門狗)。通過ps –ef | grep watchdog能夠看見,進程名稱大概是watchdog/X(數字:cpu邏輯編號1/2/3/4之類的)。這個進程或者線程每一秒鍾運行一次,否則會睡眠和待機。這個進程運行會收集每一個cpu運行時使用數據的時間並且存放到屬於每個cpu自己的內核數據結構。在內核中有很多特定的中斷函數。這些中斷函數會調用soft lockup計數,他會使用當前的時間戳與特定(對應的)cpu的內核數據結構中保存的時間對比,如果發現當前的時間戳比對應cpu保存的時間大於設定的閥值,他就假設監測進程或看門狗線程在一個相當可觀的時間還沒有執。Cpu軟鎖為什麼會產生,是怎麼產生的?如果linux內核是經過精心設計安排的CPU調度訪問,那麼怎麼會產生cpu軟死鎖?那麼只能說由於用戶開發的或者第三方軟體引入,看我們伺服器內核panic的原因就是qmgr進程引起。因為每一個無限的循環都會一直有一個cpu的執行流程(qmgr進程示一個後台郵件的消息隊列服務進程),並且擁有一定的優先順序。Cpu調度器調度一個驅動程序來運行,如果這個驅動程序有問題並且沒有被檢測到,那麼這個驅動程序將會暫用cpu的很長時間。根據前面的描述,看門狗進程會抓住(catch)這一點並且拋出一個軟死鎖(soft lockup)錯誤。軟死鎖會掛起cpu使你的系統不可用。
如果是用戶空間的進程或線程引起的問題backtrace是不會有內容的,如果內核線程那麼在soft lockup消息中會顯示出backtrace信息。
3.根據linux內核源碼分析錯誤
根據我們第一部分內核拋出的錯誤信息和call trace(linux內核的跟蹤子系統)來分析產生的具體原因。
首先根據我們的centos版本安裝相應的linux內核源碼,具體步驟如下:
(1)下載源碼的rpm包kernel-2.6.32-220.17.1.el6.src.rpm
(2)安裝相應的依賴庫,命令:yuminstall rpm-build redhat-rpm-config asciidoc newt-devel
(3)安裝源碼包:rpm -ikernel-2.6.32-220.17.1.el6.src.rpm
(4)進入建立源碼的目錄:cd~/rpmbuild/SPECS
(5)建立生成源碼目錄:rpmbuild-bp --target=`uname -m` kernel.spec

下面開始真正的根據內核bug日誌分析源碼:
(1)第一階段內核錯誤日誌分析(時間在Dec 4 14:03:34這個階段的日誌輸出代碼分析,其實這部分代碼不會導致cpu軟死鎖,主要是第二階段錯誤日誌顯示導致cpu軟死鎖)
我們首先通過日誌定位到相關源代碼:看下面日誌:Dec 4 14:03:34 BP-YZH-1-xxxx kernel: WARNING: atkernel/trace/ring_buffer.c:1988 rb_reserve_next_event+0x2ce/0x370() (Not tainted)
根據日誌內容我們可以很容易的定位到kernel/trace/ring_buffer.c這個文件的1988行代碼如下:WARN_ON(1)。
先簡單解釋一下WARN_ON的作用:WARN_ON只是列印出當前棧信息,不會panic。所以會看到後面有一大堆的棧信息。這個宏定義如下:
#ifndef WARN_ON
#defineWARN_ON(condition) ({ \
int __ret_warn_on = !!(condition); \
if (unlikely(__ret_warn_on)) \
__WARN(); \
unlikely(__ret_warn_on); \
})
#endif
這個宏很簡單保證傳遞進來的條件值為0或者1(兩次邏輯非操作的結果),然後使用分支預測技術(保證執行概率大的分支緊鄰上面的指令)判斷是否需要調用__WARN()宏定義。如果滿足條件執行了__WARN()宏定義也接著執行一條空指令;。上面調用WARN_ON宏是傳遞的1,所以會執行__WARN()。下面繼續看一下__WARN()宏定義如下:
#define __WARN() warn_slowpath_null(__FILE__,__LINE__)
從接下來的call trace信息中我們也確實發現調用了warn_slowpath_null這個函數。通過在linux內核源代碼中搜索這個函數的實現,發現在panic.c(內核恐慌時的相關功能實現)中實現如下:
voidwarn_slowpath_null(const char *file, int line)
{
warn_slowpath_common(file, line,__builtin_return_address(0),
TAINT_WARN, NULL);
}
EXPORT_SYMBOL(warn_slowpath_null);//都出這個符號,讓其他模塊可以使用這個函數
同樣的我們看到了warn_slowpath_common這個函數,而在call trace當中這個函數在warn_slowpath_null函數之前列印出來,再次印證了這個流程是正確的。同樣在panic.c這個文件中我發現了warn_slowpath_common這個函數的實現如下:
static voidwarn_slowpath_common(const char *file, int line, void *caller,
unsigned taint, struct slowpath_args *args)
{
const char *board;

printk(KERN_WARNING "------------[ cut here]------------\n");
printk(KERN_WARNING "WARNING: at %s:%d %pS()(%s)\n",
file, line, caller, print_tainted());
board = dmi_get_system_info(DMI_PRODUCT_NAME);//得到dmi系統信息
if (board)
printk(KERN_WARNING "Hardware name:%s\n", board);//通過我們的日誌信息可以發現我們硬體名稱是ProLiant DL360 G7

if (args)
vprintk(args->fmt, args->args);

print_moles();//列印系統模塊信息
mp_stack();//mp信息輸出(call trace開始)
print_oops_end_marker();//列印oops結束
add_taint(taint);
}
分析這個函數的實現不難發現我們的很多日誌信息從這里開始輸出,包括列印一些系統信息,就不繼續深入分析了(請看代碼注釋,裡面調用相關函數列印對應信息,通過我分析這些函數的實現和我們的日誌信息完全能夠對應,其中mp_stack是與cpu體系結構相關的,我們的伺服器應該是屬於x86體系)。這里在繼續分析一下mp_stack函數的實現,因為這個是與cpu體系結構相關的,而且這個函數直接反應出導致內核panic的相關進程。這個函數實現如下:
/*
* The architecture-independent mp_stackgenerator
*/
void mp_stack(void)
{
unsigned long stack;

printk("Pid: %d, comm: %.20s %s %s %.*s\n",
current->pid, current->comm,print_tainted(),
init_utsname()->release,
(int

❻ Linux內核源代碼情景分析適合初學linux的人嗎

如果你有一定的c語言基礎並且對linux的文件系統比較了解的話,可以直接看linux的內核源碼分析

❼ linux內核源代碼怎麼看

一般在Linux系統中的/usr/src/linux*.*.*(*.*.*代表的是內核版本,如2.4.23)目錄下就是內核源代碼(如果沒有類似目錄,是因為還沒安裝內核代碼)。另外還可從互連網上免費下載。注意,不要總到http://www.kernel.org/去下載,最好使用它的鏡像站點下載。請在http://www.kernel.org/mirrors/里找一個合適的下載點,再到pub/linux/kernel/v2.6/目錄下去下載2.4.23內核。 代碼目錄結構 在閱讀源碼之前,還應知道Linux內核源碼的整體分布情況。現代的操作系統一般由進程管理、內存管理、文件系統、驅動程序和網路等組成。Linux內核源碼的各個目錄大致與此相對應,其組成如下(假設相對於Linux-2.4.23目錄): 1.arch目錄包括了所有和體系結構相關的核心代碼。它下面的每一個子目錄都代表一種Linux支持的體系結構,例如i386就是Intel CPU及與之相兼容體系結構的子目錄。PC機一般都基於此目錄。 2.include目錄包括編譯核心所需要的大部分頭文件,例如與平台無關的頭文件在include/linux子目錄下。 3.init目錄包含核心的初始化代碼(不是系統的引導代碼),有main.c和Version.c兩個文件。這是研究核心如何工作的好起點。 4.mm目錄包含了所有的內存管理代碼。與具體硬體體系結構相關的內存管理代碼位於arch/*/mm目錄下。 5.drivers目錄中是系統中所有的設備驅動程序。它又進一步劃分成幾類設備驅動,每一種有對應的子目錄,如音效卡的驅動對應於drivers/sound。 6.ipc目錄包含了核心進程間的通信代碼。 7.moles目錄存放了已建好的、可動態載入的模塊。 8.fs目錄存放Linux支持的文件系統代碼。不同的文件系統有不同的子目錄對應,如ext3文件系統對應的就是ext3子目錄。 Kernel內核管理的核心代碼放在這里。同時與處理器結構相關代碼都放在arch/*/kernel目錄下。 9.net目錄里是核心的網路部分代碼,其每個子目錄對應於網路的一個方面。 10.lib目錄包含了核心的庫代碼,不過與處理器結構相關的庫代碼被放在arch/*/lib/目錄下。 11.scripts目錄包含用於配置核心的腳本文件。 12.documentation目錄下是一些文檔,是對每個目錄作用的具體說明。 一般在每個目錄下都有一個.depend文件和一個Makefile文件。這兩個文件都是編譯時使用的輔助文件。仔細閱讀這兩個文件對弄清各個文件之間的聯系和依託關系很有幫助。另外有的目錄下還有Readme文件,它是對該目錄下文件的一些說明,同樣有利於對內核源碼的理解。 在閱讀方法或順序上,有縱向與橫向之分。所謂縱向就是順著程序的執行順序逐步進行;所謂橫向,就是按模塊進行。它們經常結合在一起進行。對於Linux啟動的代碼可順著Linux的啟動順序一步步來閱讀;對於像內存管理部分,可以單獨拿出來進行閱讀分析。實際上這是一個反復的過程,不可能讀一遍就理解。

❽ 2.6了,看linux 內核源代碼情景分析有意義嗎

意義肯定有,只是你如何評定你的時間精力「投入」與「收獲」問題。看基於2.4版的《linux 內核源代碼情景分析》要注意,內存管理部分與2.6完全不同。

❾ 為什麼Linux CFS調度器沒有帶來驚艷的碾壓效果| CSDN博文精選

任何領域,革命性的碾壓式推陳出新並不是沒有,但是概率極低,人們普遍的狂妄在於,總是認為自己所置身的環境正在發生著某種碾壓式的變革,但其實,最終大概率不過是一場平庸。

作者 | dog250

責編 | 劉靜

出品 | CSDN博客

但凡懂Linux內核的,都知道Linux內核的CFS進程調度演算法,無論是從2.6.23將其初引入時的論文,還是各類源碼分析,文章,以及Linux內核專門的圖書,都給人這樣一種感覺,即 CFS調度器是革命性的,它將徹底改變進程調度演算法。 預期中,人們期待它會帶來令人驚艷的效果。

然而這是錯覺。

人們希望CFS速勝,但是分析來分析去, 卻只是在某些方面比O(1)調度器稍微好一點點 。甚至在某些方面比不上古老的4.4BSD調度器。可是人們卻依然對其趨之若鶩,特別是源碼分析,汗牛塞屋!

為什麼CFS對別的調度演算法沒有帶來碾壓的效果呢?

首先,在真實世界,碾壓是不存在的,人與人,事與事既然被放在了同一個重量級梯隊比較,其之間的差別沒有想像的那麼大,根本就不在誰碾壓誰。不能被小說電視劇電影蒙蔽了,此外,徐曉冬大擺拳暴打雷雷也不算數,因為他們本就不是一個梯隊。

任何領域,革命性的碾壓式推陳出新並不是沒有,但是概率極低,人們普遍的狂妄在於,總是認為自己所置身的環境正在發生著某種碾壓式的變革,但其實,最終大概率不過是一場平庸。

最終就出現了角力,僵持。

其次,我們應該看到,CFS調度器聲稱它會給互動式進程帶來福音,在這方面CFS確實比O(1)做得好,但是驚艷的效果來自於粉絲的認同。Linux系統交互進程本來就不多,Linux更多地被裝在伺服器,而在伺服器看來,吞吐是要比交互響應更加重要的。

那麼以交互為主的Android系統呢?我們知道,Android也是採用了CFS調度器,也有一些事BFS,為什麼同樣沒有帶來驚艷的效果呢?

我承認,2008年前後出現CFS時廳陸兆還沒有Android,等到Android出現時,其採用的Linux內核已經默認了CFS調度器,我們看下Android版本,Linux內核版本以及發行時間的關系:

Linux內核在2.6.23就採用了CFS調度器。所以一個原因就是沒有比較。Android系統上,CFS沒有機會和O(1)做比較。

另悉槐外,即便回移一個O(1)調度器到Android系統去和CFS做AB,在我看來,CFS同樣不會驚艷,原因很簡單,Android系統幾乎都是交互進程,卻前台進程永遠只有一個,你幾乎感受不到進程的切換卡頓,換句話說,即便CFS對待互動式進程比O(1)好太多,你也感受不到,因為對於手機,平板而言,你切換 APP 的時間遠遠大於進程切換的時間粒度。

那麼,CFS到底好在哪裡?

簡單點說,CFS的意義在於, 在一個混雜著大量計算型進程和IO交互進程的系統中,CFS調度器對待IO交扮租互進程要比O(1)調度器更加友善和公平 。理解這一點至關重要。

其實,CFS調度器的理念非常古老,就說在業界,CFS的思想早就被應用在了磁碟IO調度,數據包調度等領域,甚至最最古老的SRV3以及4.3BSD UNIX系統的進程調度中早就有了CFS的身影,可以說,Linux只是 使用CFS調度器 ,而不是 設計了CFS調度器

就以4.3BSD調度器為例,我們看一下其調度原理。

4.3BSD採用了1秒搶占制,每間隔1秒,會對整個系統進程進行優先順序排序,然後找到優先順序最高的投入運行,非常簡單的一個思想,現在看看它是如何計算優先順序的。

首先,每一個進程j均擁有一個CPU滴答的度量值Cj,每一個時鍾滴答,當前在運行的進程的CPU度量值C會遞增:

當一個1秒的時間區間ii過去之後,Cj被重置,該進程jj的優先順序採用下面的公式計算:

可以計算,在一個足夠長的時間段內,兩個進程運行的總時間比例,將和它們的Base_PrioBase_Prio優先順序的比例相等。

4.3BSD的優先順序公平調度是CPU滴答驅動的。

現在看Linux的CFS,CFS採用隨時搶占制。每一個進程j均攜帶一個 虛擬時鍾VCj ,每一個時鍾滴答,當前進程k的VCk會重新計算,同時調度器選擇VC最小的進程運行,計算方法非常簡單:

可見, Linux的CFS簡直就是4.3BSD進程調度的自驅無級變速版本!

如果你想了解CFS的精髓,上面的就是了。換成語言描述,CFS的精髓就是 「 n個進程的系統,任意長的時間周期TT,每一個進程運行T/n的時間!

當然,在現實和實現中,會有80%的代碼處理20%的剩餘問題,比如如何獎勵睡眠太久的進程等等,但是這些都不是精髓。

綜上,我們總結了:

所以無論從概念還是從效果,Linux CFS調度器均沒有帶來令人眼前一亮的哇塞效果。但是還缺點什麼。嗯,技術上的解釋。

分析和解釋任何一個機制之前,必然要先問,這個機制的目標是什麼,它要解決什麼問題,這樣才有意義。而不能僅僅是明白了它是怎麼工作的。

那麼Linux CFS調度器被採用,它的目標是解決什麼問題的呢?它肯定是針對O(1)演算法的一個問題而被引入並取代O(1),該問題也許並非什麼臭名昭著,但是確實是一枚釘子,必須拔除。

O(1)調度器的本質問題在於 進程的優先順序和進程可運行的時間片進行了強映射!

也就是說,給定一個進程優先順序,就會計算出一個時間片與之對應,我們忽略獎懲相關的動態優先順序,看一下原始O(1)演算法中一個進程時間片的計算:

直觀點顯示:

針對上述問題,2.6內核的O(1)O(1)引入了雙斜率來解決:

直觀圖示如下:

貌似問題解決了,但是如果單單揪住上圖的某一個優先順序子區間來看,還是會有問題,這就是相對優先順序的問題。我們看到,高優先順序的時間片是緩慢增減的,而低優先順序的時間片卻是陡然增減,同樣都是相差同樣優先順序的進程,其優先順序分布影響了它們的時間片分配。

本來是治瘸子,結果腿好了,但是胳臂壞了。

本質上來講,這都源自於下面兩個原因:

固定的優先順序映射到固定的時間片。

相對優先順序和絕對優先順序混雜。

那麼這個問題如何解決?

優先順序和時間片本來就是兩個概念,二者中間還得有個變數溝通才可以。優先順序高只是說明該進程能運行的久一些,但是到底久多少,並不是僅僅優先順序就能決定的,還要綜合考慮,換句話距離來說,如果只有一個進程,那麼即便它優先順序再低,它也可以永久運行,如果系統中有很多的進程,即便再高優先順序的進程也要讓出一些時間給其它進程。

所以,考慮到系統中總體的進程情況,將優先順序轉換為權重,將時間片轉換為份額,CFS就是了。最終的坐標系應該是 權重佔比/時間片 坐標系而不是 權重(或者優先順序)/時間片 。應該是這個平滑的樣子:

看來,Linux CFS只是為了解決O(1)O(1)中一個 「靜態優先順序/時間片映射」 問題的,那麼可想而知,它又能帶來什麼驚艷效果呢?這里還有個「但是」,這個O(1)O(1)調度器的問題其實在計算密集型的守護進程看來,並不是問題,反而是好事,畢竟高優先順序進程可以 無條件持續運行很久而不切換 。這對於吞吐率的提高,cache利用都是有好處的。無非也就侵擾了交互進程唄,又有何妨。

當然,使用調優CFS的時候,難免也要遇到IO睡眠獎懲等剩餘的事情去設計一些trick演算法,這破費精力。

對了,還要設置你的內核為HZ1000哦,這樣更能體現CFS的平滑性,就像它宣稱的那樣。我難以想像,出了Ubuntu,Suse等花哨的桌面發行版之外,還有哪個Linux需要打開HZ1000,伺服器用HZ250不挺好嗎?

關於調度的話題基本就說完了,但是在進入下一步固有的噴子環節之前,還有兩點要強調:

在CPU核數越來越多的時代,人們更應該關心 把進程調度到哪裡CPU核上 而不是 某個CPU核要運行哪個進程

單核時代一路走過來的Linux,發展迅猛,這無可厚非,但是成就一個操作系統內核的並不單單是技術,還有別的。這些當然程序員們很不愛聽,程序員最煩非技術方面的東西了,程序員跟誰都比寫代碼,程序員特別喜歡噴領導不會寫代碼雲雲。

Linux在純技術方面並不優秀,Linux總體上優秀的原因是因為有一群非代碼不明志的程序員在讓它變得越來越優秀,另一方面還要歸功於開源和社區。Linux的學習門檻極低,如果一個公司能不費吹灰之力招聘到一個Linux程序員的話,那它幹嘛還要費勁九牛二虎之力去招聘什麼高端的BSD程序員呢?最終的結果就是,Linux用的人極多,想換也換不掉了。

但無論如何也沒法彌補Linux內核上的一些原則性錯誤。

Linux內核還是以原始的主線為base,以講Linux內核的書為例,經典的Robert Love的《Linux內核設計與實現》,以及《深入理解Linux內核》,在講進程調度的時候,關於多核負載均衡的筆墨都是少之又少甚至沒有,如此經典的著作把很多同好引向了那萬劫不復的代碼深淵。於是乎,鋪天蓋地的CFS源碼分析紛至沓來。

但其實,拋開這么一個再普通不過的Linux內核,現代操作系統進入了多核時代,其核心正是在cache利用上的革新,帶來的轉變就是進程調度和內存管理的革新。review一下Linux內核源碼,這些改變早就已經表現了出來。

可悲的是,關於Linux內核的經典書籍卻再也沒有更新,所有的從傳統學校出來的喜歡看書學習的,依然是抱著10年前的大部頭在啃。

http :// www. ece.ubc.ca/~sasha/papers/eurosys16-final29.pdf

浙江溫州皮鞋濕,下雨進水不會胖。

作者:CSDN博主「dog250」,本文首發於作者CSDN博客https://blog.csdn.net/dog250/article/details/957298 30 。

【END】

❿ 如何讀懂linux內核源碼

Linux的內核源代碼可以從很多途徑得到。一般來講,在安裝的linux系統下,/usr/src/linux目錄下的東西就是內核源代碼。

對於源代碼的閱讀,要想比較順利,事先最好對源代碼的知識背景有一定的了解。對於linux內核源代碼來講,我認為,基本要求是:1、操作系統的基本知識; 2、對C語言比較熟悉,最好要有匯編語言的知識和GNU C對標准C的擴展的知識的了解。
另外在閱讀之前,還應該知道Linux內核源代碼的整體分布情況。我們知道現代的操作系統一般由進程管理、內存管理、文件系統、驅動程序、網路等組成。看一下Linux內核源代碼就可看出,各個目錄大致對應了這些方面。Linux內核源代碼的組成如下(假設相對於linux目錄):

arch 這個子目錄包含了此核心源代碼所支持的硬體體系結構相關的核心代碼。如對於X86平台就是i386。
include 這個目錄包括了核心的大多數include文件。另外對於每種支持的體系結構分別有一個子目錄。
init 此目錄包含核心啟動代碼。
mm 此目錄包含了所有的內存管理代碼。與具體硬體體系結構相關的內存管理代碼位於arch/-/mm目錄下,如對應於X86的就是arch/i386/mm/fault.c 。
drivers 系統中所有的設備驅動都位於此目錄中。它又進一步劃分成幾類設備驅動,每一種也有對應的子目錄,如音效卡的驅動對應於drivers/sound。
ipc 此目錄包含了核心的進程間通訊代碼。
moles 此目錄包含已建好可動態載入的模塊。
fs Linux支持的文件系統代碼。不同的文件系統有不同的子目錄對應,如ext2文件系統對應的就是ext2子目錄。
kernel 主要核心代碼。同時與處理器結構相關代碼都放在arch/-/kernel目錄下。
net 核心的網路部分代碼。裡面的每個子目錄對應於網路的一個方面。
lib 此目錄包含了核心的庫代碼。與處理器結構相關庫代碼被放在arch/-/lib/目錄下。
scripts 此目錄包含用於配置核心的腳本文件。
Documentation 此目錄是一些文檔,起參考作用。

熱點內容
伺服器無法通過ip訪問 發布:2025-05-16 14:26:13 瀏覽:539
網吧u盤拒絕訪問 發布:2025-05-16 14:13:50 瀏覽:260
無線網檢查網路配置是怎麼回事 發布:2025-05-16 14:04:03 瀏覽:220
網路爬蟲python代碼 發布:2025-05-16 14:03:26 瀏覽:516
汽車小組件怎麼弄到安卓桌面 發布:2025-05-16 13:51:12 瀏覽:220
linuxg編譯器下載 發布:2025-05-16 13:50:58 瀏覽:776
centosc編譯器 發布:2025-05-16 13:50:17 瀏覽:948
安卓手機如何變換桌面 發布:2025-05-16 13:39:33 瀏覽:515
sql存儲過程命令 發布:2025-05-16 13:17:54 瀏覽:146
用紙做解壓小玩具西瓜 發布:2025-05-16 13:04:09 瀏覽:936