2.1 加速 Java 程式的方法
在一個沒有經過任何優化的 Java runtime system 上,Java 程式的性能是眾所 周知的差,因其 bytecode 需要被順序地被 interpreter 解譯。經典的優化方法便是 just-in-time compilation(JIT),或稱 dynamic translation。雖然 JIT 能夠以 binary-level optimization 產 生出 品 質 不錯 的 binary code , 但 它 必 須 犧 牲 較大 的 memory footprint[15]。除此之外,startup delay[16]。另一種增進 Java 程式性能的方式便是 Java processor/co-processor。Java 加速器之設計分為 standalone 的 Java processor 及協同式的 Java co-processor。前者為在單獨的 Java processor 內完成大部分的 bytecode interpreting 及執行,協同式則是需要與 genral-purpose 之處理器進行 co-processing。採用 standalone 之設計的 Java processor 主要有 sun 的 pico-Java[7],
aJile 的 JEMCore[10],Komodo[11]及 JOP[8]等等。使用協同式的 Java co-processor 有 ARM 的 Jazelle[12]及 Nazomi 的 JSTAR[13]。JAIP 是採用易於與其他處理器整 合 的 弱 協 同 式 設 計 (weakly-coupled co-design) , 只 要 目 標 處 理 器 支 援 interrupt-driven 之 communication 便可與 JAIP 整合。JAIP 可以獨力完成幾乎所有 的 Java 程式計算,只有程式需要低階 I/O 裝置控制例如 RS-232 controller,或 class file 的解析,才會需要使用 general-purpose 處理器計算。
2.2 Previous Work on JAIP
本論文所採用的處理器架構是由柯等人所提出的異質雙核心 Java 處理器[17, 18]。在這個架構當中,由兩個異質之處理器所組成。一個核心為 Java-core,內部 含有 Bytecode Execution Engine(BEE),負責 Java bytecode 之運行,Java bytecode 所需之符號解析工作是由 Dynamic Symbol Resolution Unit(DSRU)負責,而每次所 解析到的新的 Class 則由 Class Symbol Table Management Unit(CSTMU)與 Method
5
Area Management Unit(MAMU)來負責做 class loading。另一個核心為 RISC-core,
主要負責記憶體管理,class parsing 和 physical resource 管理等工作。
圖 1 異質雙核心爪哇處理器與字串加速器
BEE 是由柯等人提出的 double-issued 之 Java Bytecode Execution Egine[17, 18]
所改良而來的 bytecode ececution pipeline。BEE 是一個獨立的 IP。也就是說,它 可以整合到任何的 host 端處理器,只要 host 端支援 interrupt-driven 之 inter-processor communication 機制。BEE 是一個四個 stage 之 pipeline,包括 translate、fetch、decode 及 execution stage。Translate stage 透過 jpc 將 Method Area 內的 Java Bytecode 讀出,
每次盡可能地讀出兩個 byte 之 Method Area 資料,每個 OP code 皆會經過 translation ROM 轉換為一組 j-code info.。j-code info.被送進 fetch stage 後,被分類成為 simple 及 complex 兩種類型 bytecode,若為 simple bytecode,會被轉換成一個 BEE 指令
─j-code,兩個無 hazard 之 jocde 可以被 double-issued;若為 complex bytecode,
會被轉換為一組 j-code-pair sequence。每個 j-code pair 會經由後面的 decode stage 和 execution stage 執行。為了讓指令平行度增加,林等人提出了 2-level stack memory 架構[19, 20]。
6
DSRU 是由郭等人提出之符號解析器[9, 14]。負責在 runtime 時解析 Class Symbol Table(CST)中的資訊、協助引發 class loading 請求以及傳遞 class ID 和 method ID 到 CSTMU 和 MAMU 中。Symbol table 在一般程式語言中,是一個專 門儲存 identifier 資訊之資料結構,可供 compiler、interpreter 或 linker 查詢變數型 態、scope 或函式進入點。在我們的 JAIP 平台中,class symbol table 存放著 ldc bytecode 所用的 constant 資訊、new bytecode 需要的 class ID、field 操作和 invocation 時都需要的 Cross Reference Table 之 entry reference。Cross referece table 內的結構 則是由一個 entry 表示的 field info.,或是由 3 個 entry 組成的 method info.。DSRU 在 BEE 遇到 field 操作、load constant 或 invocation 類型 bytecode 時被啟動後,便 會啟動 DSRU 來解析 CST 與 Cross Reference Table 之內容。
2.3 Java 之軟硬體界面設計
不同 JVM 平台有不同硬體控制之方式。為了讓 JAIP 能夠以 Java 固有之語言 特性啟動字串硬體加速器,我們對於各種 Java 平台之軟硬體協同設計方式做了研 讀。研讀的對象包括完全軟體實作的 JVM 與透過 Java co-processor 實作的平台,
希望可以找出適合 JAIP 之方法。由於 Java 語言在對底層設備操作的方法是很抽 象的,而且 Java 之保護機制,使得 Java 無法直接對特定的記憶體位址或 I/O port 直接存取。若平台是屬於 memory-mapped I/O,使用 C 或 C++這種支援指標的程 式語言可以透過 I/O port 之位址來對 hardware device 做操作;若平台是屬於 port-mapped I/O,則程式語言必須使用作業系統提供的 API 或者是直接 inline assembly code 來使用處理器之 I/O 存取專用指令。然而,Java 程式語言並不支援 這種直接記憶體位址的存取或 I/O port 存取之功能。
一些研究制定與實作 Java 層面的硬體介面,例如建立硬體物件的 class packages 來供 Java 應用程式操作使用。Schoeberl 等人[21]提出了 Hardware Abstraction Layer 之標準,概念是將 hardware device 映射到一個 Java 物件,其 fields 代表 device registers,透過 static fields 的存取,Java program 可以實現對 device 之
7
操控。Whitham 等人[22]設計的系統中,一個 Interface Generator 可以將 Interface Description Language(IDL)檔案轉換成軟體和硬體介面,分別是 class file 和 HDL file,並且以 JOP[8]為基礎,利用 JOP 內部之 communication logic 實現 hardware method 功能。Borg 等人[23]提出兩種不同 JVM 硬體支援方法,分別是 method-based 及 object-based,並採用 method-based 方法實作出 JavaMen 類別庫。Ha 等人設計 的 Hard-HotSpot[24]利用 JBit API[25]來實現 runtime-reconfiguration 機制,並且以 hardware 加速 Java 程式。然而,Java 不支援任何對硬體的直接操作,這些設計都 是仰賴更底層的 hardware interface,例如 native method 或使用自定義 bytecode,
才能夠真正實現 Java 對硬體操控之功能。下一段將會介紹 Java 平台更底層的 hardware interface 設計方法。
所有的 JVM 軟硬體協同設計之實作方式不外乎兩種:1.透過修改 JVM 來擴 充其硬體支援以及 2.透過 native library 之介面對應體操控[20, 26, 27]。第一種是透 過修改 JVM 實作方式來分割 Java method、bytecode[8, 26],甚至是 object-oriented 才有的 object 及 field[8, 23],並分別以軟體和硬體來實作這些被分割的語意。修 改的地方可能是 class loader、interpreter,execution engine 甚至是 class image[10, 28]。
aJile[10]使用自行定義的 extended Java bytecode 作為與底層硬體溝通之介面,例如 thread 的 concurrent controll 及 multiple JVM context 之支援,而 extended bytecode 是使用 application tool─JEMBuilder 修改 class image 內容,讓特定 method 內部含 有自定義的 bytecode。JOP[8]使用 micro code 來對應體觸發及參數傳遞,完成花 費較昂貴的 bytecode,例如用 HDL 程式碼實作的電路來進行 imul。第二種類型則 是使用 native library 之 interface 對 device 做操作[29, 30]。這種方式的好處是 Java application 只需要移植 native library 到其它 JVM 平台,便可使用原有的 Java program。但是對於工作幾乎獨立於自身能力的 Java processor 來說,要讓系統可 以使用 native library,則必須要透過 bus 實作 polling 或 interrupt 機制,來與 general-purposed 之處理器做溝通,而其溝通成本會直接影響到 Java program 之效
8
能。
為了讓 Java 字串之處理程式能夠使用字串加速器,並在 Java application 不需 修 改 的 情 況 之 下 增 進 效 能 , 我 們 修 改 Java 標 準 類 別 庫 中 的 String.class 、 StringBuffer.class 和 System.class 等等,將其時間花費較多的 method 以功能等價 的硬體方式實作。為了讓 JAIP 和硬體加速器能夠溝通,我們實作了 Hardware Native Interface,此介面可以經由 Dynamic Symbol Resolution Unit 進行觸發,因 此 JAIP 與 RISC-core 之間,不需要昂貴的溝通成本便可以操控硬體加速器或其它 電路邏輯。Java Language 之介面方面,developer 僅需將想使用等價電路實作的 method 宣告為 native,並修改 class parser 即可。這些 native method 未來也可以透 過更有系統的 class package 包裝,避免 Java application level 的誤用。例如本篇論 文在第三章將會介紹的 hardware profiler,Java 程式即是以一個擁有數個 static native method 之 class 來啟動或關閉。
2.4 String Matching 與硬體加速
Pattern Matching 問題可以應用到許多不同的科學領域之計算上。常見的應用 有資料庫的字串搜尋、DNA 分析、網路入侵偵測或影像辨識等。在嵌入式 Java 平台上,我們希望以簡單且有效,且字串大小可參數化之硬體加速器,來輔助多 核心 Java 處理器之 String class 中與字串搜尋相關之操作。
有許多適合軟體的經典字串搜尋演算法,例如 KMP、Boyer-Moore 等等[1, 2],
大部分的演算法都需要額外的線性 preprocessing 時間和空間,意味著如果將這些 演 算 法 以 硬 體 實 作 的 話 , 需 要 額 外 的 記 憶 體 空 間 以 及 電 路 邏 輯 來 處 理 preprocessing,且字串比對的長度會受到硬體之設計而限制。一些硬體加速字串 的方法使用許多 processing elements 來進行平行的比較[31, 32]。一個很受歡迎的 pattern matching 方法,便是使用基於 Content-Addressable Memory(CAM)的比對系 統。CAM 是適合使用在需要快速搜尋資料的系統之記憶體結構,透過將比對資
9
料輸入至 CAM blocks,資料所在之位址便會從輸出端送出。CAM 為基礎的比對 系統通常會使用到龐大的記憶體空間。不論是使用 ASIC 技術或 FPGA,都會使 用許多的硬體資源。以 Le 等人的做法為例[33],一個大小為 1kB 的 Altera M9K 記憶體結構可以作為一個 32-word x 8-bit 的 CAM unit。若需要實作可以容納 1024 個 UTF-16 字元的 CAMs,則需要 1024-word x 16-bit,也就是需要 64 個 CAM unit,
可換算成大小為 64kB 的 Altera M9K 記憶體。參考 Xilinx 之 BlockRAM 實作 CAMs 的 Reference Design[34, 35],在 XCV50 的 device 上欲實作一個能儲存 1024 個 UTF-16 字元之 CAM,需要 128 個 BlockRAM,也就是 256kB 的記憶體空間。此 外,我們尚需要額外的 shift register 及 logic element,來完成一連串的字元比對以 及記憶體位址之 encoder。
這些字串比對系統都可以很快速地進行比對,特別是使用 CAM。然而,幾 乎每種系統都需要 preprocessing,換句話說,每次新的 matching system 中的 database 或字串文本更新時,都需要重新將字串寫入比對系統以進行 preprocessing。
這些優異的系統非常適合在 database 或字串文本鮮少更動的系統中。但在 Java 平 台中,字串比對操作無法保證每次使用操作的字串物件都是相同的,字串比對系 統的 preprocessing 時間是無法避免的。若為了節省 matching system 的 preprocessing 時間而將字串物件直接儲存於像 CAM 的特殊儲存體中,那麼當程式要透過索引 值將對應位置的字元讀出時,會是一個很大的麻煩。因此將字串儲存於 RAM 中 是比較合理的作法。儘管將字元寫入比對系統的動作與字元從字串物件中讀出的 動作可以被重疊,一般情況下整個字串比對時間仍然被字串文本之讀出時間支配 著。因此,以字串文本經常變動的前提之下,只要比對動作能夠與字元從字串物 件讀出的動作可以被重疊,並且盡可能以 word 為單位進行比對,迴圈次數以及 bytecode 執行時間的節省,足以使許多字串比對的情況得到不錯的效能了。本論 文採用 brute-force 的字串比對方法,是一個不需要太多 logic element、字串大小 有彈性且完全不需要額外的記憶體空間之設計。
這些優異的系統非常適合在 database 或字串文本鮮少更動的系統中。但在 Java 平 台中,字串比對操作無法保證每次使用操作的字串物件都是相同的,字串比對系 統的 preprocessing 時間是無法避免的。若為了節省 matching system 的 preprocessing 時間而將字串物件直接儲存於像 CAM 的特殊儲存體中,那麼當程式要透過索引 值將對應位置的字元讀出時,會是一個很大的麻煩。因此將字串儲存於 RAM 中 是比較合理的作法。儘管將字元寫入比對系統的動作與字元從字串物件中讀出的 動作可以被重疊,一般情況下整個字串比對時間仍然被字串文本之讀出時間支配 著。因此,以字串文本經常變動的前提之下,只要比對動作能夠與字元從字串物 件讀出的動作可以被重疊,並且盡可能以 word 為單位進行比對,迴圈次數以及 bytecode 執行時間的節省,足以使許多字串比對的情況得到不錯的效能了。本論 文採用 brute-force 的字串比對方法,是一個不需要太多 logic element、字串大小 有彈性且完全不需要額外的記憶體空間之設計。