contributed by < steven1lung >
$ sudo insmod khttpd.ko port=1999
這命令是如何讓 port=1999
傳遞到核心,作為核心模組初始化的參數呢?htstress.c
用到 epoll 系統呼叫,其作用為何?這樣的 HTTP 效能分析工具原理為何?kecho
已使用 CMWQ,請陳述其優勢和用法create_*workqueue()
functions are deprecated and scheduled for removal",請參閱 Linux 核心的 git log (不要用 Google 搜尋!),揣摩 Linux 核心開發者的考量user-echo-server
運作原理,特別是 epoll 系統呼叫的使用bench
原理,能否比較 kecho
和 user-echo-server
表現?佐以製圖drop-tcp-socket
核心模組運作原理。TIME-WAIT
sockets 又是什麼?$ sudo insmod khttpd.ko port=1999
要將參數傳到核心可以使用 module_param(name, type, perm)
,這個巨集定義在 linux/moduleparam.>
中,module_param()
吃的參數依序為:變數名稱、變數型態、權限。前兩個都好懂,但是最後一個 @perm
是要做什麼呢,如果只是要讀取,為什麼讀取也要分權限?
文件提到,@perm
參數是要設定對應 sysfs 裡檔案的權限。Sysfs 是 linux 提供的一種虛擬檔案系統,這個系統不僅可以將裝置和驅動的資料傳送到 user space,也可以用來做對裝置和驅動的設定。虛擬檔案系統主要的功能就是讓上層的軟體可以用簡單的方法去和底層不同檔案系統溝通。這裡的 @perm
就是吃常見的 rwx
變數。
在 module_param()
巨集中,我們甚至可以使用陣列,但使用的方式就要透過 module_param_array()
或是 module_param_string()
。
在 khttpd/main.c
中,我們看到使用的方式如下:
我們可以設定預設值給 module_param()
,例如說我們執行以下命令 sudo insmod khttpd.ko
但不定義 port=1999
,就會讓程式裡 port
的值被設為 DEFAULT_PORT
也就是 8081
。
CMWQ 全名為 Concurrency Managed Workqueue,workqueue 的功用是為了要在多個非同步的執行緒下進行任務分派,當 workqueue 裡還有任務,workqueue 就會將任務指派給執行緒。
傳統的 workqueue 中,多執行緒 workqueue 會有跟處理器核數量相同數量的 worker(執行緒),而在單一執行緒 workqueue 中整個系統只會有一個 worker(執行緒)。
因為在多執行緒 workqueue 裡 worker 數量需要跟核心數量一樣,而近年來處理器核心數量的增加,所以導致在開機的時候就會將原本預設的 32k PID 空間佔滿。並且多執行緒 workqueue 不僅佔用了許多資源,達到的並行效果也沒有令人滿意,甚至不太好。每個 workqueue 都維護各自的 worker pool,work items 也會競爭資源,導致死結情況更容易發生。
於是就有人重新設計了 workqueue ,CMWQ 就出現了。依照下列目的進行設計:
alloc_workqueue
建立一個新的 workqueue,這個函式會吃 3 個參數,分別是 @name
、@flags
、@max_active
。
@name
是 workqueue 的名稱,也可以是之後 rescuer 的名稱。@flags
跟 @max_active
會控制 workqueue 裡面的工作會如何被排程跟分配執行。flags
WQ_UNBOUND
任務會被排到一個 unbound 的 workqueue 中,並會被多個沒被綁在特定 CPU 的 worker 執行。這個 flag 會讓 workqueue 變成不提供並行的單純任務提供者。Worker pools 裡的工人會盡快開始執行 workqueue 裡的任務。Unbound workqueue 會犧牲 locality,但是在一些場合中會有幫助。像是:執行時間長並且會被密集執行的任務會希望把並行排程交給系統的排程器。
WQ_FREEZABLE
可以凍結的 workqueue 會參與系統的 suspend 機制,在 workqueue 裡的任務會被分配,但是會等到 workqueue 解凍時才執行。
WQ_MEM_RECLAIM
只要 workqueue 有參與記憶體空間的領回,就必須要有這個 flag,這個 workqueue 會保證儘管有記憶體壓力也會至少有一個工人。
WQ_HIGHPRI
當要排進 workqueue 的任務是有高優先權的,會被排入 highpri 的 workqueue。要注意的是一般的 workqueue 跟高優先權的 workqueue 是分開管理的,兩者不會跟對方溝通。
max_active
這個參數決定了每個處理器最多可以執行的任務數量,例如說 max_active 設定為 16 會使在 workqueue 中最多有 16 個任務被單個 CPU 同時執行,預設值為 0。
destroy_workqueue
吃一個 workqueue 參數,這個函式會安全地刪除一個 workqueue,等正在執行的任務完成後再進行刪除。
queue_work
這個函式會將任務排入 workqueue 中,吃兩個參數,分別是 workqueue 的名字跟要被排入的任務。
這邊只列出在 kecho 使用到的函式,更詳細的 API 說明可以去看 Concurrency Managed Workqueue (cmwq)。
create_workqueue
的考量上方有提到換成 CMWQ 的好處了,我覺得最主要的原因是因為原本的 workqueue 不適合越來越多核處理器,會浪費許多資源,且並行的效果沒有令人滿意,所以設計出了新的 workqueue。
也有原因是因為越來越多的功能被加入 workqueue 之中,像是舊版的 workqueue 並沒有 flags 參數,而是將要使用的功能分成一個一個的參數分別輸入 workqueue,造成往後開發新功能造成麻煩。
在 97e37d7 中,作者提到了那時候的 workqueue 會吃 @SingleThread
跟 @freezable
這兩個參數來決定 workqueue 是不是單執行緒或是要不要有凍結功能。這個 commit 會將這兩個參數修改成 flags 形式,並且使用新的命名風格:WQ_XXXXXX
。
在 502ca9d 中,作者修改了原本的單執行緒 workqueue 讓他變成 shared worker pool friendly。原本的實作是限制 workqueue 只能使用一個特定的 CPU,但這個做法對要 worker pool 不太友善。所以使用了新的方法改善:使用動態的 CPU binding 跟 cwq->limit
。因為在任何時刻,單執行緒的 workqueue 都會被任一個 CPU 綁住。
上述的 cwq 全名是 cpu workqueue