Try   HackMD

2022q1 Homework3 (fibdrv)

contributed by < BensonYang1999 >

實作前準備

閱讀 《The Linux Kernel Module Programming Guide

依照步驟實作,成功編譯出 hello world ,並成功執行

$ sudo insmod hello-1.ko
$ sudo lsmod | grep hello
hello_1                16384  0
$ sudo rmmod hello_1
$ sudo journalctl --since "1 hour ago" | grep kernel
 三  08 21:26:27 benson-ubuntu kernel: Hello world 1.
 三  08 21:26:45 benson-ubuntu kernel: Goodbye world 1.

產生出 Module Dpcumentation

$ modinfo hello-4.ko
filename:       hello-4.ko
description:    A sample driver
author:         LKMPG
license:        GPL
srcversion:     510C26102AE3F8D731FE755
depends:        
retpoline:      Y
name:           hello_4
vermagic:       5.13.0-30-generic SMP mod_unload modversions 

傳入參數

$ sudo insmod hello-5.ko mystring="bebop" myintarray=-1
$ sudo dmesg -t | tail -7
myshort is a short integer: 1
myint is an integer: 420
mylong is a long integer: 9999
mystring is a string: bebop
myintarray[0] = -1
myintarray[1] = 420
got 1 arguments for myintarray.

待續

前期準備

  • linux 核心版本
    ​​​​$ uname -r
    ​​​​5.13.0-30-generic
    
  • 套件安裝
    ​​​​$ sudo apt install linux-headers-`uname -r`
    ​​​​Reading package lists... Done
    ​​​​Building dependency tree       
    ​​​​Reading state information... Done
    ​​​​linux-headers-5.13.0-30-generic is already the newest version (5.13.0-30.33~20.04.1).
    ​​​​0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
    
  • 檢查使用者
    ​​​​$ whoami
    ​​​​benson
    ​​​​$ sudo whoami
    ​​​​root
    
  • 安裝工具
    ​​​​$ sudo apt install util-linux strace gnuplot-nox
    
  • 取得原始程式碼並測試
    ​​​​$ git clone git@github.com:BensonYang1999/fibdrv.git
    ​​​​$ cd fibdrv
    ​​​​$ make check
    ​​​​ Passed [-]
    ​​​​f(93) fail
    ​​​​input: 7540113804746346429
    ​​​​expected: 12200160415121876738
    
    ​​​​$ modinfo fibdrv.ko
    ​​​​filename:       /fibdrv.ko
    ​​​​version:        0.1
    ​​​​description:    Fibonacci engine driver
    ​​​​author:         National Cheng Kung University, Taiwan
    ​​​​license:        Dual MIT/GPL
    ​​​​srcversion:     9A01E3671A116ADA9F2BB0A
    ​​​​depends:        
    ​​​​retpoline:      Y
    ​​​​name:           fibdrv
    ​​​​vermagic:       5.13.0-30-generic SMP mod_unload modversions 
    
    ​​​​$ sudo insmod fibdrv.ko
    ​​​​$ ls -l /dev/fibonacci
    ​​​​crw------- 1 root root 505, 0  三   8 23:32 /dev/fibonacci
    
    ​​​​$ cat /sys/class/fibonacci/fibonacci/dev
    ​​​​505:0
    
    ​​​​$ cat /sys/module/fibdrv/version
    ​​​​0.1
    
    ​​​​$ lsmod | grep fibdrv
    ​​​​fibdrv                 16384  0
    
    ​​​​$ cat /sys/module/fibdrv/refcnt
    ​​​​0
    
    ​​​​$ sudo rmmod fibdrv
    
    測試內容接符合預期

Fix C99 variable-length array (VLA) is not allowed in Linux kernel.

這裡原本使用動態宣告陣列儲存斐波那契數列,但是 Linux 核心開發不傾向使用 VLA,因此編譯時會產生警告

