contributed by < youjiaw >
留意各式細節,唯有重視小處並步步為營,方可挑戰原始程式碼規模超越三千七百萬行的 Linux 核心。
好的
yu-hsiennn
改寫程式碼 ( q_sort ),使其更為精簡。
感謝提醒,已修改。
實做 queue
對照 Dictionary.com 對 implement 一詞的解釋:
「實作」會是符合上述 "implement" 語意的譯詞,取「起」以「創作」的意思,而「製造」本質上是固定輸入並通常產生固定輸出的行為。
資訊科技詞彙翻譯
q_new
配置記憶體,並用 INIT_LIST_HEAD
初始化。
q_free
一開始實作時,沒有確認 head
是否有成功配置到記憶體,在 make test
的 "Test of malloc failure on new" 會出現錯誤。
q_insert_head
, q_insert_tail
原本未檢查記憶體配置情況,在 make test
的 "Test of malloc failure on insert_head, insert_tail" 出現錯誤。
q_remove_head
, q_remove_tail
使用 API 的 list_entry
取得開頭的 element
,將值複製到 sp
並從佇列移除。
q_remove_tail
的做法相同,但改取尾端的 element
。
q_size
使用教材提供的做法。
列出程式碼的目的是討論和檢討,倘若你沒有如此的舉措,就不用列出。
好的,已修正。
q_delete_mid
避免非必要的項目縮排 (即 *
和 -
),以清晰、明確,且流暢的漢語書寫。
好的,謝謝老師提醒。
我原本的做法如下,除了沒有考慮到 q_size
逐一走訪每個節點的成本,使用 indirect pointer 來實作此函式的優缺點也需討論。
在參考 chun61205 以及 yanjiew1 的建議後,決定使用兩個指標,從頭尾往中間找,以此減少記憶體的存取次數。
commit 85a19ba
q_delete_dup
避免非必要的項目縮排 (即 *
和 -
),以清晰、明確,且流暢的漢語書寫。
由於是傳入已排序的佇列,因此,只需檢查相鄰節點的值是否相同。
使用 list_for_each_entry_safe
逐一走訪每個節點,若 current
與 next
的值相同,就刪除 current
,而 flag
的作用為刪除最後一個重複的節點。
目前發現 make test
有時後會出現以下錯誤:
ERROR: Duplicate strings are in queue or distinct strings are not in queue
在經過 ./qtest
測試不同測資後,發現如果最後一個節點有重複的話,會直接被跳過,因此加入檢查程式碼。
commit bb834f2
q_swap
避免非必要的項目縮排 (即 *
和 -
),以清晰、明確,且流暢的漢語書寫。
使用 list_for_each
逐一走訪每個節點。
使用 list_move
將 next
移到 prev
後方,等同於將 current
與 next
交換位置。
q_reverse
用指標 first
指向開頭節點,並不斷將 next
移動至 head
後方。
q_reverseK
參考 koty6069 的做法,以每 k 個節點為一組執行 q_reverse
。
q_sort
分為 q_sort
及 list_merge
。
q_sort
list_cut_position
將佇列對半切。list_merge
。list_merge
merged
(用來存放排序過的節點)。merged
尾端。你如何確認目前的測試程式已涵蓋排序演算法的最差狀況?
q_ascend
由尾端向 head
走訪,並比較當前與前一個節點的 value
:
prev
大於 current
,就刪除 prev
。current
指向 prev
。q_descend
想法與 q_ascend
相同,但將條件改為:若 prev
小於 current
,就刪除 prev
。
由下圖可發現,若由尾端向左邊走訪,只需紀錄最大值,並將小於當前最大值的節點移除即可。
q_merge
目前作法是將所有佇列接起來,再執行 q_sort
。
改進你的漢語表達。
執行 make valgrind
以及開啟 Address Sanitizer
後,都沒有偵測到記憶體錯誤。
make
時產生 erordirectory 的翻譯是「目錄」,而非「資料夾」(folder)
好的,已修正。
我在寫完 shuffle 函式後,做了以下幾個步驟:
scripts
make
。接著就出現數行錯誤訊息,以下節錄其中兩行做紀錄
這與 Address Sanitizer 有關,查閱 GCC 手冊。
好,謝謝老師提醒。
就我的觀察,所有的 .c
檔均有產生此錯誤,內容格式為
嘗試解決:
首先,刪除測試的 Python 檔案和 shuffle 函式,確保在 Visual Studio Code 的版本控制中,沒有任何更改過的項目(版本與成功執行 make valgrind 時一致)。但仍有相同的錯誤訊息。
在老師提醒這與 Address Sanitizer 有關後,我嘗試執行 make clean
及 make SANITIZER=0
來關閉它,隨後便可順利執行 make test
。
函式按照 Fisher–Yates shuffle 演算法來實作,以下為測試 [1, 2, 3, 4] 做 shuffle 1,000,000 次的直方圖。
Dudect 使用 leakage detection tests 在目標平台上進行統計分析,以決定該程式是否能在常數時間內完成,此方法解決了相關研究中,需要對硬體進行建模的困難。
我的疑惑是,為什麼兩種輸入資料的執行時間分佈相同時,就代表此演算法可以在常數時間內完成?
在查閱了 leakage detection 的論文後得知,在兩種輸入資料下,如果演算法的執行時間分佈在統計上沒有顯著差異,則代表演算法的性能不受輸入資料分佈的影響,即時間複雜度為常數時間。
由 trace-17-complexity.cmd 可得知,在測試 it, ih, rh 及 rt 是否為常數時間時,會開啟 simulation 模式,讓 qtest.c
的 queue_insert() 與 queue_remove() 函式可以使用 dudect
目錄中的 test_const() 進行測試。
test_const()
會依照預先設定的測試次數,持續呼叫 doit()
來獲得測試結果,此函式可分為三個部分,分別對應到 dudect
中的 dudect_init()
, dudect_main()
及dudect_free()
。
在 dudect_main()
裡,會捨棄部份的第一批測量結果,根據論文所述,大於閾值 p 的測量值會被捨棄,目的是要讓結果與測量值的分佈盡可能的相符,我目前還不是很理解此意思。
若不是第一次測試,會呼叫 update_statistics()
,可以發現在 dudect
中的函式會捨棄前 10 次的結果,而 lab0-c
則是沒有捨棄。
因此,我們要改進的部份如下:
做完上述的改進後(commit cb0eb09),make test
的 trace-17-complexity
就可以順利通過了。