# 2023q1 Homework3 (fibdrv) contributed by < `SPFishcool` > ## 開發環境 ```shell $ neofetch --stdout fico@fico-mac ------------- OS: Arch Linux ARM aarch64 Host: Apple MacBook Air (13-inch, M2, 2022) Kernel: 6.1.0-asahi-2-2-ARCH Uptime: 12 mins Packages: 1207 (pacman) Shell: zsh 5.9 Resolution: 2560x1600 DE: Plasma 5.27.2 WM: KWin Theme: [Plasma], Breeze [GTK2/3] Icons: [Plasma], breeze [GTK2/3] Terminal: konsole CPU: (8) @ 2.424GHz Memory: 3746MiB / 15650MiB $ gcc -v Using built-in specs. COLLECT_GCC=gcc COLLECT_LTO_WRAPPER=/usr/lib/gcc/aarch64-unknown-linux-gnu/12.1.0/lto-wrapper Target: aarch64-unknown-linux-gnu Configured with: /build/gcc/src/gcc/configure --enable-languages=c,c++,fortran,go,lto,objc,obj-c++ --enable-bootstrap --prefix=/usr --libdir=/usr/lib --libexecdir=/usr/lib --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=https://github.com/archlinuxarm/PKGBUILDs/issues --with-linker-hash-style=gnu --with-system-zlib --enable-__cxa_atexit --enable-checking=release --enable-clocale=gnu --enable-default-pie --enable-default-ssp --enable-gnu-indirect-function --enable-gnu-unique-object --enable-linker-build-id --enable-lto --enable-plugin --enable-shared --enable-threads=posix --disable-libssp --disable-libstdcxx-pch --disable-multilib --disable-werror --host=aarch64-unknown-linux-gnu --build=aarch64-unknown-linux-gnu --with-arch=armv8-a --enable-fix-cortex-a53-835769 --enable-fix-cortex-a53-843419 Thread model: posix Supported LTO compression algorithms: zlib zstd gcc version 12.1.0 (GCC) ``` ## 改善 big number fibonacci ### 初步嘗試 初步嘗試使用 `list_head` 改善大數問題,參考 [fibdrv:加速 Fibonacci 運算](https://hackmd.io/@sysprog/linux2023-fibdrv/%2F%40sysprog%2Flinux2023-fibdrv-d)裡的 `list_head` 結構,首先我建立 `NEW_NODE`、`FULL_ADD64`、 `bn_add_smaller` 、`bn_to_string` 等函式和 `bn_node` 的 entry。 ```c static long long fib_sequence_bn(long long k, char *buf){ struct list_head *h1 = kmalloc(sizeof(*h1), GFP_KERNEL), *h2 = kmalloc(sizeof(*h2), GFP_KERNEL); if (!h1 || !h2) return 0; INIT_LIST_HEAD(h1); INIT_LIST_HEAD(h2); NEW_NODE(h1, 1); NEW_NODE(h2, 0); ``` 一開始預設 `h1` 為大數 `h2` 為小數,每次加完的數值就會存回 `h2`,因此在每次加完數後將 `h1` 、 `h2` 進行 swap ```c for (int i = 2;i <= k;i++){ bn_add_smaller(h1, h2); swap(h1, h2); } ``` 在 `bn_add_smaller` 裡會進行 `FULL_ADD64`,`FULL_ADD64` 會將兩數進行加法,`overflow` 內存入進位數,若有進位則為 `1`,否則為 `0`。 ```c #define FULL_ADD64(a, b, carry) \ ({ \ uint64_t res = (a) + (b) + (carry); \ uint64_t overflow = -!!(res >= BOUND64); \ (b) = res - (BOUND64 & overflow); \ overflow; \ }) ``` 如果回傳發現有 overflow ,表示這個節點數值超過了,就會新增新的節點存取接下來的數值。 最後再將這些節點的數值一一存成字串,最後將其 reverse (如果從最低位數開始存的話)。 ```c while (*cur != bn){ uint64_t val = list_entry(*cur, bn_node, link)->value; while(val > 0){ *p = (val % 10) + '0'; val /= 10; p++; } cur = &(*cur)->next; } *p = '\0'; // '\0' is end of String. bn_strnrev(str, len); ``` 經過 lab0 的經驗,若字串處理最後沒有結束字元('\0'),在使用字串相關函式或 `printf` 有可能會發生 Segmentation fault! 在完成函式後嘗試將字串能夠讓 [./client.c](https://github.com/SPFishcool/fibdrv/blob/master/client.c) 輸出,一開始想讓函式回傳 `char *` ```c static char *fib_sequence_bn(long long k) ``` 後來發現這個 `fibdrv.c` 裡面的 `read` function 是輸出 `ssize`,也就是一個數值,並不能這樣改,後來發現 `copy_to_user` 這個函式可以將字串貼到我們 [./client.c](https://github.com/SPFishcool/fibdrv/blob/master/client.c) 所設定的 buffer 上,因此函式可以輸出字串長度以便後續將我們存入的字串取出。 ```c if (k == 0) { __copy_to_user(buf, "0", 2); return 1; } __copy_to_user(buf, str, len + 1); return len; ``` 目前進度:能夠計算 $f(92)$ 以上 ### Binary Big Number By `list_head` 因為實作 Faster Doubling 的特性,十進位用運算會用到大量乘法,不妨嘗試實作使用二進制表示的 `list_head` Big Number。 首先,進制改變後程式修改最明顯的就是 `bn_to_string` ,原本是每個位數一一取出再將其轉為字串放入,但是二進制轉為十進制字串不適合這麼做,因為每考慮到一個位數整個數字都有可能會變動到,參考 [fibdrv:加速 Fibonacci 運算](https://hackmd.io/@sysprog/linux2023-fibdrv/%2F%40sysprog%2Flinux2023-fibdrv-d)中的 `bn_to_string`,這裡將從 linked list 的 tail 的最高位元開始拜訪,每拜訪一位就會將字串裡的數字乘二,相當於整數右移一位。 ```c for (struct list_head *cur = bn->prev;cur != bn;cur = cur->prev) { uint32_t val = list_entry(cur, bn_node, link)->value; for (uint32_t bit = 1UL << 31;bit;bit >>= 1) { int carry = !!(val & bit); for (int i = len - 2;i >= 0;i--) { dec_str[i] += dec_str[i] - '0' + carry; carry = (dec_str[i] > '9'); if (carry) dec_str[i] -= 10; } } } ``` 正在努力開發中... ## Faster Doubling ### 初步嘗試 在實作 Faster Doubling 會運用到大量乘法,若使用十進制進行運算並不是一個明智之舉,但若使用二進位進行運算,可以將乘法用位移和加法代替,再將 `bn_to_String` 功能寫成 binary to decimal String,預估此舉能夠大幅提升效能。 正在努力開發中...