contributed by < charliechiou
>
1
解釋上述程式碼運作原理
程式碼使用 mpi_t 的結構來儲存大數,藉由組合多個 uint32_t 來完成。 mpi_t 預先分配為 1 個 struct 元素的陣列,在編譯時便可確保 mpi_t 始終會佔據一個 struct 的空間。而使用陣列的形式而非指標,即可不需要再額外分配記憶體。在結構體中,使用 data 來儲存該大數的其中一段,而 capacity 則表示這個大數用到的空間。
其餘使用 mpi_init 初始化,使用 mpi_clear 釋放資料,並使用 mpi_set_u32 及 mpi_set_u64 來設定數值。
由於要保留一位做進位,因此使用 mpi_t 中每個段落為 31 位元。藉由 ceil_div 來計算總共需要多少段落,並將其存入 capacity 中。
計算完 capacity 後使用 mpi_enlarge 將 mpi 擴充到所需的空間,其中 mpi_enlarge 使用 realloc 來重新分配空間,由於每個 data 會需要 32 位元,因此分配 capacity * 4
的大小。
接著將輸入使用位元遮罩 0x7fffffff
切分,取底下 31 位元並存入 data 後位移。
接著再把剩下的空間清 0 避免多餘的空間造成錯誤。
函式用來把 MPI 格式轉換回 uint32 或 uint64,這部份計算 capacity 。以 32 位元為例,由於 32 位元存為 mpi_t 最多只需要兩個 limb 因此這邊僅提取 mpi_t 的最低兩個 limb 其餘則截斷,而 64 位元則僅提取最低三個 limb 。由於有留下最高位當作進位用,因此會移動 31 位元再加入到要儲存的結果中。
這部份我也嘗試去修改讓 capacity 固定,修改 mpi_get_u32 中的 capacity 為 2 可以發現執行結果正確, 可見到 32 位元僅須兩個 limb 的數值便足夠。原先 ceil_dev 的寫法是為了可讀性,能夠更清楚的表示 capacity 的計算方式。
此外,我也嘗試將 capacity 設超過 2 並檢視會發生什麼錯誤,由於每次計算皆會把結果向左 shift 因此無論讀取了多少個 mpi_t 內部的數值都只會剩下最後的兩個 limb。然而,capacity 超過 2 時可能會讀取到錯誤的記憶體空間,但這樣的錯誤卻不會反應在結果上。
透過 valgrind 查看,可以發現 capacity 超過 2 時會顯示錯誤的讀取。
相加或相減需要先確認 capacity,將其設為兩者中較大者,並擴展 rop 的容量。
使用 for 迴圈遍歷每個 limb ,首先先使用各自的 capacity 確認該 limb 有數值
接著把兩個 limb 相加並加上 carry (進位)存入 rop 對應的 limb 中。
最後再把進位設定好並截斷多餘的位元。
最後若還有進位則擴充 capacity 並使用 compact 壓縮。
而其餘 mpi_add_u64
, mpi_add_u32
, mpi_sub_u32
, mpi_mul_u32
也是用類似的方式來完成。
這項實作依賴遞迴呼叫,請避免使用並降低記憶體開銷
改進最大公因數的運算效率
2
解釋上述程式碼運作原理
比較 Linux 核心原本 (與平台無關) 的實作和 memchr_opt,設計實驗來觀察隨著字串長度和特定 pattern 變化的效能影響
研讀 2022 年學生報告,在 Linux 核心原始程式碼找出 x86_64 或 arm64 對應的最佳化實作,跟上述程式碼比較,並嘗試舉出其中的策略和分析
1
在 Linux 核心原始程式碼中找到 CRC32 的應用案例至少 3 處,並探討其原始程式碼
設計實驗來分析 Fast CRC32 提出的手法 (要涵蓋 branchless 和查表的變形),並與硬體的 CRC32 指令效能進行比較。
以 x86-64 或 Arm64 為探討標的,說明 Linux 核心如何使用硬體加速的 CRC32 指令
2
解釋上述程式碼運作原理,搭配「信號與系統」教材
探討定點數的使用和其精確度
改進 MIDI 一閃一閃亮晶晶的音效輸出