2010年3月27日 星期六

Multi-SPARC Virtual Platform -- 品皓

======================5/17============================
meeting投影片

利用之前完成的觀測instruction cycle執行數的功能,觀測自己寫的矩陣相乘程式。

40X40 矩陣相乘,分給四個core,切割方式是每一個task計算出一個element,也就是說每個task接收80個elements,處理40個乘加運算,最後產生一個element並送出。總共有1600個task。一個task所需的instruction cycle數:
wait input: 557
calculation: 2119
send output: 82

以上是平均的結果,但是meeting時大家疑問為什麼40個乘加需要花費這麼多instruction?

之後檢討,觀察assembly code,一個整數的乘法是呼叫一個function .umul


.umul 是在做bit的乘法(mulscc),也就是說一個32 bit的整數他需要做32次mulscc


其中的原因是sparc gcc預設是產生v7的instuction code,為了產生v8的必須加上參數-mcpu=v8。產生的結果是一個整數乘法只需一個instuction完成(smul)。



v8 task所需的instruction cycle數:
wait input: 481
calculation: 354
send output: 82

整個40x40的矩陣相乘所需的instruction cycle數
wait input: 191919 ~ 192591
calculation: 141645
send output: 32718

wait input數據有點差距的原因是程式的行為,開始是四個core同時在等待input,但是外部module送input data卻是一次只能送一個,所以才會造成這一點差距。

======================4/26============================
主要是完成上禮拜做一半的事情,完成外部module透過Multi-core’s Interface與core溝通的能力;並改寫應用程式: 矩陣相乘,改成input & output data皆由ELF sender收送。

另外一個是觀測instruction執行數的功能。
寫成一個應用程式(ELF)可呼叫的function,包在library裡。功用是回傳目前執行總cycle數。
用法跟一般timer類似,想紀錄一段測試程式執行所花費的cycle數時,在測試程式執行前紀錄當下時間,和測試程式執行結束後的當下時間,兩個數值相減就是所要的。

實作方面,此暫存值紀錄在buffer state裡(下圖的inst count),ELF裡的function call只是回傳那個暫存器的資料,實際上是由模擬器更新,也就是SPARC ISS每個cycle更新一次。



======================4/13============================

修改之前呈現的範例程式: 矩陣相乘
原本為了趕比賽把input data寫死在ELF裡,ELF sender把應用程式透過multi-core's interface把執行檔分給所有的core,不同的core自行取用運算所需的input,運算結果全部傳到其中一個core收集並結束。改成input & output data皆由ELF sender收送,core只負責收input和把運算結果output就好。

簡單的說就是需要外部module透過Multi-core’s Interface與core溝通的能力。我的想法是如同之前core之間的溝通方式;也就是增加與sc_port對應的I/O buffer,如同SPARC ISS的I/O buffer。Interface作資料讀寫看到的仍是buffers,並無多少改變。


這樣的好處是可以沿用舊有的溝通方式。不管是core還是sc_port,資料讀寫時看到的都是自己的I/O buffer,同樣interface在處理資料收送時,看到的同樣是buffers,整體上不會修改到太多。


之後還會加上別的功能如多個multi-core's interface的溝通,仍然是透過sc_port,所以應該也可以透過同樣的方式溝通。
======================3/28============================
比賽影片

比賽文件


上禮拜meeting時報告了幾個case執行的數據如下:
Case: 12X12矩陣相乘 分給四個core執行
total Instruction executed: 9,346,711 X 4
Time: 40.92 sec

Case: 12X12矩陣相乘 分給一個core執行
total Instruction executed: 34,639,538
Time: 55.29 sec

這數據蠻奇怪的,模擬34M指令需要55秒,模擬36M指令卻只要41秒?
因為明明是在同一台電腦上模擬,模擬四個core的效率竟然比一個core好。

後來找了很久才發現是systemc kernal的overhead問題,因為我的模擬器是這樣設計的,每跳一個clock所有的ISS就執行一個instruction,而模擬一個instruction的工作量比起systemc kernal小很多。也就是說模擬一個core就是每一個clock跑一個instruction和一次systemc kernal,模擬四個core就是每一個clock跑四個instruction和一個systemc kernal。