fibdrv.c: In function ‘fib_sequence’:
fibdrv.c:30:5: warning: ISO C90 forbids variable length array ‘f’ [-Wvla]
   30 |     long long f[k + 2];
      |     ^~~~

我參考講義中提到的 Fast Doubling 作法,嘗試修改這部份的程式碼

static long long fib_sequence(long long k)
{
    if (k <= 2)
        return k ? 1 : 0;

    long long n = 0;
    if (k % 2) {
        n = (k - 1) / 2;
        return fib_sequence(n) * fib_sequence(n) +
               fib_sequence(n + 1) * fib_sequence(n + 1);
    } else {
        n = k / 2;
        return fib_sequence(n) * (2 * fib_sequence(n + 1) - fib_sequence(n));
    }
}

修改後的程式雖然還是沒辦法處理 F93 以上的大數,但可以解決編譯時的 VLA 問題

平台轉換

在參考 laneser 的作業後,發現可以使用 raspberry pi 完成作業,因此我毅然決然決定更換平台,使用 raspberry pi 3b+ ,以利筆記的書寫 (因為 ubuntu 的中文輸入法不是很好用)
更換平台後的環境

$ gcc --version
gcc (Debian 10.2.1-6) 10.2.1 20210110

$ lscpu
Architecture:                    aarch64
CPU op-mode(s):                  32-bit, 64-bit
Byte Order:                      Little Endian
CPU(s):                          4
On-line CPU(s) list:             0-3
Thread(s) per core:              1
Core(s) per socket:              4
Socket(s):                       1
Vendor ID:                       ARM
Model:                           4
Model name:                      Cortex-A53
Stepping:                        r0p4
CPU max MHz:                     1400.0000
CPU min MHz:                     600.0000
BogoMIPS:                        38.40
Vulnerability Itlb multihit:     Not affected
Vulnerability L1tf:              Not affected
Vulnerability Mds:               Not affected
Vulnerability Meltdown:          Not affected
Vulnerability Spec store bypass: Not affected
Vulnerability Spectre v1:        Mitigation; __user pointer sanitization
Vulnerability Spectre v2:        Not affected
Vulnerability Srbds:             Not affected
Vulnerability Tsx async abort:   Not affected
Flags:                           fp asimd evtstrm crc32 cpuid

排除干擾效能分析的因素

抑制程式使用特定核心

/boot/cmdline.txt 檔案中加入參數 isolcpus=3 ,重開機之後即可排除程式利用 core 3

排除干擾效能分析的因素

抑制 address space layout randomization (ASLR)

$ sudo sh -c "echo 0 > /proc/sys/kernel/randomize_va_space"

設定 scaling_governor 為 performance

建立檔案 performance.sh ,並加入以下內容

for i in /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
do
    echo performance > ${i}
done

之後用 $ sudo sh performance.sh 執行

##時間測量
這部分將參考 KYG-yaya573142 的報告 ,嘗試修改 fib_write

static ssize_t fib_write(struct file *file,
                         const char *buf,
                         size_t size,
                         loff_t *offset)
{
    ktime_t kt;
    kt = ktime_get();
    fib_sequence(*offset);
    kt = ktime_sub(ktime_get(), kt);
    return (ssize_t) ktime_to_ns(kt);
}

結果在執行 make check 時,會報錯

...
-Writing to /dev/fibonacci, returned the sequence 157
+Writing to /dev/fibonacci, returned the sequence 1
...
make: *** [Makefile:40: check] Error 1

推測是 fib_write 的回傳值有問題,因此參考 laneser 的筆記,修改回傳值

static ssize_t fib_write(struct file *file,
                         const char *buf,
                         size_t size,
                         loff_t *offset)
{
    if (buf)
        return 1;
    
    ktime_t kt;
    kt = ktime_get();
    fib_sequence(*offset);
    kt = ktime_sub(ktime_get(), kt);
    return (ssize_t) ktime_to_ns(kt);
}