其實這裡都是我誤解了 n-th set bit,他與陣列位置的概念一樣。第 0 個位置在現實生活中其實是第一個。因此第 0-th set bit 是指 first set bit。不過都花了 2 天在寫和找問題,刪掉也可惜,因此把這裡當作警惕和紀錄。
3
不過當時認為 find_nth_bit
不可能出錯,因此一直花時間在檢查測試函式是否有問題,最後先放棄,做改進後比對的測試,大致上就是將改進前與改進後的程式碼取不同名稱並輸入相同測試數據比對輸出結果,而突然想到我的改寫原先應會出錯,卻不管怎麼修改測試數據皆與 find_nth_bit
輸出結果相同,因此開始尋找問題,並發現 linux/include/linux/bitops.h 內的函式 fns
計算方法有誤,如下:
fns
函式錯誤函式定義:
find N'th set bit in a word ,即在一 word 長度中的記憶體尋找第 n 個 set bits
函式作法:
__ffs
尋找低位開始第一個 set bit 之位置那麼假設傳入函式參數為 word = 10000000110010111, n = 4
那麼流程將為
MRE (Minimal reproducible example)
因為 n--
尚不等於 0 ,因此會去尋找第二個 set bit。
因此應改成 --n
的動作,如此可得正確位置
修改 linux/include/linux/bitops.h 內的 fns
函式:
更改後再做測試,測試筆數: 10000 次,每一次皆尋找第 200000、300000 及第 400000個 set bit
FIND_NTH_BIT
函式錯誤可以看到仍有錯誤,不過我認為是其他函式出錯了,因為我檢查輸出結果與事實只要是錯誤的皆 >=64
,但 fns
只負責一個 64 bits 的範圍,而 FIND_NTH_BIT
內寫到
假設 nr
剛好為 64
,即代表距離還需要尋找 64
個 set bits ,而 hweight_long(tmp)
剛好也回傳 64
,那麼不會進入判斷式 if (w > nr)
,這說明了 fns
不可能會處理到 nr
為 >=64
的情況,因此不可能會差到 >=64
,所以並非函式 fns
的問題。
那麼如果 w == nr
卻不進入判斷式 if (w > nr)
會怎樣呢 ?
與上述同樣情況,那麼 nr
等於 0
,會再找一段 word 去加長長度,數值說明:
那麼為什麼誤差會 >= 64
呢?
因為原先目標位置 n 在上一個 idx 的 word 內,而現在被以 64 計算,因此多計算了 leadind zero 的數量 (因為加上此 word 的 set bits 要剛好等於 nr
)
因此最後誤差為 128 - n
,其中 n 為前一個 word 的最後一個 set bit
MRE (Minimal reproducible example)
只要首個 word = 1, n(set bit) = 1 ,即可重現
修改 linux/lib/find_bit.c 內的 FIND_NTH_BIT
函式:
4
所浪費的時間KSM is a memory-saving de-duplication feature
目的就是節省記憶體使用
KSM 起初與 KVM (Kernel-based Virtual Machine) 一同開發 (也被稱為 Kernel Shared Memory),透過共享含有相同資料的記憶體,將更多虛擬機器放入實體記憶體內。
而方法為週期性的掃描使用者記憶體有註冊 (有向 MMU (記憶體管理單元(Memory management unit)) 中註冊相關 page 對應的實體位址) 之位置,並尋找 pages 中可被單一寫入保護的 page 取代的完全相同的內容 (若後續想要更新該內容,則會自動複製一份) ,而 KSM 常駐程式每一次掃描的 pages 數量及掃描的間隔時間由 sysfs interface
設置。
KSM 僅合併匿名 (private) pages ,而非 pagecache (file) pages。
KSM 合併的 pages 原本被鎖定於 kernel 記憶體內,但現在可以被置換入硬碟成其他使用者的 pages 以釋放實體記憶體 (不過共享在當他們被置換入記憶體時會被破壞,因為在置換入硬碟時合併的資訊同時會失去,因此 ksmd 需重新探索 pages 是否一致並重新合併)
為了降低過多的掃瞄, KSM 透過一 pointers 指向 pages 之位置的資料結構儲存透過內容排序的 pages 。
因為 pages 內的內容隨時都會改變, KSM 不能僅插入 pages 進入一般排序的樹並期待他能找到所有內容。因此 KSM 使用兩種資料結構 – 穩定及不穩定樹。
穩定樹保有指向所有合併 pages (KSM pages) 的 pointers ,並透過其內容進行排序。由於每一個 page 皆為寫入保護,在此樹尋找是完全可以被保證是有作用的 (除非 pages 為非映射),因此此樹被稱為穩定樹。
穩定樹的節點包含了從 KSM page 反向映射到有定位到此頁面之虛擬位址的資訊。因此給定一個 KSM page,系統可以查詢穩定樹,以找到所有映射到這個頁面的虛擬地址,如下:
為了避免在 KSM 分頁反向映射造成的巨大的延遲, KSM 在穩定樹中維持兩種節點:
於內部,常規節點 "dups" 和 "chains" 代表使用相同 struct ksm_stable_node
的結構。
除了穩定樹, KSM 使用第二個資料結構稱為不穩定樹,此樹保有指向在一段時間未被改變 pages 的 pointers 。不穩定樹透過其 pages 內容進行排序,不過由於其並非為寫入保護, KSM 無法依賴不穩定樹能正常工作,因為不穩定樹容易因內容被修改而被破壞,因此才稱為不穩定。
KSM 利用以下技術解決此問題:
當可調整的 merge_across_nodes
未被設置, KSM 將會維持多個穩定樹及多個不穩定樹,每個 NUMA 節點各一個。
NUMA, Non-Uniform Memory Access ,是一種可以在多處理系統中設定微處理器叢集的方法,因此他們可以在 local 共享記憶體
參考 non-uniform memory access (NUMA)
Trace code:
目的為探究並分析程式碼對於名稱 exponential weighted moving average
的精確度。
避免有額外的計算在函式 ewma 外,因此將相關會影響函式同時列出:
傳入參數為 advisor_ctx.change 及 change ,而從第 574 行可以看到
而 advisor_ctx.change 之初始化我目前只能在第 341 行看到
雖然在 trace 會呼叫到此函式的 code 時會發現 唯一呼叫到此函式的函式為
( 不過在 linux 中就不會再有任何函式呼叫到此函式。)
因此我將 advisor_ctx.change
暫時視為僅與 change
有關。
而與change
有關為
第一部分僅為獲取現在 kernel 時間並與 advisor_ctx.start_scan
相減再轉換為秒,因此不會作額外計算,而 last_scan_time
使用的函式 prev_scan_time
也僅為使用可用的 scan_time
。
因此可看出 change
為 scan_time
之變化量百分比。
這裡他第 393 行的 facor
應該為 factor
,是一個貢獻 Linux 的機會。