contributed by < Paintako
>
使用 malloc 在 heap 中配置 struct list_head 的大小, 如果失敗的話就 return NULL, 否則使用 Linux 核心風格的 list.h
所提供的 INIT_LIST_HEAD
巨集,後者作用是對一個 node 做初始化, 使 next/ prev pointer 皆指向自己
利用 Linux Kernal API 提供的 list_for_each_safe
function 來 iterate the whole list.
實作過程中報錯 ???, 皆與 allocated block
有關
查看 queue.h
才知道配置空間時是以 block 為單位
改進漢語書寫
jservImage Not Showing Possible ReasonsLearn More →
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
實作過程中, 只使用 free
是不夠的, 因為整個 queue 中的 node 有:
queue.h
提供的 q_release_element
來安全的釋放掉 node.q_release_element
函式:依據 list.h
中的描述,佇列內每個節點皆是一個含有以下兩者的 struct:
所以在 malloc 時, 除了上述 struct 的空間需要配置外, 需要額外 malloc 傳入的字串, 需要特別注意的是, 當配置字串的大小時, 需要額外配置 1 byte, 原因是因為需要額外配置一個空間給 EOF
為何是 EOF
?
另外, 第8行以及第15/16行需要特別注意, 如果 malloc 失敗, 要回傳 false 前需要把剛剛配置的空間給釋放掉, 否則會造成 memory leak
.
同insert_head, 但是這次 call 的 api 是 list_add_tail
將某個 node remove 是將它移出 list中, 並非將它回收掉, 此 function 中有限定:
*sp
中.而且此 function 只有給 pointer to head, 所以要透過 list_first_entry
或者 list_entry
找的對應的 element_t, 然後把此 element_t 中的字串複製到 sp
中
Note:
執行 $ make SANITIZER=1
開啟 Address Sanitizer 後, 發現 remove 皆有 heap over flow
的問題, 原因是:
使用之前的 for loop 會導致越界, 試圖存取 heap 之外的的範圍, 改用 strncpy
可以解決問題
補充:
strcpy v.s strncpy
可使用以下工具來 Debug:
跟 q_remove_head
的差別在於, 在找 list_entry
時, 給的位址並非 head
而是 head->prev
, 此動作相當於找 tail.
使用一變數 len
來紀錄 node 個數.
使用兩種 pointer:
這兩種的差別是: fast pointer一次移動兩次, 而 slow 移動一次, 如果 fast 移動到終點, 那 slow 的所在位置即是中點.
實作過程中, 因為 list_mode
可以把兩個節點交換, 所以只需要用兩個指標指向要交換的兩個點, 並且若第一個指標指向 head
or head->next
, 則不做交換.
做的過程中, 首先我的想法是: 宣告一個類似 stack 的結構, 走訪每一的節點的同時, 如果這個點沒有看過, 就把它 push 進去 stack 中, 如果看過就 remove , 但是我誤會題目的意思了
這題的題意是: 如果 list 中有重複的值, 全部刪掉, 例如:
參考 https://hackmd.io/@yanjiew/linux2023q1-lab0#q_delete_dup
的作法
Linux Kernal API
中的 function:
list_cut_position(head_to, head_from, node)
list_splice()
由於有要求複雜度在 nlgn 內, 選用 merget sort.
參考 https://hackmd.io/@yanjiew/linux2023q1-lab0#q_delete_dup
的作法
採用 top down
的 merge sort, 先找到 list 中點, 切成左右兩邊下去做排序.
Intutive 的想法: 把所有 list 接起來, 再 merge.
分析: 沒有利用到 sort 後的優點
錯誤來自 q_remove_head
以及 q_remove_tail
使用 gdb 確認出錯地方, 使用前把 exception_setup
給註解掉, 否則無法進入 q_remove_head
內檢查
進入 q_remove_head
中 for 迴圈後, 不斷 n
直到退出循環為止, 但是停止條件有誤, 故 for 迴圈會不斷執行直到 heap-buffer-overflow 觸發 exception 為止
這裡越界的指標是 char *str_ptr
解法改用 strncpy
, 可防止 buffer-overflow
q_remove_head
以及 q_remove_head
還沒修復前, 執行 valgrind 結果如下
Invalid read of size 1
表示有越界讀取的行為發生
方法: leakage detection test on the execution time.
具體之作法是給程式兩個不同類型的輸入資料(i.e. fix-vs-random 測試),並觀察給定不同的輸入資料,所造成的執行時間分佈在統計上是否相同。
規格書中描述如何量測 Eexecution time
RDTSC ( Read Time-Stamp Counter and Processor ID IA assembly instruction )
基本上, 使用這個指令時,需要先把 preemption
給關掉,以及 interrupts
給關掉,避免因為搶佔 (preemption) 影響量測。以下是範例程式碼:
上面的程式看似合理, 但是有缺陷會影響評測, 例如:
用來寫 inline assembly,C 語言中為了效率等目的直接要求編譯器加入我們所指定組合語言。
外部設備/硬體介面:當變量是外部設備/硬體介面的寄存器時,該變量可能會在未知的時間被更改,因此使用 volatile 關鍵字可以告訴編譯器不要對這些變量進行某些最佳化,例如刪除未使用的變量或進行重複計算等。
多執行緒環境:在多執行緒環境下,多個執行緒可能同時訪問同一個變量,如果不使用 volatile 關鍵字,編譯器可能會對該變量進行某些最佳化,導致在執行緒間共享變量時出現問題。
非預期的控制流:當控制流在編譯器無法預測的方式下更改變量時,使用 volatile 關鍵字可以確保編譯器不會對變量進行某些最佳化。
總之,volatile 關鍵字告訴編譯器該變量是易變的,不能對其進行某些最佳化,以確保變量在某些情況下的可見性和可預測性。
lab0-c
內 dudect
缺陷執行 RDTSC
前,並沒有preemption
給關掉,以及 interrupts
給關掉
改進你的漢語表達
觀察 qtest.c
, 檢查 insert head
, insert_tail
等動作時, 會呼叫 is_##_const
的 function, 這些 function 定義在 fixture.h
頭文件中
C 語言中, ##是一個預處理器運算符, 以下節錄自 C99 規格書
6.10.3.3 The ## operator
Semantics
1 The resulting token is the concatenation of the original two tokens. The resulting token is available for further macro expansion, except in the following cases:
— It is formed by replacing a parameter by a token sequence that does not contain any of the following: ##, #, or a parameter;
— It is the result of a ## operator in a macro definition that was not used in a # operator with a string literal as its operand;
— It is a character constant, a string literal, or a header name (that is, the result of a < or a > operator in a #include directive).
簡而言之,##
的作用是將兩個 token 結合成一個新的 token 。該運算符通常用於擴展巨集(macro)中,以將多個 token 結合成一個新的巨集名稱、變量名稱、函數名稱等等。
以上節錄自Chatgpt
改進上方的書寫,留意 資訊科技詞彙翻譯Image Not Showing Possible ReasonsLearn More →
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
jservImage Not Showing Possible ReasonsLearn More →
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
收到!
fixture.c
中, 存在一個函式 measure
, 該 function 會呼叫 cpucycles
來計算程式執行期間的 cpu cycles 數量
dudect
中, 沒有按照 interl 白皮書中的那樣, 計算 cpu cycle 前關掉 preemption
及 interrupts
.
根據這點, 利用 perf
來做實驗
以下是統計來自 user space
的 instruction count
使用白皮書內的寫法後, cycles 數量不減反增. 且無法 #include <linux/preempt.h>
, 待查
確認 cache 對效能的影響。
以下參考自 KHLee529
論文中有以下論述:
Cropping: Typical timing distributions are positively
skewed towards larger execution times. This may be caused by measurement artifacts, the main process being interrupted by the OS or other extraneous activities. In this case, it may be convenient to crop the measurements (or discard measurements that are larger than a fixed, class-independent threshold).
可以把 outlier ( 離群值 )
刪除
同時檢查 cpu cycles, 發現其實並沒有和前者有太大的差距, 但是通過 constant time 檢查