# 2023q1 Homework3 (fibdrv) :::spoiler 開發環境 ``` $ gcc --version gcc (Ubuntu 11.3.0-1ubuntu1~22.04) 11.3.0 Copyright (C) 2021 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Architecture: x86_64 CPU op-mode(s): 32-bit, 64-bit Address sizes: 39 bits physical, 48 bits virtual Byte Order: Little Endian CPU(s): 12 On-line CPU(s) list: 0-11 Vendor ID: GenuineIntel Model name: Intel(R) Core(TM) i7-8700 CPU @ 3.20GHz CPU family: 6 Model: 158 Thread(s) per core: 2 Core(s) per socket: 6 Socket(s): 1 Stepping: 10 CPU max MHz: 4600.0000 CPU min MHz: 800.0000 BogoMIPS: 6399.96 ``` ::: ### 使用 string 實作 fibnacci 解決溢位問題 :::spoiler ```c void add_str(char *num1, char *num2, char *out) { size_t len1 = strlen(num1), len2 = strlen(num2); int i, sum, carry = 0; reverse(num1); reverse(num2); if (len1 >= len2) { for (i = 0; i < len2; i++) { sum = (num1[i] - '0') + (num2[i] - '0') + carry; out[i] = '0' + sum % 10; carry = sum / 10; } for (i = len2; i < len1; i++) { sum = (num1[i] - '0') + carry; out[i] = '0' + sum % 10; carry = sum / 10; } } else { for (i = 0; i < len1; i++) { sum = (num1[i] - '0') + (num2[i] - '0') + carry; out[i] = '0' + sum % 10; carry = sum / 10; } for (i = len1; i < len2; i++) { sum = (num2[i] - '0') + carry; out[i] = '0' + sum % 10; carry = sum / 10; } } if (carry) out[i++] = '0' + carry; out[i] = '\0'; reverse(num1); reverse(num2); reverse(out); } ``` ::: ```c struct BigN{ char string[128]; }; ``` ```c static long long fib_sequence(long long k, char *buf) { struct BigN *f = kmalloc(sizeof(struct BigN) * (k + 1), GFP_KERNEL); if (!f) { return -ENOMEM; } strncpy(f[0].string, "0", 1); strncpy(f[1].string, "1", 1); for (int i = 2; i <= k; i++) add_str(f[i - 1].string , f[i - 2].string, f[i].string); int len = strlen(f[k].string) + 1; printk("k: %lld\n", k); if(__copy_to_user(buf, f[k].string, len)) return -EFAULT; return len; } ``` 使用字串來實作大數運算,發現 `fib[93]` 開始還是會錯,在 `fib_squence` 中加入 `printk("k: %lld\n", k);` ,並搭配 `journalctl` 發現 93 到 100 的 `k` 值都是 92。 發現 fibdrv.c 裡面有設定 `MAX_LENGTH` , 改完後就可以通過 make check ### clz / ctz 一類的指令對 Fibonacci 數運算的幫助 將原本的 fib 運算改成 fast doubling , 搭配 `__builtin_clzll` 去除 leading zero ```c static long long fib_sequence(long long k) { int num_bits = sizeof(k) * 8 - __builtin_clzll(k); long long t1, t2; long long a = 0, b = 1; // m = 0 for (int i = num_bits; i > 0; i--) { t1 = a * (2 * b - a); t2 = b * b + a * a; a = t1; b = t2; // m *= 2 if ((k >> (i - 1)) & 1) { t1 = a + b; // m++ a = b; b = t1; } } return a; } ``` ### [用 string 實作 fast doubling](https://github.com/sysprog21/fibdrv/commit/a08f677ad802aaaf1430b3c802a6188ad4c81d3f) `void mul_str(char *num1, char *num2, char *result)` `mul_str(t2, tmp, tmp);` 原本在 `fib_sequence` 中呼叫 `mul_str` 時沒注意到 `num2` 跟 `result` 是帶入相同的指標,在更改 `result` 時就會改到 `num2` ### 測量執行時間 加入測試時間程式後執行 make check 會卡住,待查 --- - [ ] 研讀上述 Linux 效能分析的提示 描述,在自己的實體電腦運作 G NU/Linux,做好必要的設定和準備工作 → 從中也該理解為何不希望在虛擬機器中進行實驗; - [ ] 研讀上述費氏數列相關材料 (包含論文),摘錄關鍵手法,並思考 clz / ctz 一類的指令對 Fibonacci 數運算的幫助。請列出關鍵程式碼並解說 - [ ] 複習 C 語言 數值系統 和 bitwise operation,思考 Fibonacci 數快速計算演算法的實作中如何減少乘法運算的成本; - [ ] 學習指出針對大數運算的加速運算和縮減記憶體操作成本的舉措,紀錄你的認知和疑惑 - [ ] 注意到 fibdrv.c 存在著 DEFINE_MUTEX, mutex_trylock, mutex_init, mutex_unlock, mutex_destroy 等字樣,什麼場景中會需要呢?撰寫多執行緒的 userspace 程式來測試,觀察 Linux 核心模組若沒用到 mutex,到底會發生什麼問題。嘗試撰寫使用 POSIX Thread 的程式碼來確認。 → 搭配閱讀〈並行和多執行緒程式設計〉