or
or
By clicking below, you agree to our terms of service.
New to HackMD? Sign up
Syntax | Example | Reference | |
---|---|---|---|
# Header | Header | 基本排版 | |
- Unordered List |
|
||
1. Ordered List |
|
||
- [ ] Todo List |
|
||
> Blockquote | Blockquote |
||
**Bold font** | Bold font | ||
*Italics font* | Italics font | ||
~~Strikethrough~~ | |||
19^th^ | 19th | ||
H~2~O | H2O | ||
++Inserted text++ | Inserted text | ||
==Marked text== | Marked text | ||
[link text](https:// "title") | Link | ||
 | Image | ||
`Code` | Code |
在筆記中貼入程式碼 | |
```javascript var i = 0; ``` |
|
||
:smile: | ![]() |
Emoji list | |
{%youtube youtube_id %} | Externals | ||
$L^aT_eX$ | LaTeX | ||
:::info This is a alert area. ::: |
This is a alert area. |
On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?
Please give us some advice and help us improve HackMD.
Syncing
xxxxxxxxxx
2023q1 Homework1 (lab0)
contributed by <
yanjiew1
>開發與實驗環境
進度記錄
以下複製自「作業要求」
queue.[ch]
和連帶的檔案,測試後用 Git 管理各項修改,要能滿足$ make test
自動評分系統的所有項目。lab0-c
專案,比較你自己實作的 merge sort 和 Linux 核心程式碼之間效能落差qtest
提供的web
命令得以搭配上述佇列實作使用,目前一旦網頁伺服器啟動後,原本處理命令列操作的linenoise
套件就無法使用,請提出改善機制qtest
提供新的命令shuffle
,允許藉由 Fisher–Yates shuffle 演算法,對佇列中所有節點進行洗牌 (shuffle) 操作,需要以統計的原理來分析你的實作,探究洗牌的「亂度」qtest
中執行option entropy 1
並搭配ih RAND 10
一類的命令,觀察亂數字串的分布,並運用「資訊與熵互補,資訊就是負熵」的觀念,設計一組新的命令或選項,得以在qtest
切換不同的 PRNG 的實作 (可選定 Xorshift),搭配統計分析工具,比較亂數產生器 (如 Xorshift vs. 內建) 的品質qtest
執行過程中的錯誤qtest
實作的記憶體錯誤,並透過 Massif 視覺化 "simulation" 過程中的記憶體使用量,需要設計對應的實驗改進
queue.c
q_new
透過
malloc
來配置記憶體,使用list.h
裡面提供的INIT_LIST_HEAD
來初始化struct list_head
。q_free
使用
list.h
內提供的list_for_each_entry_safe
來走訪每一個節點。使用的過程中,safe
會存放下一個節點,而it
節點可以從 linked list 移除,不影響list_for_each_entry_safe
運作。故在這裡,可以直接在走訪的過程中釋放每一個節點。最後再呼叫free
釋放鏈結串列所配置的記憶體空間。。開發過程記錄
一開始程式碼如下:
隨後很快發現,應該要釋放
element_t
才對,因為struct list_head
是包含在element_t
裡面的一個成員。於是變更如下:但因為釋放
element_t
很常被用到,所以後來我寫一個獨立函式q_free_elem
來做。最後又發現queue.h
有提供q_release_element
,最後改成用q_release_element
,修改如下:後來又仔細研究
list_for_each_entry_safe
巨集後,發現list_del
可以不用做。此巨集的特性是我們可以把it
直接釋放,只要不要動到safe
,就可以安全操作。最後變更如下:q_new_elem
配合
q_insert_head
和q_insert_tail
要新增元素,新增此函式,用來建立element_t
。使用
malloc
來配置記憶體空間。使用strdup
來配置字串空間並拷貝字串。過程中如果配置失敗,則回傳NULL
。q_insert_head
和q_insert_tail
一開始要檢查
head
是否為NULL
,若為NULL
則不進行任何操作。使用前面建立的
q_new_elem
來建立element_t
。並且透過list_add
或list_add_tail
來把節點串上去。 若過程中失敗則回傳false
。q_copy_string
在
q_remove_head
和q_remove_tail
需要複製字串,且 buffer 的大小是有限制的。C 標準函式庫提供的strcpy
無法滿足此需求,故在此實作另一個函式q_copy_string
來完成字串拷貝。此函式是否必要?其通用的程度如何?
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →q_remove_head
和q_remove_tail
這裡實作從佇列中移走開頭或尾端。
利用
list_first_entry
和list_last_entry
來取得要移除的元素。使用list_del
來移除元素。題目要求要把移除元素的字串值拷貝到sp
這個 buffer ,並且 buffer 大小為bufsize
,就透過前面實作的q_copy_string
來做。q_remove_tail
程式碼相似,就不佔用版面了。正因程式碼相似度高,你更該思索如何簡化程式碼,從而降低維護的程式碼。
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →q_size
實作很簡單:直接使用
list.h
提供的list_for_each
來走訪每一個節點。每走訪一個節點就遞增count
變數,最後再回傳count
變數的值即為所求。q_delete_mid
這裡充份利用雙向鏈結串列的特性,從頭尾開始走訪節點,直到二個指標碰面時,即取得中間的節點。最後再把中間節點所代表的元素刪除。
q_delete_dup
我的作法是先宣告
cut
變數,其內容固定存放「目前走訪元素往前看,第一個其元素值與目前元素不同的元素」。此外另外宣告一個
trash
pending
作為暫時放置待移除元素的地方,要移除的元素都會先放在這裡,最後再一起清掉。"trash" 命名不精準,可用 pending list 一類的詞彙。
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →在走訪元素的過程中,
&safe->list != head && strcmp(safe->value, it->value) == 0
&safe->list != head && !strcmp(safe->value, it->value)
會去判斷下一個元素跟目前元素的值是否相同。若相同時,就繼續走訪,直到遇到下個元素safe
與目前元素it
值不同時,再來進行接下來操作,如下:當下個元素
safe
與目前元素it
不同時,會先去檢查cut
變數,是不是指向前一個元素。若是指向前一個元素,代表目前元素跟前一個元素不同,則不用處置,因為目前元素it
跟前一個元素沒有重複;若cut
不是指向前一個元素,則代表cut
指向更之前的元素,且 \((cut, it]\) 元素其值均相同,故把 \((cut, it]\) 元素全部丟到放到trash
pending
中。迴圈最後
cut = safe->list.prev;
這敘述,因為目前元素it
與下一個元素值safe
不同 (若相同就不會執行到此,故更新cut
為目前元素後,再進行下個迴圈。迴圈結束
q_delete_dup
要返回前。要清除trash
pending
裡的垃圾元素。用list_for_each_entry_safe
來走訪每一個trash
pending
中的元素,並用q_release_element
來刪除它。將
strcmp(safe->value, it->value) == 0
改為!strcmp(safe->value, it->value)
可縮減程式碼。- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →q_reverse
這裡的實作很簡單,就是用
list_for_each_safe
走訪每一個節點。走訪過程中,用list_move
把每一個節點移到開頭,這樣子順序就反過來了。list_for_each_safe
允許對目前走訪的節點移動位置。因為是往前移到開頭,故不會因為節點移動而改變走訪次序或是重複走訪。變更記錄
把
list_for_each_safe
大括號拿掉,按照 Coding Style ,這裡不用放大括號。q_reverseK
使用
count
來記錄已走訪幾個節點,一開始把count
設為k
,每走訪一個節點就把count
減去 1 。當走訪k
個節點時 (--count
變成 0),就會把cut
記錄的切點到目前走訪的節點(不包含cut
但包含it
,即(cut, it]
)切下,放到tmp
上,再重用前面實作好的q_reverse
,對tmp
做反轉,再用list_splice
把tmp
接回來。最後設定
safe->prev
為新的cut
。這裡不能用it
是因為it
已在反轉的過程中移動位置了。追加
list_empty()
的檢查。- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →q_swap
swap
就是二個二個一組進行reverse
,故直接重用q_reverseK
的程式 。q_merge_two
因為
q_sort
和q_merge
都會需要合併二個串列。故新增一個q_merge_two
用來合併二個串列。參考alanjian85
同學的實作。合併的方式是每次從輸入的二個串列中,取較小的,放到一個暫存串列中tmp
,之後再把串列接回first
。q_sort
採用 merge sort 遞迴演算法。一開始運用雙向鏈結串列的特性,從頭尾開始往中間找到中間節點,找到後,把 (
head
,mid
] 留在head
並把 (mid
,head
) 切下來加到second
中。再針對head
、second
分別遞迴呼叫q_sort
,對子串列進行排序。最後再把排序好的head
和second
透過q_merge_two
合併。若要改為迭代的實作,你預計怎麼做?
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →更新記錄
原本串列合併的程式直接寫在
q_sort
裡,後來把它移到獨立的函式中。q_descend
我的想法就是從尾到頭掃過一次。在掃的過程中,會判斷下一個節點(
prev
)是否小於等於目前節點(cur
),若是就把下一個節點(prev
)刪除再重複迴圈,直到下一個節點是大於目前節點時,才會把cur
移動到下一個節點,並且cnt
(計數器) 加 1 。目前
lab0-c
內建的list.h
標頭檔和 Linux 核心原始程式碼 include/linux/list.h 存在一些差距,後者的list_for_each_prev
巨集不在前者出現。若有它則可以用它來實作。針對呼叫
strcmp
的那行敘述,若搭配使用break
或continue
關鍵字,可進一步縮減程式碼。- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →q_merge
採用 Strategies for Stable Merge Sorting 這篇論文中的 2-merge 演算法來實作。用此演算法,使合併二個 queue 時,其二個 queue 元素數量差距不要太大。
其運作原理是這樣:
若 pending list 個數大於 3 個時,判斷是否合併:
x
,y
,z
。 若|y| < 2|x|
則按下步驟進行合併,若否,則繼續進行 2. 迴圈|x| < |z|
則將x
和y
合併,否則y
和z
合併x
、y
、z
,判斷是否符合需要合併的條件更新記錄
原本是這重用前面實作的
q_sort
。我把所有鏈結串列接在一起,然後呼叫q_sort
排序好,放回第一個串列。後來變更實作,改成直接進行合併,並且合併時,透過一些策略降低二個 queue 要合併時的長度差異。q_ascend
這是後來
lab-0
加上的函式,跟q_descend
很像。故把q_descend
的程式複製一份來用,把中間的<
改為>
即可。Valgrind 與 Address Sanitizer 記憶體檢查
Makefile 中關於
make valgrind
的內容分析裡面看到很神奇的部份,就是在用 Valgrind 執行時,會把
qtest
執行檔中,所有alarm
改為isnan
。我的猜測是因為 Valgrind 會使程式執行速度變慢,導致一些操作會超過時間限制。我把這行拿掉sed -i "s/alarm/isnan/g" $(patched_file)
,執行make valgrind
,果然就出現超時訊息。查詢 C 標準函式庫可知,isnan(3p) 是用來檢查傳入的浮點數是否為 NaN ,會選用這個函數來取代alarm
,估計是因為它跟alarm
一樣函式名稱都是 5 個字元,此外isnan
沒有任何 side effects ,故剛好可以拿來用。為了測試,我嘗試把isnan
替換成asinf
看看能不能運作。實測的結果如預期,可以正常運作。使用 Valgrind
執行
make valgrind
,產生了很多 Memory leak 的訊息。以下為節錄的訊息:我先用
valgrind ./qtest
的方式測試,發現只要在結束前沒有把所有的 queue 釋放,就會產生上述訊息。後來發現在q_quit
裡面,在第一行是return true;
使下面釋放記憶體的程式沒辦法執行。把這行拿掉後就正常了。但若是使用
valgrind ./qtest < traces/trace-01-ops.cmd
的方式來執行,仍然會出現下面訊息:從上述訊息可以看出是 linenoise 中處理 history 的部份出錯。分析了一下 linenoise.c 的程式碼,發現
line_atexit
只會在enable_raw_mode
函式裡被註冊為 atexit function ,但是在 stdin 不為 tty 的情況下enable_raw_mode
不會被呼叫到。故把註冊line_atexit
的程式移到linenoise
function 就解決了。至此,所有
make valgrind
會產生的記憶體問題都解決了。使用 address sanitizer
重新編譯有開啟 address sanitizer 的版本。
之後執行
make test
,沒有出現任何記憶體相關錯誤訊息。至此檢查通過。加入 option
descend
lab-0
在 Commit 0fcefb0 加入了descend
option ,故把上游版本sysprog21/lab0-c
合併進來時,也需要一併實作 optiondescend
。修改
q_merge_two
因為
q_sort
和q_merge
都會用到q_merge_two
來合併二個串列。故在q_merge_two
實作合併時,由大到小排序。其中迴圈內在選擇要哪一個元素放到合併後的串列時,做了些更動,如下:而
q_merge_two
函式宣告改為:針對
descend
為true
的清況,正負號反轉,即可實現大到小排序,且也維持q_sort
和q_merge
的穩定排序特性。修改
q_sort
和q_merge
而
q_sort
和q_merge
則是修改成:呼叫q_merge_two
時會多傳入descend
參數,來決定是否要由大到小排序。修改
q_ksort
q_ksort
是使用 Linux 核心的list_sort
排序演算法。list_sort
會傳入比較函式cmp
作為參數。故我實作一個比較函式q_cmp_descend
,它會呼叫原本的比較函式q_cmp
,但正負號相反,如下:再把
q_ksort
改成判斷descend
是否為true
,再選擇適當的比較函式。Linux 核心 Linked List 排序研究
整合 Linux 核心的
list_sort
將 Linux 核心原始程式碼的
list_sort.c
和list_sort.h
複製到lab0-c
專案中,進行些許修改讓它可以成功在這個專案中編譯。主要是把u8
改為uint8_t
(並加入stdint.h
) 、移除不必要的#include
。之後修改Makefile
加入list_sort.o
後,確認用make
命令可以正常編譯。接下來是額外撰寫一份用 Linux kernel 排序的程式。因為
queue.h
不能更動,我決定把這個程式放在另一個檔案ksort.c
並且有對應的標頭檔ksort.h
。 此也在Makefile
內加入ksort.o
。因為 Linux kernel 實作需傳入
cmp
比較函式作為比較大小用。我的實作如下:我新增了一個 option
ksort
,可以用來切換排序實作。在qtest.c
按照原本定義 option 的格式新增下方程式在console_init
中。此外也加入一個全域變數來記錄目前要使用的排序實作。未來或許會有多款排序的實作,設計選項時,應予以考慮,亦即你可用
option sort 0
(預設),option sort 1
(上述來自 Linux 核心原始程式碼的list_sort
),option sort 2
(未來實作的排序程式碼) 來切換。- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →效能分析
在開始分析效能前。看到 Linux 核心的
list_sort
是以 bottom-up 方式實作 merge sort 並且合併方式是用對 cache 較友善的方式。即 \(3 \times 2^k\) 就合併,大概可以猜測 Linux 的排序實作效能會比較好。我用以下的命令序列來分析排序效能:為了避免出現 Time out 的問題。開始測試前會先 patch ./qtest,即
sed -i "s/alarm/isnan/g"
。測試的結果如下表:
可以看到我的 top-down 排序演算法花的時間是 Linux 核心
list_sort
實作的 1.341 倍。即比 Linux 排序演算法慢 34% 左右。Linux Kernel Linked List 排序演算法探索
Linux 核心是使用 bottom-up 的 merge sort ,但是它合併的方式跟傳統教科書不一樣。
TODO 補完此節
web
命令/網頁伺服器改善TODO
亂數研究及 shuffle 實作
程式實作
在作業說明裡面,每次抽到的數字後,都要從最前面開始往後數,這樣子會讓時間複雜度最壞情況至 \(O(n^2)\) ,故我採取不同的策略。
我先建立一個存放所有節點的指標陣列,如下所示:
可變更為
malloc(sizeof(*entries) * size)
以縮減程式碼。- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →把所有節點的位址放入陣列中:
取得隨機數先直接使用 C 語言標準函式庫提供的
rand
函數取得隨機數。因為rand
的範圍是[0, RAND_MAX]
,RAND_MAX
不一定可以被候選數個數整除。故使用一個迴圈,丟棄任何會大於RAND_MAX - (RAND_MAX % k)
的數值,使得取得的隨機數最大值可被候選數個數整除。讓每一個候選數被選中的機率是一樣的。以下是相關程式碼片段。這裡要取得 \([0, i]\) 之間的數。對照看
random.[ch]
程式碼。- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →這樣的實作缺點是需要使用
malloc
來配置額外空間。無法做到空間複雜度 \(O(1)\) 。目前還沒想到能在時間複雜度為 \(O(n)\) 情況下,空間複雜度為 \(O(1)\) 的方式。Fisher–Yates shuffle 亂度分析
分析方式為建立一個 queue , 並分別新增 a, b, c, d 至 queue 中。執行 shuffle 1000000 次,並統計每種排列方式出現的次數。
直接使用作業說明提供的程式來分析。把作業說明的 Python 程式複製到
script/shuffle.py
,並修改改用 a, b, c, d 來進行 shuffle 測試。使用此線上工具計算 P 值,計算出來為 0.34 左右,故無法拒絕 Fisher–Yates shuffle 不是 Uniform Distribution。
Entropy 觀察
跟據作業要求,執行以下命令來觀察 entropy。
大致上可以發現,在相同字串長度下,不重複的字母數愈多,其 entropy 愈高。例如:
ciahh(21.88%)
,xffww(17.19%)
,也就是代表其亂度愈高。從 entropy 公式可以發現,若字串中每一個字母其出現機率愈一致(即字串愈亂),且一字串所包含的不同字母數愈多 (即每個字母出現的機率一致),其 entropy 愈高,符合作業說明所說的。
不過到這裡,我還是沒有完全理解 entropy 的意義,目前的理解是:它用來表達一個訊息內容有多亂。之後還要再研讀。
加入 Xoshiro256++ 亂數產生器並比較系統提供之亂數產生器
qtest
亂數產生器存放在random.c
,可以看到此亂數產生器是直接使用 Linux 核心提供的亂數產生器。我跟據作業提供的 Wikipedia Xorshift 參考連結,並參考了相關的變形實作。我決定引進 Xoshiro256++ 來作為另一套亂數產生器。因為原本的 Xorshift 跟據維基百科說明,在統計上可能有些瑕疵。而其變種 Xoshiro256++ 在作者官網介紹中感覺看不出有瑕疵。
作者在他的網站上提供了 Xoshiro256++ 的程式碼,故我就直接使用作者網站提供的程式碼,再做點修改。此外作者建議使用 SplitMix64 作為初始化 Xoshiro256++ 的內部狀態,同樣也在他的網站上提供程式碼,我也直接把它拿來用。
把上述程式結合,再做點修改後,Xoshiro256++ 亂數產生器程式放在 xoshiro.c 檔案內。
另外再建立一個
qrandom.c
檔案,這裡是亂數產生器的單一入口,會再透過全域變數qrandom_impl
來決定要使用的亂數產生器。而qrandom_impl
可用option random
來控制。目前設定是qrandom_impl == 0
時使用系統提供的亂數產生器,qrandom_impl != 1
時就用 Xoshiro256++。此外,我在
qtest.c
內實作-r
選項,可讓qtest
直接使用內部的亂數產生器,產生隨機 raw bytes 並輸出到 stdout 。-r 0
為使用內建的亂數產生器,-r 1
為使用 xoshiro256++ ,搭配作業說明ent
工具來評估亂數產生器的品質。在
main
函式處理命令列選項的 switch-case 地方加入:另外也新增一個函式
generate_randombytes
,來把亂數輸出到 stdout 。Xoshiro256++
亂數品質測試執行下面命令來測試亂數品質,可得到這個報告
卡方檢定的結果 p 值為 32.52% ,離 5% 遙遠,故此亂數產生器產生的亂數可能是 Uniform Distribution 的。
此外 entropy 值為 7.99998 bits per byte, 可說是相當高。
系統內建亂數測試
卡方檢定的結果 p 值為 60.75% ,離 5% 遙遠,故此亂數產生器產生的亂數可能是 Uniform Distribution 的。
此外 entropy 值為 7.999983 bits per byte, 也是相當高。
故二種亂數產生器均能產生品質不錯的亂數。
原本想要用
dieharder
測試,但跑了很久都沒有結束,所以後來就先提供ent
報告結果。你若對這主題感興趣,可對照閱讀 Uniting the Linux random-number devices,亂數產生器的品質,是近期 Linux 核心的重要開發方針之一。
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →研讀論文〈Dude, is my code constant time?〉
dudect
統計原理dudect
會以二種不同類型的資料作為輸入,對待測的程式進行多次時間量測,並分別觀察二種資料作為輸入時其執行時間的分布,進行比較。這二種不同類型的資料分別是:若固定輸入資料與隨機輸入資料的時間分布有顯著差異,則可以證明待測的程式其執行時間不是常數時間。反之則其執行時間可能是常數時間 (即無法拒絕其為常數時間)
執行
dudect
分為三步驟:dudect
是用 Welch’s t-test這份文件有其他人寫的論文說明也可供參考
需要再研讀 目前還是不懂 Welch’s t-test 和 Student's t-test 的原理,還需要再研究。
目前
lab0-c
內dudect
缺陷我發現
lab0-c
裡dudect
有許多嚴重錯誤會導致偏差lab0-c
的程式碼,發現的確沒有 percentile 相關程式。在原始的 oreparaz/dudect 會先計算 percentile 並把極端值除去。故在lab-0
裡沒有正確實作這部份。constants.c
裡的prepare_inputs
和measure
設計錯誤。prepare_inputs
裡的字串產生程式沒有辦法產生長度一致的字串,因為 randombytes 可能會讓字串中間有'\0'
,此外prepare_inputs
沒有跟據「固定資料」產生固定字串。prepare_inputs
雖然一開始產生隨機資料放在input_data
中,但這份資料沒有在measure
使用dudect
是直接用rdtsc
指令來計算花費週期數,但計算的結果會包含程式執行到一半可能會被中斷去執行,因為系統上不是只有待測程式在執行。對
lab-0
中dudect
的改進改進方法如下:
dudect.h
引入我的程式,但把它拆成dudect.c
和dudect.h
。dudect.c
內的randombytes
和randombit
的函式移除, 因此在random.c
就有提供相同的函式了。dudect
原本是設計一個 binary 只能有一種測試,因為它會直接呼叫prepare_inputs
和do_one_computation
這二個由使用者實作的函式,但因為lab0-c
有四個待測物,故我把dudect_config_t
內加入prepare
和compute
二個存放 function pointer 欄位,然後把原本呼叫prepare_inputs
和do_one_computation
改成呼叫dudect_config_t
內的 function pointer 。DUDECT_NOT_ENOUGHT_MEASUREMENTS
這個狀態。並修改report
在還沒收集足夠資料時,回傳DUDECT_NOT_ENOUGHT_MEASUREMENTS
。而dudect_main
函式中,預設也是在還沒測試時回DUDECT_NOT_ENOUGHT_MEASUREMENTS
measure.c
和measure.h
,放置待測程式及dudect_config_t
的相關設定。並且也實作is_##op_const
巨集用來產生is_xxx_const
函數供qtest.c
內的程式呼叫。此外把CHUNK_SIZE
提升到 640 使測試更準確。因為版面有限,就不把程式碼貼出來,可點連結觀看。完成以上步驟後,
make test
的結果正確回報為執行時間為常數時間。請提交 pull request。
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →可再進一步實驗
perf_event_open
搭配config = PERF_COUNT_HW_CPU_CYCLES
量測時間。看看能不能更能排除待測程式執行時被中斷的執行時間。labc-0
中的dudect
程式做修正,而不是直接引入上游最新版和重寫測試程式。貢獻與程式改進記錄
修正 GitHub Action 問題
我檢視我的 repository 的 GitHub Action 有無正常運作時,發現 GitHub Action 在
Run webfactory/ssh-agent@v0.7.0
這個步驟時就失敗了。於是我就看了一下原始的
sysprog21/lab0-c
repository 。裡面的 GitHub Action 可以運作成功。發現原來Run webfactory/ssh-agent@v0.7.0
是用來載入 ssh private key 讓原始sysprog21/lab0-c
repository 在沒有queue.c
的解答情況下,能從另一個 private repository 拷貝queue.c
來使用,使原始的sysprog21/lab0-c
repository 的 GitHub 在沒解答情況下也可以測試。但是在 fork 之後的 repository ,不會有 ssh private key 。導致在
Run webfactory/ssh-agent@v0.7.0
步驟就失敗,以致後面的make check
、make test
等步驟都不會執行。我看了 GitHub 的文件後,發現可以把 GitHub Action 某個步驟標示為即使失敗仍然能繼續執行。故我在
.github/workflows/main.yml
裡進行小修正,針對webfactory/ssh-agent@v0.7.0
這個步驟加入continue-on-error: true
來讓它失敗時,也可以往下執行其他 GitHub Action ,使得即便沒有 ssh private key , GitHub Action 也能有作用。我為此建了一個 pull request 來提交我的改動,目前已經被 merge 了。
其他貢獻
return true;
inq_quit
function原本的程式
q_quit
一開始就return true;
導致後面記憶體釋放的程式沒有執行,以致於觸發 valgrind memory leak。此 pull request 改善此問題line_atexit
inlinenoise
functionline_atexit
內會呼叫free_history
釋放記憶體。但在 stdin 非 tty 時,line_atexit
不會被註冊,以致於使用檔案輸入指令時,沒辦法釋放linenoise
記憶體,導致linenoise
出現 memory leak 。此 pull request 修正此問題。Merge do_i(h|t)
into a single functionTODO 放 GitHub Pull requests
其他記錄
cppcheck 問題
要 commit 時發現在
report.c
中的static char *msg_name_text[N_MSG]
變數宣告會觸發 cppcheck 錯誤。原本打算把此行改為static char * const msg_name_text[N_MSG]
,但後來發現 GitHub 有更新新的程式碼加入// cppcheck-suppress constVariable
修正此問題,因此我直接在 GitHub 網頁介面上操作 sync fork 取得更新的程式至自己 fork 出來的 repository 。因為自己只寫了一點點程式,故直接捨棄本地端的 commit,用 GitHub 上新的程式覆寫本地的 repository 。
可善用
git rebase
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →