contributed by < linhoward0522
>
不用複製作業要求內容,善用超連結。
q_new
INIT_LIST_HEAD
來初始化一個空的 list_head
q_free
list_entry
找出對應的 element 並且釋放其內部所指的字串以及自身的空間queue.h
中裡面 q_release_element
可以用來釋放記憶體list_for_each_entry_safe
會記錄下一個位置,並可以安全刪除當前節點,進一步精簡程式碼q_insert_head
list.h
,其中的 list_add
將新的 element_t->list
加入原有的 head 裡。strlen
並不含 '\0'
,所以在配置時需要將記憶體空間多加一。q_insert_tail
q_insert_head
,使用 list_add_tail
來實作q_remove_head
list.h
裡的 list_first_entry
,可以將第一個 element_t 的位址取出list_del_init
確保在移除 entry 後前後節點會互相連結sp
,並且複製字串到 sp
時要加上 null terminator
的空間q_remove_tail
q_remove_head
,使用 list_last_entry
將最後一個 element_t
的位址取出q_size
list_for_each
走訪每個節點並計算長度。q_delete_mid
list_del_init
確保在移除 entry 後前後節點會互相連結list_entry
找出對應的 element 並使用 q_release_element
釋放記憶體空間。q_delete_dup
list_for_each_entry_safe
進行迭代,能得到當前的以及下一個 element_t
的位址strcmp
比對字串是否相同flag
用來確認如果字串相同,則在下一個迴圈就會刪除另一個重複的元素q_swap
list_swap
要來做使用,但在 list.h
並沒有看到相關實作,後來改用 list_move
來實作list_move
,所以兩個指標也互換,所以迭代到下一次時就相當於是 current->next->next ,即完成兩兩交換q_reverse
list.h
裡的 list_for_each_safe
進行迭代prev
和 next
來紀錄前後位置,然後反轉節點list.h
裡的 list_move
,可以將節點移至串列起始點,即完成反轉q_reverseK
q_size
紀錄串列長度,用來確保最後剩下不足 k 個節點不會做反向順序排列current
紀錄 pos->next
的位址list_move
後,相對地 pos
會向後移一格*current
就會指向下一個要做反向順序排列的節點tmp
用來紀錄要將節點移動到的地方q_sort
merge sort
的實作merge_list
bit-wsie
方法來加速運算merge_sort
merge_list
將第一個節點開頭的串列及中間節點開頭的串列,合併成一個有序的串列。slow->next = NULL;
是必須要將第一個節點開頭的串列尾巴指向NULL
q_sort
merge_sort
前要先將 head
斷開,使其變成 singly-linked list
來避免產生無窮迴圈singly-linked list
,所以要將 prev
指標更新,也需將串列尾巴與串列開頭相互連結,讓串列變回 circular doubly-linked list
,以維持 struct list_head
的型態q_descend
q_merge
queue.h
可以了解 queue_contex_t
的結構
q
用來指向 queue 的 headchain
用來將每一個 queue_contex_t
結構串連起來size
表示這個 queue 的長度id
表示每一個 queue 唯一的編號qtest.c
發現有宣告 queue_chain_t
的結構,並從do_new
函式可以發現
queue_contex_t
結構的 headqueue_contex_t
結構,都會將此結構插入到串列的尾端qtest.c
的 do_merge
函式可以發現它傳入的參數是 queue_chain_t
結構的 headqtest.c
裡面有宣告 q_chain_t
的結構,所以邊界條件不用判斷 !head
list_empty(head)
與 list_is_singular(head)
為邊界條件即可q_sort
差不多,執行 merge_list
前要先將 head
斷開,使其變成 singly-linked list
來避免產生無窮迴圈circular doubly-linked list
INIT_LIST_HEAD(pos->q)
才不會造成 Segmentation fault
目前 trace-17-complexity 還是無法通過
lib/list_sort.c
lab0-c
專案qtest
命令直譯器的實作list_sort.c
程式碼複製到 qtest.c
__attribute__((nonnull(2,3,4)))
關鍵字
list_sort.c
有使用到 likely
這個巨集,所以需要增添到 qtest.c
,而他們被定義在 /include/linux/compiler.h 中
__built_expect()
是 gcc 的內建 function,用來將 branch 的相關資訊提供給 compiler ,告訴 compiler 設計者期望的比較結果,以便對程式碼改變分支順序來進行優化。likely
, unlikely
兩個巨集,可以讓 compiler 在編譯 assembly code 的時候做一些最佳化,可以告訴 compiler 某段 if
敘述為 true 的機率較高或低,讓 compiler 把對應程式碼接在判斷的後面list_sort.h
中將 list_cmp_func_t
的定義加入到 qtest.c
Function Pointer
,並且因為 __attribute__((nonnull(2,3)))
所以第二以及第三個參數不能為 null
list_sort.c
的註解來實作 comparison function
list_sort
是 stable sort
,所以沒必要區分 a < b 和 a == b 的情況do_sort
函式,實作 do_linux_sort
qtest.c
的 console_init
中加入新命令 :error: unknown type name ‘u8’
count
變數,型態為 u8
,被定義在 /tools/include/linux/types 裡#include <linux/types.h>
才出錯,但加上後仍然出現錯誤訊息#include <linux/types.h>
改成 #include <stdint.h>
,並且將型態 u8
改為 uint8_t
才不會出現錯誤訊息
目前還不知道確切原因
merge sort
和 Linux
核心程式碼之間效能落差perf Examples
來做安裝與撰寫shell script
分別用來執行 linux_sort
與 sort
的效能測試,並使用 perf report
將輸出存起來
cache-misses
, branches
, instructions
, context-switches
lab0-c/traces
新增兩個目錄,分別存放用來測試 linux_sort
與 sort
的命令檔
RAND_*.cmd
的內容是參考 trace-0*-ops.cmd
來改寫,表示要 sort *
個隨機字串
.sh
檔案.sh
檔案 顯示 Permission denied
chmod u+x *.sh
perf report
內容sort
# node | cache-misses | branches | instructions | context-switches | time |
---|---|---|---|---|---|
1000 | 4443 | 78,9179 | 514,5106 | 0 | 0.0009679 |
10000 | 2960 | 621,6845 | 4248,6763 | 0 | 0.0054019 |
100000 | 79,2148 | 6354,8361 | 4,2894,2226 | 0 | 0.063659 |
1000000 | 4692,1584 | 6,6668,8777 | 44,2436,0379 | 152 | 1.03455 |
list_sort
# node | cache-misses | branches | instructions | context-switches | time |
---|---|---|---|---|---|
1000 | 1289 | 78,1958 | 516,3000 | 0 | 0.0008445 |
10000 | 3118 | 615,8586 | 4285,4486 | 0 | 0.0058063 |
100000 | 37,9827 | 6297,2125 | 4,3374,6650 | 0 | 0.061114 |
1000000 | 3669,3394 | 6,6033,1233 | 44,7728,5288 | 2 | 0.96378 |
由實驗結果可以看出上面測試項目基本上 list_sort
都比我自己實作的 sort
還要優秀,尤其在節點數 1000000 時, cache-misses
, context-switches
數量相差非常大
qtest
提供新的命令 shuffle
swap
函式,用來將節點內的數值做交換
tail
指標紀錄目前串列的最後位置cur
指標用來紀錄隨機挑出節點的位置cur
指標所紀錄的位置來做交換跟 tail
指標所紀錄的位置來做交換tail = tail->prev
會紀錄下一次要交換節點的位置qtest.c
中各個 do_*
函式,加入函式 do_shuffle
q_shuffle
之前檢查佇列並發出警告訊息,接著再執行 q_shuffle
:qtest.c
的 console_init
中加入新命令:shuffle
scripts/shuffle_test.py
#!/bin/python
python3 ./scripts/shuffle_test.py
排列組合 | 觀察到的頻率 | 期待的頻率 | |
---|---|---|---|
[1, 2, 3, 4] | 41,566 | 41,666 | 0.240003840061441 |
[1, 2, 4, 3] | 41,589 | 41,666 | 0.14229827677242837 |
[1, 3, 2, 4] | 41,212 | 41,666 | 4.9468631498103965 |
[1, 3, 4, 2] | 41,533 | 41,666 | 0.424542792684683 |
[1, 4, 2, 3] | 41,389 | 41,666 | 1.8415254644074306 |
[1, 4, 3, 2] | 41,778 | 41,666 | 0.3010608169730716 |
[2, 1, 3, 4] | 41,672 | 41,666 | 0.0008640138242211876 |
[2, 1, 4, 3] | 41,579 | 41,666 | 0.1816589065425047 |
[2, 3, 1, 4] | 41,690 | 41,666 | 0.013824221187539001 |
[2, 3, 4, 1] | 41,989 | 41,666 | 2.5039360629770075 |
[2, 4, 1, 3] | 41,960 | 41,666 | 2.0744971919550714 |
[2, 4, 3, 1] | 41,701 | 41,666 | 0.02940047040752652 |
[3, 1, 2, 4] | 41,553 | 41,666 | 0.306460903374454 |
[3, 1, 4, 2] | 41,758 | 41,666 | 0.1858589737435799 |
[3, 2, 1, 4] | 41,508 | 41,666 | 0.5991455863293813 |
[3, 2, 4, 1] | 41,561 | 41,666 | 0.26460423366773866 |
[3, 4, 1, 2] | 41,825 | 41,666 | 0.6067537080593289 |
[3, 4, 2, 1] | 41,798 | 41,666 | 0.41818269092305477 |
[4, 1, 2, 3] | 41,783 | 41,666 | 0.3285412566601066 |
[4, 1, 3, 2] | 41,567 | 41,666 | 0.2352277636442183 |
[4, 2, 1, 3] | 41,574 | 41,666 | 0.20313925022800364 |
[4, 2, 3, 1] | 41,862 | 41,666 | 0.9219987519800317 |
[4, 3, 1, 2] | 41,623 | 41,666 | 0.04437671002736044 |
[4, 3, 2, 1] | 42,110 | 41,666 | 4.731339701435223 |
Total | 21.546104737675805 |
= 21.546104737675805
dudcet
,用來量測程式能否在常數時間執行完成TIMING LEAKAGE DETECTION
Measure execution time
fix-vs-random test
dudct/cpucycles.h
`可找到相關程式碼Apply post-processing
positive skew
,可能會因為 OS 或外部程式造成測量誤差,透過裁剪超過 threshold 的測量結果Apply statistical test
Welch’s t-test
Address Sanitizer
,修正 qtest
執行過程中的錯誤Valgrind
排除 qtest
實作的記憶體錯誤make valgrind
q_free
, do_free
都沒有問題qtest.c
中的 q_quit
函式,第一行就是 return ture
,會導致下面的程式無法正常執行,以至於沒有正常釋放記憶體return ture
拿掉後就沒有出現錯誤訊息了simulation
it
simulation
ih
simulation
rt
simulation
rh
上述四個的共通點都是記憶體沒有被完全釋放
GitHub Action 目前都無法正常運作,還沒有找到原因