contributed by <yanjiew1
>
就在閱讀 list_sort.c
的原始碼過程中,發現 list_sort.c
內的 merge
,搭配你所不知道的 C 語言: linked list 和非連續記憶體的技巧,透過 indirect pointer 的方式減少 if 敘述,故很快的就就做了相關的修改,如下:
同樣的修改也適用在 tools/lib/list_sort.c
檔案內。
為了送出我的 patch ,我閱讀了 Linux 核心的貢獻 patch 說明 Submitting patches: the essential guide to getting your code into the kernel ,按照說明的方式來貢獻。
跟據說明,需要透過 git format-patch
來讓 git 跟據 commits 來產生 patch ,故會需要先 clone Linux kernel git repository 。
需要先 clone 最新的 Linux kernel tree 。其中可以透過 Google 提供的 Linux kernel 的 git mirror 來加速 clone 。
下載完後,我就去修改 lib/list_sort.c
和 tools/lib/list_sort.c
的程式碼。這二邊的程式基本上是相同的,但前者是用在 kernel 本身,後者用在 Linux kernel 提供的使用者模式下的工具 .
我的 commit message 如下:
在 commit 之前,先透過 git 命令設定自己的名字和 E-mail ,這樣才能正確出現在 commit message 中:
之後再用 git commit -s
來進行 commit ,特別注意 -s
這個參數,它會為 commit message 加入 Signed-off-by: ....
,....
是自己的名字和 E-mail ,是貢獻 Linux 核心需要加入的,代表自已對這個 commit 負責。
Linux 核心貢獻不像 GitHub 是透過 Pull request ,是透過電子郵件寄送 patch 來貢獻。 git 提供了方便的命令 git format-patch
來建立 patch 。
其中, --base=auto
是在 patch 中加入 base commit 的 hash ,讓開發者和 CI 工具知道你的 patch 是基於哪個 commit 建立的。 -o patch
用來指定 patch 檔案輸出目錄。 origin/master
用來告訴 git 要跟哪一個 git ref 做比較,這裡是指定 origin/master
也就是上游遠端的 repository 中的 master branch 。
在 Submitting patches: the essential guide to getting your code into the kernel 文件,特別強調 E-mail 應以純文字寄送,不應用 MIME 格式或把 patch 放在附件。但現在的 Gmail 或是像是 Thunderbird 等軟體都會去嘗試對 E-mail 內的格式做調整,這樣核心開發者收到 patch 沒辦法直接去套用。
但還好的是 git
提供一個很方便的工具來寄信, git send-email
,透過它就不會有上述問題。 https://git-send-email.io/ 這個網站有提供設定教學。關鍵點是在 ~/.gitconfig
加入 SMTP 資訊,如下:
設定完成後,就可以來寄信了。至於要寄給誰呢? Linux 核心原始碼目錄裡,提供一個方便的工具 (./scripts/get_maintainer.pl
) 來查詢要寄給誰。
如上所示,要寄給 linux-kernel@vger.kernel.org
。
在 2023/3/28 , Jserv 老師跟我說,我應該要寄給相關的 lib
維護者和近期對 lib/list_sort.c
有較多修改的開發人員。
故上述 ./scripts/get_maintainer.pl
是不夠的,仍然要去翻閱 Commit log 和看核心程式碼下的 MAINTAINERS
檔案來查詢要寄送的人員。
以 lib/list_sort.c
來說,還需要包含 George Spelvin <lkml@sdf.org>
做完設定,找出收件者,就來寄信了。寄信很簡單:
故我用下方命令來寄。如果怕寄錯,可以先寄給自已確認沒問題再寄出。
過幾分鐘後,就可以在 Linux kernel mailing list 看到自已寄的 patch 。
我的 patch 在這。
第一個 patch 不是最完美的,我很快就發現我的 patch 還可以寫得更好。透過改用 do-while
迴圈,可以減少一個分支指令:
修改完成後,用 git add lib/list_sort.c tools/lib/list_sort.c
把相關檔案加入 staging area ,然後用 git commit --amend
來重寫目前的 commit 。
再用 git format-patch
命令來建新的 patch
上述的 -v 2
代表此 patch 是第二版。執行完後,會產生 patch_v2/v2-0001-lib-list_sort-reduce-if-statements.patch
就是新的 patch 檔。
與前面不一樣的是,第二版以後的 patch 都要加入修改記錄,故用文字編輯器打開 patch 檔案,在 commit message 後 ---
下方加入:
為了避免洗版,和讓核心開發人員可以關聯原始 patch 和新版的 patch ,要在 E-mail header 加入 In-Reply-To , 內容是第一版的 Message ID 。故到 Linux Kernel Mailing List 查詢自已寄送 patch 的 Message ID :
或是看最下方的 Reply Instruction:
這裡就告訴我們怎麼用 git send-email
來寄送。但這裡還是要把 to
改成 linux-kernel@vger.kernel.org
,而 --cc ...
就可以拿掉了。最後的寄送命令是:
這樣子第二版的 patch 就寄出了。
在 3/28 , Jserv 老師跟我討論貢獻的事時,因為我沒附上 --cc
至相關開發人員,他建我一段時間後再重寄 v4
版本,並附上實驗數據。因此我就開始做了實驗。
我在 Compiler Explorer 把 merge
的程式片段放進去。連結在此。
仔細推敲後,發現
cmp(priv, a, b) <= 0 ? &a : &b
這段程式,仍會產生分支指令,沒有辦法用沒有分支的版本來做。故我提出的修改,仍需要每個迴圈執行 2 個分支指令。a
和 b
二變數放在記憶體而不是暫存器中,導致我的版本需要更多記憶體存取。我把 Linux Kernel 的 list_sort.c
和相關 header 取出,獨立出來做實驗。
實驗結果如下:
list_sort_old
list_sort_new
果然我提出的 merge 在 cycle 數、instruction 數量,記憶體存取數及花費時間都比較慢。
故這個貢獻計畫就取消了。
為了避免開發者誤用 patch ,故我再寄了一封信到 Linux Kernel Mailing List 如下。
因為這是一封回信。原本我想要直接在 Gmail 寄,但 Gmail 在寫信的過程中,因為字體不是等寬,沒辦法讓我判斷每一行的字數。後來改用 Thunderbird 這個 E-mail Client,它有 Auto Wrap 的工具,可以自動把太長的行折下來。
寄出後,沒多久,信件就出珼在 Linux Kernel Mailing List
至次第一分貢獻宣告失敗。
這次失敗經驗讓我學到: 不要太急著送 patch ,好好做實驗,確認提出的程式是更好的作法,且沒有問題,才發送 patch 。
真的很感謝 Jserv 老師的指導,讓我發現我提出 patch 的問題。