判斷這問題的方式則是增加每個instruction模擬的工作量即可,我的作法是加入很長的迴圈,之後得到的數據就比較正常了
Case: 12X12矩陣相乘 分給四個core執行
total Instruction executed: 4.2M X 4
Time: 502 sec

Case: 12X12矩陣相乘 分給一個core執行
total Instruction executed: 14.5M
Time: 436 sec


======================3/16============================

之前有提到,編譯應用程式ELF時裡面的I/O buffer的宣告和使用我是包成一個c library,使用者撰寫應用程式時必須include這個library,那麼編譯時如果有作最佳化是否會出問題?

答案是會的......

最後我避免的方式是加入attribute的設定,可以強制編譯器在處理這個function時使用指定的最佳化等級,譬如以下範例:
void foo () __attribute__ ((optimize(0)));
void foo () {
.........
}
表示foo()這個function編譯時強制使用optimization level 0,只是這方法只能在gcc上使用。

另外是把GDB的功能加到SPARC ISS上。使用ArchC產生SPARC ISS 時就有順帶產生SPARC GDB stub function,雖然ArchC文件寫GDB這段寫的不清不楚的,但是因為之前有作過8051 debugging stub,所以花了點時間trace code就知道怎麼用了。之後簡單測試了幾個指令:中斷點,單步執行,讀寫變數都沒有問題。



目前測試情況如上圖:左邊數來第一個視窗為systemC虛擬平台上兩個SPARC ISS,各一個GDB stub在跑,右邊兩個GDB視窗與之相連。由於systemc是單執行序的模擬方式,所以同時間只會有一個GDB端在與其對應的GDB stub溝通,其他的則是在等待狀態。

======================3/8============================

目前正在作多個SPARC ISS之間的資料讀寫問題,架構與溝通方式以下分段講解:
1.架構:一個中央模組ISS interface連接所有SPARC ISS,也就是全部透過sc_interface與ISS interface相連。每個SPARC ISS都會有I/O buffer各一個,和一個state buffer,ISS interface檢查每個SPARC ISS的I/O buffer並執行搬運資料的動作來達成。

那些buffer是SPARC ISS裡面執行的測試程式(test.elf)宣告在SPARC memory裡的。這裡就關係到應用程式設計者要怎麼使用I/O buffer來達成多核分工的問題。I/O buffer的宣告和使用我是包成一個c library,使用者撰寫應用程式時必須include這個library,並在程式一開始時呼叫buffer初始化的function。之後使用者就可以使用裡面的function進行多核之間的資料讀寫。

這裡比較麻煩的是buffer的位子,是由sparc gcc安排在 sparc memory,包在elf裡。因為ISS interface在存取I/O buffer時必須知道其位子,因此需要buffer初始化。

SPARC ISS載入elf後從pc = 0開始執行。elf裡一開始一定會執行buffer初始化,將I/O buffer address指定在幾個local register並等待(無限迴圈)ISS interface讀取。ISS interface讀取完後將建立一個I/O buffer address table,之後讀寫資料根據此table。ISS interface建立完table後告知SPARC ISS,跳脫等待的無限迴圈並結束buffer的初始化,之後就繼續執行elf的程式。



2. 溝通方式:假設有兩個SPARC ISS A&B,A寫資料給B,如上圖producer->consumer。
A將要寫的資料寫到自己的output buffer並註明目標為B
ISS interface檢查每個SPARC ISS的I/O buffer,知道A有資料要給B
ISS interface檢查B的input buffer是否為空
如果為空,將A的output buffer搬到B的input buffer
B檢查自己的input buffer是否為空以得知有沒有別人傳資料給他。

=====================================================
整個計畫的起始點是從一個單核SPARC simulator開始. 我找了很多模擬器, 最後決定用ArchC. ArchC為 Architecture Description Language, 我用ArchC產生SPARC V8 指令模擬器, 產生出來的模擬器是純c code, 包成一個SystemC module, 且支援gdb的樣子. 測試程式可以由sparc gcc編譯出的elf直接放到指令模擬器上執行.

有了SPARC ISS和其支援工具, 接下來是要發展成多核虛擬平台. 目的是可以將一個應用程式差成多個子程式, 放在不同的SPARC ISS上執行, 最後共同完成此應用程式的功能, 達到多核分工的目標.