--- title: 2023q1 Homework3 (quiz3) tags: Linux核心實作 --- # 2023q1 Homework3 ([quiz3](https://hackmd.io/@sysprog/linux2023-quiz3)) contributed by < [`lorian0738`](https://github.com/lorian0738) > ## 測驗 1 ## 測驗 2 ## 測驗 3 > Linear feedback shift register (LFSR) 是指給定前一狀態,將該輸出的線性函數作為輸入的移位暫存器,其應用包括產生 PRNG。考慮一個運用 LFSR 來產生隨機數,並使其均勻分佈於 64 位元無號整數的有效空間 (distribution of uniformly arbitrarily large uint64_t)。 > 程式碼可參見 bucket_uniform.c (部分程式碼遮蔽): > * log2_64 : 計算以 2 為底的 x 的對數 (logarithm of x to the base b),且下取整函數 (floor) > * bucket_number : 在指定區間內,使產生的 LFSR 數值得以均勻分佈 ### 1. 解釋 [Linear feedback shift register](https://en.wikipedia.org/wiki/Linear-feedback_shift_register) (LFSR) 的運作原理,搭配在 [Linux 核心原始程式碼](https://github.com/torvalds/linux)中,用 git log 和 grep 找出 LFSR 的應用案例 LFSR 通常右移一串序列將最低位 (最左邊的位元) 做為輸出,且將輸出作為其中一個輸入,與挑選的其他 bits 做 XOR 等動作,得到的值作為那串 bits 的最高位元 (feed back),重複以上動作,選得恰當的話可以做偽隨機數生成器 ### 2. 解釋[上述程式碼](https://gist.github.com/jserv/15c6ef4383d5d010326cdc4382ffdd1d)運作的原理 ```c int main() { int num_of_buckets = 120; /* an example of some non-power of 2 */ int num_of_iterations = (1 << 20); /* roughly 1 million */ set_N_BUCKETS(num_of_buckets); set_N_BITS(); unsigned int *buckets = malloc(N_BUCKETS * sizeof(unsigned int)); int i = 0; while (i < N_BUCKETS) { *(buckets + i) = 0; i++; } fill_buckets(buckets, num_of_iterations); evaluate_buckets(buckets); free(buckets); return 0; } ``` `set_N_BUCKETS` 將 N_BUCKETS 設為 num_of_buckets `set_N_BITS` 將 N_BITS 設為 N_BUCKETS 取以 2 為底的對數並下取整函數,其中用 `log2_64` 這個函式來實作 ```c static const char log_table_256[256] = { #define _(n) n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, _(4), _(5), _(5), _(6), _(6), _(6), _(6), _(7), _(7), _(7), _(7), _(7), _(7), _(7), _(7), #undef _ }; #undef _ /* ASSUME x >= 1 * returns smallest integer b such that 2^b = 1 << b is >= x */ uint64_t log2_64(uint64_t v) { unsigned r; uint64_t t, tt, ttt; ttt = v >> 32; if (ttt) { tt = ttt >> 16; if (tt) { t = tt >> 8; if (t) { r = 56 + log_table_256[t]; } else { r = 48 + log_table_256[tt]; } } else { t = ttt >> 8; if (t) { r = 40 + log_table_256[t]; } else { r = 32 + log_table_256[ttt]; } } } else { tt = v >> 16; if (tt) { t = tt >> 8; if (t) { r = 24 + log_table_256[t]; } else { r = 16 + log_table_256[tt]; } } else { t = v >> 8; if (t) { r = 8 + log_table_256[t]; } else { r = 0 + log_table_256[v]; } } } return r; } ``` 這個部份目的是對 N_BUCKETS 取以 2 為底的對數並下取整函數,首先將輸入值右移 32 位元,若是右移後非 0,表示這個數字大於等於 $2^{32}$,再繼續右移 16 位元,若還是非 0 則表示這個數字大於等於 $2^{48}$,再右移 8 個位元,若還是非 0 則表示這個數字大於等於 $2^{56}$,這時可回傳 56 加上剩下的值用 log_table_256 找到的值。 其他以此類推,總之就是先找到 8 個 bits 一起看時,該值最大大於等於 2 的第幾個 8 次方,例如大於 $2^{56}$、$2^{48}$、$2^{40}$、$2^{32}$、$2^{24}$...,而 $2^{8}$ 就是 256,因此再從預定義好的 log_table_256 找出剩餘要加上的值 ### 3. 在 Linux 核心原始程式碼中找到 $log_{2}({x})$ 的實作 (整數),要涵蓋不同的整數型態寬度,以及是否能運用微處理器提供的指令來加速。也從 Linux 核心找出整數 $log_{2}({x})$ 的應用案例並解說。 ### 4. lab0-c 提供類似的實作 [log2_lshift16.h](https://github.com/sysprog21/lab0-c/blob/master/log2_lshift16.h),解釋其原理並嘗試改進其效能 ## 測驗 4