[Linux 核心設計 (2025): 第 6 份作業解說](https://www.youtube.com/watch?v=zxGEER-1ru8&t=1413s) read 一開始並不會到 user space 一定是在 kernel 處理,所以 user space 必須去 kernel 讀取網路封包,接著進行某些加工後,再 write 回 kernel,在透過驅動程式將封包交給 client 端(網路瀏覽器、社群軟體)。 > 所以這過程有大量的資料複製要處理。 ![r1Iqseg1gg](https://hackmd.io/_uploads/SktY6KUyle.png) sendfile 合併了傳統的 read 及 write。原先的步驟是從檔案系統讀取內容傳到 user space,再將資料從 user space 傳到 kernel,合併後的優點是 user space 只要檢查執行結果就好。所以如今的網路伺服器幾乎都在 user space 實作。 io_uring 是 Linux 的明星技術,受到了廣泛的關注。 epoll 這個系統呼叫可監控多個事件。但本質上是同步的,而 io_uring 是 AIO。 Ftrace 也是動態追蹤 linux 核心的工具,在授課老師撰寫的排程器書籍第六章有相關介紹,主要用於追蹤特定時間段,kernel 某部份的程式碼執行時間 kecho > 是運作在 kernel 的 server。 將專案 clone 下來後,使用 make 進行編譯。 接著要掛載 `kecho.ko` 檔。 ```shell $ sudo insmod kecho.ko ``` 接著可透過下列命令來檢查是否運作: ```shell $ telnet localhost 12345 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. ``` 接著輸入下方命令可以離開: ```shell ^] telnet> q Connection closed. ``` > 其中 ^] 並非直接輸入,而是按下 ctrl+] 專案中的 ./bench 可用來效能分析,會將結果輸出至 bench.txt ```shell $ ./bench $ vim bench.txt 0 31 1 35 2 38 3 41 4 48 5 48 6 51 7 57 8 55 9 68 ... ``` user-echo-server > 是運作在 user space 的 server 使用之前要先將 kecho 解除: ```shell $ sudo rmmod kecho ``` 再執行一次 `make check`: ```shell $ make check make -C /lib/modules/6.11.0-21-generic/build M=/home/boju/Linux2025/kecho KBUILD_VERBOSE= modules make[1]: Entering directory '/usr/src/linux-headers-6.11.0-21-generic' warning: the compiler differs from the one used to build the kernel The kernel was built by: x86_64-linux-gnu-gcc-13 (Ubuntu 13.3.0-6ubuntu2~24.04) 13.3.0 You are using: gcc-13 (Ubuntu 13.3.0-6ubuntu2~24.04) 13.3.0 make[1]: Leaving directory '/usr/src/linux-headers-6.11.0-21-generic' Preparing... Send message via telnet Progress : [########################################] 100% Complete ``` 上述進度條的相關實作在 `scripts/util.sh` 中 drop-tcp-socket 這也是一個核心模組,若 kecho 崩潰,但沒有釋放其佔用的埠,可用將指定的埠關掉。 seHTTPd * Ractor pattern 大量存在於 server 中,針對大量連線的情境,並沒有對每個單一的連線請求建立獨立的 thread,其想法在於,只先準備一個 thread,再轉送給其他 handler。 將專案 clone 下來後,主要要看的程式碼在 /src 中 epoll 效率很高,為何還要 select 及 poll?? > 使用場景不同,如同排序演算法, 編譯完後使用下列命令執行伺服器: ```shell $ ./sehttpd Web server started. ``` 開啟另一個終端機視窗,輸入下列命令可以監看伺服器的效能: ```shell $ ab -n 10000 -c 500 -k http://127.0.0.1:8081/ ``` > 這個跑超級慢。 結果如下: ```shell Server Software: Server Hostname: 127.0.0.1 Server Port: 8081 Document Path: / Document Length: 0 bytes Concurrency Level: 500 Time taken for tests: 874.832 seconds Complete requests: 1747 Failed requests: 0 Keep-Alive requests: 0 Total transferred: 424764 bytes HTML transferred: 0 bytes Requests per second: 2.00 [#/sec] (mean) Time per request: 250381.240 [ms] (mean) Time per request: 500.762 [ms] (mean, across all concurrent requests) Transfer rate: 0.47 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 0 0.0 0 0 Processing: 500 501 0.2 501 501 Waiting: 0 0 0.0 0 0 Total: 500 501 0.2 501 501 Percentage of the requests served within a certain time (ms) 50% 501 66% 501 75% 501 80% 501 90% 501 95% 501 98% 501 99% 501 100% 501 (longest request) ``` 而 [httperf](https://github.com/httperf/httperf) 也可作為伺服器效能的評估工具。 > 須從原始程式碼編譯。 在 lab0-c 評估常數時間時,可以將 outlier 去除,但反映在網頁伺服器上,這個議題須更慎重考慮。 BPF 程式一但編譯後變成了 byte code,就會注入到 Linux Kernel。 # khttpd 一樣先使用 make 編譯,編譯完成後要掛載,命令如下: ```shell $ sudo insmod khttpd.ko ``` 同時也可以自行指令埠要用幾號: ```shell $ sudo insmod khttpd.ko port=1999 ``` 接著使用下列命令可以建立客戶端連線: ```shell $ wget localhost:1999 ``` 用下方命令可以觀測 port 狀況: ```shell $ sudo netstat -apn | grep 8081 tcp 0 0 0.0.0.0:8081 0.0.0.0:* LISTEN 9362/./sehttpd ``` > 我還不知道為啥是觀測 8081,因為上面指定的是 1999。 重新看了一下影片,老師有先解除掛載,然後再重新掛載一次,並且這次沒有指定 port。不過當我進行一樣的操作時,出現下方資訊: ```shell $ sudo rmmod khttpd $ sudo insmod khttpd.ko insmod: ERROR: could not insert module khttpd.ko: Address already in use ``` > 還不確定問題所在。 接著可以使用 `htstress` 進行壓力測試: ```shell ./htstress -n 100000 -c 1 -t 4 http://localhost:8081/ ``` 結果如下: ```shell 0 requests 10000 requests 20000 requests 30000 requests 40000 requests 50000 requests 60000 requests 70000 requests 80000 requests 90000 requests requests: 100000 good requests: 100000 [100%] bad requests: 0 [0%] socket errors: 0 [0%] seconds: 1.114 requests/sec: 89732.051 ``` 下方命令可查看與模組相關的 kernel thread: ```shell $ ps -ef | grep khttpd 0|1 err 17:04:54 root 4149 2 0 16:40 ? 00:00:00 [khttpd] boju 105022 3983 0 17:04 pts/0 00:00:00 grep --color=auto --exclude-dir=.bzr --exclude-dir=CVS --exclude-dir=.git --exclude-dir=.hg --exclude-dir=.svn --exclude-dir=.idea --exclude-dir=.tox --exclude-dir=.venv --exclude-dir=venv khttpd ``` 改進網頁伺服器性能,可以透過 ftrace 來追蹤,首先要先確認目前系統是否有 ftrace: ```shell $ cat /boot/config-`uname -r` | grep CONFIG_HAVE_FUNCTION_TRACER CONFIG_HAVE_FUNCTION_TRACER=y ``` 接著是結合剛剛的壓力測試去撰寫簡單的測試腳本: ```c #!/bin/bash TRACE_DIR=/sys/kernel/debug/tracing # clear echo 0 > $TRACE_DIR/tracing_on echo > $TRACE_DIR/set_graph_function echo > $TRACE_DIR/set_ftrace_filter echo nop > $TRACE_DIR/current_tracer # setting echo function_graph > $TRACE_DIR/current_tracer echo 3 > $TRACE_DIR/max_graph_depth echo http_server_worker > $TRACE_DIR/set_graph_function # execute echo 1 > $TRACE_DIR/tracing_on ./htstress localhost:8081 -n 2000 echo 0 > $TRACE_DIR/tracing_on ``` 將其命名為 `test.sh`,可以以下列命令執行: ```shell $ sudo bash test.sh 0 requests 200 requests 400 requests 600 requests 800 requests 1000 requests 1200 requests 1400 requests 1600 requests 1800 requests requests: 2000 good requests: 2000 [100%] bad requests: 0 [0%] socket errors: 0 [0%] seconds: 0.299 requests/sec: 6681.901 ``` > 每秒可以回應將近 7000 個連線,相比剛剛少了很多。 接著去追蹤 `ftrace` 的結果: ```shell $ sudo cat /sys/kernel/debug/tracing/trace ``` 會發現花費許多時間在: ```shell http_parser_callback_message_complete [khttpd](); ``` 從這些花費時間較長的函式去改善,就有相當大的優化空間。 > 此為本作業重要的要求。 `ftrace` 還能追蹤函式的階層關係,我還沒詳細去操作過。