contributed by < linjohnss
>
滿足 $ make test
自動評分系統的所有項目
也可以用 $ ./qtest -f traces/trace-XX-CAT.cmd
來針對單一項目測試
q_new
: 建立新的「空」佇列q_free
: 釋放佇列所佔用的記憶體q_insert_head
: 在佇列開頭 (head) 插入 (insert) 給定的新節點 (以 LIFO 準則)q_insert_tail
: 在佇列尾端 (tail) 插入 (insert) 給定的新節點 (以 FIFO 準則)q_remove_head
: 在佇列開頭 (head) 移去 (remove) 給定的節點q_release_element
: 釋放特定節點的記憶體空間q_size
: 計算目前佇列的節點總量q_delete_mid
: 移走佇列中間的節點q_delete_dup
: 在已經排序的狀況,移走佇列中具備重複內容的節點q_swap
: 交換佇列中鄰近的節點q_reverse
: 以反向順序重新排列鏈結串列,該函式不該配置或釋放任何鏈結串列節點,換言之,它只能重排已經存在的節點q_sort
: 以遞增順序來排序鏈結串列的節點允許藉由 Fisher–Yates shuffle 演算法,對佇列中所有節點進行洗牌 (shuffle) 操作
提供 web 伺服器功能,注意: web 伺服器運作過程中,qtest 仍可接受其他命令
研讀 Linux 核心原始程式碼的 lib/list_sort.c 並嘗試引入到 lab0-c 專案,比較你自己實作的 merge sort 和 Linux 核心程式碼之間效能落差
運用 Valgrind 排除 qtest 實作的記憶體錯誤,並透過 Massif 視覺化 “simulation” 過程中的記憶體使用量,需要設計對應的實驗
db70a3
根據作業說明進行 queue 長度計算的實作。
0a8131
利用 list.h
裡的函式 INIT_LIST_HEAD
來初始化 head
。
當無法分配空間時 molloc
會回傳 NULL
,因此需要在 molloc
後檢查 head
是否為 NULL
。
利用 list.h
裡的函式 list_for_each_entry_safe
來走訪 list 中的 element
,並釋放其佔用的記憶體。
9cd1fa
原先為用 free
實做得的部份,可以改用 q_release_element
來代替,進而提昇程式碼精簡度。
0a8131
由於 strlen
不會算到結束字元\0
,因此要+1
用來放結束字元。
node->value
的空間時,除了回傳 false
外,還要釋放 node
的空間。
0a8131
同 q_insert_head
改用 list_add_tail
加入 list
0cf3af
利用 list_for_each_safe
走訪 list 中的 node
,並將該 node
的 prev
以及 next
交換。
走訪完畢後,需要將 head->next
與 head->prev
交換。
2aa8d7
參考 Kevin-Shih 的開發紀錄 提到使用 list_for_each_safe
時,可以利用 safe
紀錄的下一個節點替代 tmp
,因此根據此特性作修改。
e60602
先透過 list_first_entry
找到第一個 element
,接著利用 list_del_init
移除。
若 sp
不為 NULL
則將 element
的 value
複製到 sp
(須判斷 vlaue
與 bufsize
的大小)。
3edcaf
把比較值 bufsize
改為 bufsize -1
,因為要留一個字元存取 Null-terminated
。
e60602
同 q_remove_head
,改用 list_last_entry
找到最後一個 element
。
3edcaf
把比較值 bufsize
改為 bufsize -1
,因為要留一個字元存取 Null-terminated
。
3edcaf
利用兩個指標 rear
、front
指向 list 的頭尾,兩個指標反向移動,當指標發生交會時,及找到 list 的中間值。
eeca3c
根據 leetcode 解釋,是將 queue
分兩兩一組,並進行交換。
head
不存在、空的或是只有一個 node
,則什麼都不用作。left
、right
分別指向開頭相鄰的左右兩個 node
。node
用 list_move
交換。此時,原本在左邊的 node
就會移到右邊。left = left->next
、right = right->next
。left == head || right == head
。1、2、3、4
。left
、right
指向前兩個相鄰的 node
。node
用 list_move
交換。因此,left
會成為右側的 node
。left = left->next, right = right->next
,並重複這兩個動作,直到沒辦法相鄰兩兩一組為止。eeca3c
利用 Merge Sort 對 Queue 進行排序,因為 Merge Sort 為 O(nlogn),可以通過 trace-14
與 trace-15
。
d38186
利用 list_for_each_entry_safe
走訪整個 Queue,當 entry->value
與 safe->value
(下一個 node
的值) 相同時,刪除 entry->value
。
node
直到剩下單獨一個 node
,並不符合題意,須要刪除所有重複的 node
。
為了刪除留下的一個 element
,先宣告一個變數 left
,用來判斷是否為留下來的重複 element
(當重複發生時,令 left
為 true
。如此一來,若與下一個 safe->value
不相同,但是left
為 true
則代表為留下來的element),並將其刪除。
4532cd
閱讀 Fisher–Yates shuffle 演算法,在queue.c
加入函式q_shuffle
:
4532cd
在qtest.c
先宣告q_shuffle
函式其定義在queue.c
中。
接著在 console_init()
加入一行
並加入 do_shuffle
tiny.c
至 lab0-c將 tiny.c
加入 lab0-c,並修改 Makefile
來編譯它。在 Makefile
的 OBJS
加入 tiny.o
即可。
tiny.h
至 lab0-c宣告兩個全域變數 listenfd
與 noise
,提供 console.c
讀取。
改寫自 tiny.c
的 main
,只需保留啟動 server
與忽略 SIGPIPE
訊號的部份。並且將 socket 改為 non-blocking,防止程式停止接收使用者輸入。
參照 lab0-c 作業提示改寫。原先給的程式碼無法通過 pre-commit。
TODO:handle_request(fd, req.filename),負責處理 reply message。
根據 lab0-c 作業提示,cmd_select
可以滿足同時處理命令列輸入與網頁伺服器。因此我們根據提示下去改。
這次嘗試在 console.c
中加入 command。先實做 do_web
函式。
接著在 init_cmd()
中加入一行。
0399d2
lib/list_sort.c
改寫成 linux_sort.h
,並在 queue.c
includestring_cmp
與 q_linux_sort
0399d2
在 qtest.c
裡加入 do_LinuxSort
接著在 console_init()
加入一行
撰寫一個用於比較 merge sort 與 linux 的 list_sort 效能落差的 .cmd
檔案
從上述成果,可以看出 Linux 的 list_sort 相較我的 merge sort 快了一倍。
首先,執行 qtest
並開啟 Valgrind
可以看到報告不斷顯示 blocks are still reachable
,代表在 linenoise.c
的 linenoiseHistoryAdd
有記憶體未被釋放。
根據 Valgrind 報告,找到 linenoise.c
的這行出現問題。在 qtest.c
執行 linenoiseHistoryLoad
會使用到。
根據作業說明,
still reachable
代表程式結束時有未釋放的記憶體,不過卻還有指標指著,通常會發生在 global 變數。
strdup
會進行 malloc
,而在 linenoise.c
中複製後的字串會被放入陣列 history
。而這個 history
會在
從 linenoise.c
中可以發現有一個函式 freeHistory
會釋放 history
的記憶體。
接著,我們從 console.c
中的 run_console
找到當 has_infile = true
時,並不會對 history
有任何改動(包含釋放記憶體空間)。
has_infile = true
代表為 command 為從檔案輸入的。
然後我們可以在 qtest.c
中發現,無論 command 是否為從檔案輸入它都會將 command history 載入(linenoiseHistoryLoad
),進而導致記憶體空間沒有被釋放。
針對上述觀察,我們可以改由讀取鍵盤指令的方式判斷是否有記憶體錯誤發生。發現確實沒有發生錯誤,驗證了我們的觀察。
因此,我們可以藉由判斷 command 是否為從檔案(infile_name
)輸入來判斷要不要使用 command history。重新執行 make valgrind
後就沒有回報記憶體錯誤了。
Student’s t-distribution,簡稱 t 分佈,改善 z 檢定在小樣本誤差大的問題。