龍芯2E平台程式效能分析

2021-06-15 21:37:18 字數 3562 閱讀 1597

1. 分析一段**的效能,最常用的方法是測量這段**的執行時間。假如我要分析下面這兩段**的效能差異,可以在**前後插入2個變數,分別記錄執行前後的時間,相減即可:

**一:

int matrix[2047][7];

int main()

**二:

int matrix[2047][7];

int main()

則可以在a1,a2處插入 beg = times(null); // 返回以過去某點為基準點的時鐘滴答數

b1, b2處插入 end = times(null);     // 需要包含標頭檔案 sys/times.h

相減即可得到該段**的執行時間。

當 前linux系統的每秒經過的時鐘滴答數可以使用sysconf(_sc_clk_tck)獲得,我在linux-2.6.18 for loongson2e的環境下獲取的值為 100,即最小測量的精度是10ms。這個精度要遠遠高於time() 1s的精度,但是這個精度還是無法滿足上面測量要求,因為分別編譯執行後,兩段**的執行時間是一致的,這個結果是不能被接收的,從定性的分析開看,** 二的效能肯定是優於**一的。

2. 使用龍芯2e系統協處理器(cp0)中的兩個效能計數器

(performance counter)

龍 芯2e之系統協處理器中引入了兩個效能計數器,對應cp0暫存器的25號,長度為64位,低32位作為counter 0,高32位作為counter 1。其中cp0的24號暫存器作為2個計數器的控制暫存器,亦是64位,可以設定它,分別控制兩個計數器所記錄的事件。

cp0的24號暫存器簡單描述:3~0 位作為使能位目前置1;第5位作為中斷使能位目前置0;8~5為counter 0的計數事件,12~9 作為counter 1的計數事件,其餘位置0。

比 如我要控制 counter 0對時鐘週期進行計數,counter 1對一級資料快取不命中進行計數,可以將cp0d的24號暫存器置值為 0x80f(01000 0000 1111),即counter 0的計數事件為0000,counter 1的計數事件為0100,這個值可以檢視龍芯2e使用者手冊。

3. 設定效能計數器的計數事件

counter 0常用計數事件(4位):

0000: 時鐘週期計數

0001: 分支指令計數

0100: 一級i-cache不命中計數

1001: 從主存中讀計數

1110: tlb重填例外計數

counter 1常用計數事件(4位):

0001: 分支**失敗計數

0100: 一級d-cache不命中計數

0111: 訪問未快取計數

1001: 寫到主存計數

1100: itlb不命中計數

目前的核心起起來後,cp0的24號暫存器為 0x1ef,故而我要重設24號暫存器的值 0x80f(01000 0000 1111,counter 0的計數事件為0000,counter 1的計數事件為0100).

對龍芯2e系統協處理器的暫存器執行寫操作在使用者空間是沒有寫許可權的。我們可以寫乙個簡單的模組,把設定的操作放在模組初試化函式中來完成:

[set_event.c]

#include

#include

module_license("gpl");

static int set_init(void)

static void set_exit(void)

module_init(set_init);

module_exit(set_exit);

相應的makefile為:

ifeq ($(kernelrelease),)

kerneldir ?= /lib/modules/$(shell uname -r)/build

pwd := $(shell pwd)

modules:

$(make) -c $(kerneldir) m=$(pwd) modules

modules_install:

$(make) -c $(kerneldir) m=$(pwd) modules_install

clean:

rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions

.phony: modules modules_install clean

else

# called from kernel build system: just declare what our modules are

obj-m := set_event.o

endif

4. 解決問題

在使用上述模組編譯、安裝(insmod),設定好兩個計數器的計數事件後,我們依然在a1,a2插入**,讀取兩個計數器的值,並記錄:

unsigned int cache_miss_beg, cache_miss_end;

asm volatile

(".set mips3/n/t"

"dmfc0 %0, $25/n/t"

"dsra   %0, 32/n/t"

:"=r"(cache_miss_beg)         //記錄執行前counter 1的值,l1 d-cache的事件

);asm volatile("mfc0 %0, $25":"=r"(beg)); //記錄執行前counter 0的值,cpu時鐘週期事件

在b1,b2插入:

asm volatile("mfc0 %0, $25":"=r"(end)); //記錄執行後counter 0的值,cpu時鐘週期事件

asm volatile

(".set mips3/n/t"

"dmfc0 %0, $25/n/t"

"dsra   %0, 32/n/t"

:"=r"(cache_miss_end)         //記錄執行後counter 1的值,l1 d-cache的事件

);printf("total cpu cycles is: %d/n", end - beg);

printf("the number of l1 d-cache miss is: %d/n", cache_miss_end - cache_miss_beg);

基於計數器的測量方法,精度很高,可以得到程式執行期間所經過的時鐘週期數。但是影響其準確性的因素也很多,主要有因程序上下文切換,致使其他程序占用處理器,影響計數器的計數,這個可以通過在低負載的機器上多次執行求平均值的方法來弱化。

如上面的例子我們執行 init 1 進入單使用者模式下,此時系統僅有乙個bash程序,分別執行5次求得平均值:

**一所需時鐘週期為:         1035200

**一一級資料cache缺失次數為:   2431

**二所需時鐘週期為:         735310

**二一級資料cache缺失次數為:   2092

**一所需時鐘週期是**二的 1.4 倍

**一一級資料cache缺失次數是**二的 1.16 倍

可以看到,**一訪問陣列按行訪問(c語言中,陣列存放於記憶體是按列存放),這樣cpu對資料的訪問就會呈「跳躍」的形態,違背了空間區域性性,致使cache命中率下降,影響了整個**的效能。

測試**:

關閉龍芯2E 之 cache

發表日期 2006 11 01 19 50 pmon 載入kernel 時,是載入到 kseg0 的 通過在 arch mips makefile 中 load config godsonev2e 0x80100000 指定 該位址空間是 unmaped cached 的,當 pmon 將控制權交給...

龍芯軟體開發 12 龍芯2E摸索前行

上一次說到怎麼樣執行起來,現在接著上次再進行分析下去。在 locate的程式,如下 locate la s0,start subu s0,ra,s0 ands0,0xffff0000 li t0,sr boot exc vec mtc0 t0,cop 0 status reg mtc0 zero,c...

龍芯軟體開發 11 龍芯2E執行的第一行程式

天生萬物,萬物始於天。同樣,龍芯2e要執行起來,那麼就少不了程式。那麼龍芯2e的盤古開天是從那裡開始呢?追源尋根,才能了解事物的來龍去脈,才能把握住未來的方向。現在就去尋找龍芯電腦執行的第一行程式,去看看龍芯的初始化階段都做了些什麼事情,有沒有做壞事情呢?哈哈,這個很難說的。如果有bug的出現,就會...