# 2021q1 Homework3 (fibdrv)
Contributed by < `fdfdd12345628` >
> [作業需求](https://hackmd.io/@sysprog/linux2021-fibdrv)
> [GitHub](https://github.com/fdfdd12345628/fibdrv)
## Fibonacci 數列
這裡使用 [HUGE-Fibonacci](https://github.com/wolfofalgstreet/HUGE-Fibonacci) ,因為是 MIT licence 所以就直接用了。
它的原理是建構一個 struct 來儲存大數字
```cpp
// Fibonacci.h
struct HugeInteger
{
// a dynamically allocated array to hold the digits of a huge integer
int *digits;
// the number of digits in the huge integer (approx. equal to array length)
int length;
}
```
並且在每次加法時配置更多記憶體
```cpp
// fibonacci.c
if(isPlenLarger(p,q) == 1)
hugeAddition->digits = calloc(p->length + 7, sizeof(int));
else hugeAddition->digits = calloc(q->length + 7, sizeof(int));
```
並且加法時計算加了幾位數,最後才儲存 length
```cpp
// fibonacci.c
hugeAddition->length = size;
```
由於這個程式是使用 int array 當儲存數字的地方,但因為單個數字範圍只有$0 - 9$,所以可以只用 byte array 就好了。
最後把 `malloc` 改成 `kmalloc` , `calloc` 改成 `kcalloc` , `free` 改成 `kfree` 。並且將 header 全部整合進一個檔案,就可以編譯並且執行了。
## 效能檢定
測試電腦環境如下
CPU: kvm Genuine Intel(R) CPU x1
RAM: 981MB
測試電腦在伺服器上,可以將筆電相關的影響去除
首先在 `fibdrv.c` 加入以下程式碼來計算時間
```clike=
// fibdrv.c
static ktime_t kt;
static HugeInteger *fib_time_proxy(long long k)
{
kt = ktime_get();
HugeInteger *result = fib_sequence(k);
kt = ktime_sub(ktime_get(), kt);
return result;
}
static ssize_t fib_read(struct file *file,
char *buf,
size_t size,
loff_t *offset)
{
HugeInteger *result = fib_time_proxy(*offset);
copy_to_user(buf, result->digits, sizeof(int) * result->length);
return result->length;
}
static ssize_t fib_write(struct file *file,
const char *buf,
size_t size,
loff_t *offset)
{
return ktime_to_ns(kt);
}
```
這樣可以在 `fib_write` 時讀取到上次 `fib_read` 的時間。
並且製作一個新的 client 來讀取 kernel 耗時與計算 user 耗時,取樣 100 次
```clike=
for (int k = 0; k < 100; k++) {
long long sz;
sz = write(fd, write_buf, strlen(write_buf));
long long kernel_time = sz;
for (int i = 0; i <= offset; i++) {
// printf("Writing to " FIB_DEV ", returned the sequence %lld\n",sz);
lseek(fd, i, SEEK_SET);
struct timespec start, end;
double time_used;
// 計算開始時間
clock_gettime(CLOCK_MONOTONIC, &start);
sz = read(fd, buf, 100 * sizeof(int));
clock_gettime(CLOCK_MONOTONIC, &end);
// printf("Reading from " FIB_DEV " at offset %d, returned the sequence ", i);
for (int j = sz - 1; j >= 0; j--) {
printf("%d", buf[j]);
}
printf(".\n");
struct timespec temp = diff(start, end);
time_used = (double) temp.tv_nsec;
sz = write(fd, write_buf, strlen(write_buf));
kernel_time = sz;
printf("Num: %d, kernel: %lld, user: %lf, diff: %lf\n", i, kernel_time, time_used, time_used - kernel_time);
memset(buf, 0, sizeof(int) * 100);
}
}
```
輸出如下
```
...
218922995834555169026.
Num: 99, kernel: 21413, user: 24785.000000, diff: 3372.000000
354224848179261915075.
Num: 100, kernel: 21839, user: 25191.000000, diff: 3352.000000
```
最後將輸出資料用 python 處理
```python=
# script/statistic.py
#!/usr/bin/env python3
import pprint
import numpy as np
expect = [0, 1]
result = []
result_split = []
dics = []
for i in range(2, 101):
expect.append(expect[i - 1] + expect[i - 2])
with open('out', 'r') as f:
tmp = f.readline()
while (tmp):
result.append(tmp)
tmp = f.readline()
f.close()
for r in result:
if (r.find('Num') != -1):
result_split.append(r.split(' '))
num=int(result_split[-1][1][:-1])
kernel=int((result_split[-1][3][:-1]))
user=int(float(result_split[-1][5][:-1]))
diff=int(float(result_split[-1][7][:-1]))
if num==0:
dics.append([])
dics[-1].append((num, kernel, user, diff))
# pprint.pprint(dics)
mean=[]
data=np.array(dics)
print(data[:, 1:2,:])
def outlier_filter(datas, threshold = 2):
datas = np.array(datas)
z = np.abs((datas - datas.mean()) / datas.std())
return datas[z < threshold]
def data_processing(data_set, n):
catgories = data_set[0].shape[0]
samples = data_set[0].shape[1]
final = np.zeros((catgories, samples))
for c in range(catgories):
for s in range(samples):
final[c][s] = \
outlier_filter([data_set[i][c][s] for i in range(n)]).mean()
return final
for i in range(101):
kernel_mean = outlier_filter(data[:, i:i+1, 1]).mean()
user_mean = outlier_filter(data[:, i:i+1, 2]).mean()
diff_mean = outlier_filter(data[:, i:i+1, 3]).mean()
mean.append((i, kernel_mean, user_mean, diff_mean))
print("result:")
pprint.pprint(mean)
import csv
with open('output.csv', 'w+') as fp:
writer=csv.writer(fp)
writer.writerows(mean)
```
最後用 gnuplot 來繪製 `output.csv` 如下
![](https://i.imgur.com/tAlZX3W.png)
可以看出 kernel 到 user 有一定的 overhead
## TODO
1. 增進大數計算