余 澤 霖,徐 云
(1.中國科學(xué)技術(shù)大學(xué) 計(jì)算機(jī)科學(xué)與技術(shù)學(xué)院,安徽 合肥230026;2.安徽省高性能計(jì)算重點(diǎn)實(shí)驗(yàn)室,安徽 合肥230026)
MATLAB 由于其強(qiáng)大的功能、友好的開發(fā)界面和簡單易用的編程語言形式而被開發(fā)人員廣泛使用,許多企業(yè)和科研單位都存在著大量的MATLAB遺留代碼(Legacy Code)。但由于MATLAB 程序運(yùn)行依賴于MATLAB 軟件系統(tǒng),部分工作平臺無法滿足要求,并且它的運(yùn)行速度相較于C 等更底層的語言慢,無法滿足高性能計(jì)算的需求,通常需要將這些遺留MATLAB 代碼轉(zhuǎn)換為C 代碼。而人工轉(zhuǎn)換代碼需要付出高昂的人力成本,因此,理想的解決方案是將MATLAB 代碼自動(dòng)轉(zhuǎn)換成C 代碼。
程序轉(zhuǎn)換可以節(jié)省軟件開發(fā)的成本,并在軟件的移植、重用、更新和編譯等方面有著重要的應(yīng)用[1],因此在國內(nèi)外有大量的對編程語言轉(zhuǎn)換的研究。本文對已有的編程語言轉(zhuǎn)換方法進(jìn)行了借鑒和改進(jìn),提出了一個(gè)MATLAB 到C 的自動(dòng)轉(zhuǎn)換方法,著重解決了以下三個(gè)關(guān)鍵問題:一是引入了一種基于抽象語法樹(Abstract Syntax Tree,AST)的中間表示(Intermediate Representation,IR)來解決兩語言間的差異問題,為MATLAB 和C 轉(zhuǎn)換過程中提供統(tǒng)一的接口,避免為兩種語言的語法結(jié)構(gòu)映射制定繁瑣的規(guī)則。二是由于C 中變量需要聲明后使用,而MATLAB 不需要,因此在轉(zhuǎn)換時(shí)需要對MATLAB 中的矩陣變量的類型信息(矩陣的大小和矩陣元素的類型)進(jìn)行識別。已有許多對此類高級語言的變量類型信息識別的研究成果[2-6],本文借鑒并實(shí)現(xiàn)了MATLAB 到C 的轉(zhuǎn)換過程中的類型信息推導(dǎo)。三是MATLAB 中大部分表達(dá)式是矢量間的運(yùn)算,直接轉(zhuǎn)換到C 語句會導(dǎo)致性能下降,并且很多內(nèi)置的科學(xué)計(jì)算函數(shù)沒有直接對應(yīng)的C 代碼。本文設(shè)計(jì)了轉(zhuǎn)換算法,使用C 數(shù)學(xué)核心庫(Math Kernel Library,MKL)中的函數(shù)為MATLAB 中的矢量運(yùn)算和庫函數(shù)生成高性能C 代碼段,解決轉(zhuǎn)換困難和性能問題。本文實(shí)現(xiàn)的系統(tǒng)能幫助開發(fā)人員將MATLAB 代碼自動(dòng)轉(zhuǎn)換生成C代碼,提升代碼性能,減少人工成本。
目前,編程語言轉(zhuǎn)換方法大致可以分為兩類。
一類是將原語言的語法結(jié)構(gòu)一一轉(zhuǎn)換到目標(biāo)語言的語法結(jié)構(gòu)。李友仁[1]等人提出了一種語義解釋的轉(zhuǎn)換方法,為Prolog 的不同組成部分制定相應(yīng)的轉(zhuǎn)換模板,并應(yīng)用該方法開發(fā)了Prolog 到C 的自動(dòng)轉(zhuǎn)換系統(tǒng);Boyle[7]等人通過將Lisp 中的多種語言特性逐步轉(zhuǎn)換為對應(yīng)的Fortran 語句實(shí)現(xiàn)Lisp 到Fortran的轉(zhuǎn)換;Moynihan[8]等人通過定義固定的轉(zhuǎn)換規(guī)則把Pascal-SC 中的語句轉(zhuǎn)換到對應(yīng)的Ada 語句,輔助將Pascal-SC 代碼轉(zhuǎn)換到Ada 代碼;Demaine[9]提出了將C 中的指針等價(jià)地轉(zhuǎn)換成Java 中的引用的方法,并基于此實(shí)現(xiàn)C 到Java 代碼的自動(dòng)轉(zhuǎn)換。這類方法需要為原語言的每種語言結(jié)構(gòu)制定相應(yīng)的轉(zhuǎn)換方案,對語言依賴性高,當(dāng)出現(xiàn)新的需要轉(zhuǎn)換的結(jié)構(gòu)時(shí)往往需要對原方案重新設(shè)計(jì),缺乏通用性。
另一類是通過引入一層IR 來橋接語言差異。De Rose[10]和Reis[11]等人通過基于SSA(Static Single Assignment)的IR,分別實(shí)現(xiàn)了MATLAB 到Fortran 90 和C 代碼的轉(zhuǎn)換和優(yōu)化;石學(xué)林[12]等人引入了兩層IR來實(shí)現(xiàn)Cobol 到Java 代碼的自動(dòng)轉(zhuǎn)換器;Zhao[13]、Paulsen[14]等人分別通過基于AST 的IR 實(shí)現(xiàn)了PHP和MATLAB 到C++的自動(dòng)轉(zhuǎn)換。這類方法使用IR作為原語言和目標(biāo)語言之間的接口,存儲語言中的數(shù)據(jù)結(jié)構(gòu)和語法結(jié)構(gòu)信息,從而避免依賴特定語言,當(dāng)某一語言的轉(zhuǎn)換需求發(fā)生變更時(shí)只需要改動(dòng)其與中間層的轉(zhuǎn)換關(guān)系即可,避免對整個(gè)轉(zhuǎn)換框架做較大改動(dòng)。而且在IR 中可以存儲代碼信息,方便后續(xù)的分析和優(yōu)化。但是多引入一層IR 會帶來額外工作量,需要選擇合適的IR 以及生成方法。
在MATLAB 代碼轉(zhuǎn)換中針對如何將高性能運(yùn)算轉(zhuǎn)換到C 代碼的問題也有相應(yīng)的研究。Banerjee[15]等人的方法是使用目標(biāo)語言開發(fā)相應(yīng)的接口,該方法工作量較大,難以應(yīng)對需求變化,且轉(zhuǎn)換后代碼難以保證高性能;Paulsen[14]使用Armadillo 庫中的函數(shù)來替換相對應(yīng)的MATLAB 函數(shù),能有效避免轉(zhuǎn)換困難,但是存在轉(zhuǎn)換后代碼性能問題,同時(shí),對非函數(shù)形式的表達(dá)式的轉(zhuǎn)換也有所欠缺。對此,需要設(shè)計(jì)相應(yīng)的算法解決。
另外,商用的工具如MATLAB Coder[16]還沒有公開的實(shí)現(xiàn)方法。
目前已有許多針對高級語言的矩陣型變量的類型識別研究。Schwartz[2]通過對高級語言SETL 做數(shù)據(jù)流分析,獲取程序上下文中向量的長度信息并生成相應(yīng)的優(yōu)化代碼;Chatterjee[3]在VCODE 編譯器中實(shí)現(xiàn)了對向量的長度推斷;Joisha[4]、Chevalier-Boisvert[5]和Bispo[6]等分別在MATLAB 的優(yōu)化或轉(zhuǎn)換工作中對矩陣變量的類型信息進(jìn)行了推斷。這些方法的推斷過程基本上是通過代碼中入口函數(shù)的參數(shù)對代碼語句進(jìn)行數(shù)據(jù)流分析,逐條推導(dǎo)表達(dá)式結(jié)果變量的類型信息。推導(dǎo)方法可以應(yīng)用于本文的研究中。
本文的研究中引入了一層中間表示(Intermediate Representation,IR)來避免對語言特征的依賴,該IR以AST 為基礎(chǔ)構(gòu)建。AST 是源代碼語法結(jié)構(gòu)的一種抽象表示,以樹狀的方式呈現(xiàn),其中每個(gè)節(jié)點(diǎn)表示源代碼中的一個(gè)結(jié)構(gòu),一個(gè)AST 的示例如圖1 所示。AST 被廣泛應(yīng)用于代碼編譯等領(lǐng)域。
圖1 表達(dá)式y(tǒng)=1+2*x 的AST
在構(gòu)建C 代碼時(shí),需要對變量先聲明后使用,所以需要知道相應(yīng)MATLAB 變量的類型信息,本文將這些信息存儲到AST 中代表矩陣變量的節(jié)點(diǎn)中,從而構(gòu)成以AST 為基礎(chǔ)的IR。從源代碼生成AST需要對代碼進(jìn)行語法分析,大部分研究中都是手動(dòng)實(shí)現(xiàn)這一過程,是一項(xiàng)繁瑣的工作。本文使用ANTLR(ANother Tool for Language Recognition)來實(shí)現(xiàn)。ANTLR是一款強(qiáng)大的語法分析器生成工具,可用于讀取、處理、執(zhí)行和翻譯結(jié)構(gòu)化的文本或二進(jìn)制文件,被廣泛應(yīng)用于學(xué)術(shù)領(lǐng)域和工業(yè)生產(chǎn)實(shí)踐,是眾多語言、工具和框架的基石[17]。使用ANTLR 生成MATLAB的語法分析器后,就能進(jìn)一步生成AST。
與編譯器技術(shù)中IR 會深入到底層表示不同,本文的IR 層只是概念模型,MATLAB 代碼轉(zhuǎn)換到IR 后會直接轉(zhuǎn)換到C 代碼,不涉及更底層的語言,減少了轉(zhuǎn)換的層次。
由于引入了IR 層,需要分別將MATLAB 代碼轉(zhuǎn)換到IR 以及將IR 轉(zhuǎn)換到C 代碼,將這兩個(gè)階段的工作劃分為前端轉(zhuǎn)換模塊和后端轉(zhuǎn)換模塊,通過中間層模塊連接起來。
在前端轉(zhuǎn)換模塊中,需要從MATLAB 代碼生成AST,并識別代碼中矩陣變量類型信息。上述工作分別劃分給AST 生成模塊、矩陣大小推導(dǎo)模塊和矩陣元素類型推導(dǎo)模塊。
后端轉(zhuǎn)換模塊中,需要對IR 中的AST 進(jìn)行遍歷,轉(zhuǎn)換為相應(yīng)的C 代碼。該過程中的矢量運(yùn)算和函數(shù)調(diào)用需要使用MKL 庫中相同功能的C 函數(shù)進(jìn)行替換生成相應(yīng)代碼段。上述工作分別劃分給解析模塊和替換模塊。
各模塊及其子模塊的關(guān)系如圖2 所示。
圖2 系統(tǒng)功能模塊劃分
圖3 系統(tǒng)處理流程
系統(tǒng)將MATLAB 代碼轉(zhuǎn)換為C 代碼的工作流程如圖3 所示。首先輸入待轉(zhuǎn)換的MATLAB 代碼文件,進(jìn)入到前端轉(zhuǎn)換階段,該階段第一步是將MATLAB代碼經(jīng)過詞法和語法解析后生成AST,然后添加MATLAB 代碼的輸入?yún)?shù)矩陣信息,通過AST 結(jié)合輸入信息推導(dǎo)出其他矩陣變量的大小和元素類型信息,加入到AST 中得到IR。然后進(jìn)入到后端轉(zhuǎn)換階段,對IR 進(jìn)行解析,將每個(gè)AST 節(jié)點(diǎn)轉(zhuǎn)換為相應(yīng)的C 代碼結(jié)構(gòu),并輸出為相應(yīng)的C 代碼。同時(shí),對代表矢量運(yùn)算和函數(shù)調(diào)用的節(jié)點(diǎn),將其交由替換模塊處理,輸出相應(yīng)的MKL 庫函數(shù)。最終得到高性能的C 代碼文件。
2.3.1 前端轉(zhuǎn)換模塊實(shí)現(xiàn)
下面說明前端轉(zhuǎn)換模塊中三個(gè)子模塊的設(shè)計(jì)與實(shí)現(xiàn)。
(1)AST 生成模塊實(shí)現(xiàn)。本文使用ANTLR 來實(shí)現(xiàn)MATLAB 的詞法和語法分析器。使用ANTLR 時(shí)需要提供待處理語言的語法文件,通過閱讀MATLAB文檔,編寫出MATLAB 的語法文件,圖4 是該語法文件的部分示例。
圖4 MATLAB 語法文件部分示例
(2)矩陣大小推導(dǎo)模塊實(shí)現(xiàn)。矩陣大小的推導(dǎo)方法是根據(jù)矩陣運(yùn)算以及MATLAB 函數(shù)的規(guī)則來制定的。首先是矩陣運(yùn)算,當(dāng)知道參與運(yùn)算的矩陣大小以及運(yùn)算符,就可以推導(dǎo)出結(jié)果矩陣的大小,比如兩矩陣A 和B 相乘,結(jié)果矩陣的行數(shù)為A 的行數(shù),列數(shù)為B 的列數(shù)。這些矩陣運(yùn)算的規(guī)則有限,可以實(shí)現(xiàn)到代碼流程中。
對于函數(shù)調(diào)用,新產(chǎn)生的矩陣的大小與參數(shù)矩陣的大小和函數(shù)有關(guān),可以通過這樣一個(gè)三元組來定義:<函數(shù)名,參數(shù)矩陣大小,輸出矩陣大?。?,即函數(shù)名和參數(shù)矩陣大小可以確定輸出矩陣的大小。為便于管理和擴(kuò)展,將這些規(guī)則按照三元組形式寫入到文件中構(gòu)成規(guī)則文件,推導(dǎo)模塊在遇到函數(shù)調(diào)用時(shí)通過規(guī)則文件查詢相應(yīng)的規(guī)則。當(dāng)待處理的MATLAB 代碼中出現(xiàn)新的函數(shù)調(diào)用時(shí),在規(guī)則文件中加入新的規(guī)則即可。
有了上述推導(dǎo)方法,在給出MATLAB 代碼輸入?yún)?shù)矩陣的大小之后,對2.1 節(jié)中生成的AST 進(jìn)行遍歷,對其中遇到的計(jì)算節(jié)點(diǎn)和函數(shù)調(diào)用節(jié)點(diǎn)推導(dǎo)結(jié)果矩陣的大小,遍歷完成后就能得到所有矩陣變量的大小并存儲到相應(yīng)的矩陣變量節(jié)點(diǎn)中。
MATLAB 代碼入口輸入?yún)?shù)矩陣的大小信息通過一個(gè)三元組來定義:<矩陣名,行數(shù),列數(shù)>,將所有輸入?yún)?shù)矩陣的大小按照三元組形式寫入到文件中,提供給推導(dǎo)模塊使用。
(3)矩陣元素類型推導(dǎo)模塊實(shí)現(xiàn)。在MATLAB中,矩陣的元素可以有多種數(shù)據(jù)類型,具體如表1所示。
表1 MATLAB 數(shù)據(jù)類型
MATLAB 規(guī)定了矩陣運(yùn)算時(shí),結(jié)果矩陣的元素?cái)?shù)據(jù)類型與運(yùn)算數(shù)的元素?cái)?shù)據(jù)類型的關(guān)系,規(guī)則如下:①如果運(yùn)算數(shù)中含有整數(shù)矩陣,其他運(yùn)算數(shù)也必須是同一類型的整數(shù)矩陣,或者是雙精度的浮點(diǎn)數(shù)標(biāo)量,而結(jié)果仍然是原整數(shù)型;②浮點(diǎn)數(shù)運(yùn)算時(shí),如果運(yùn)算數(shù)中有單精度矩陣,那么結(jié)果矩陣也是單精度的。這兩個(gè)有限的規(guī)則實(shí)現(xiàn)到代碼流程中。對于函數(shù)調(diào)用的輸出矩陣元素類型規(guī)則,同前文一樣,定義為一個(gè)三元組:<函數(shù)名,參數(shù)矩陣元素類型,輸出矩陣元素類型>,通過文件的方式提供給推導(dǎo)模塊。
矩陣元素類型推導(dǎo)過程與前文中矩陣大小推導(dǎo)過程相似,也是對AST 進(jìn)行遍歷,同時(shí)進(jìn)行推導(dǎo)。該過程需要輸入?yún)?shù)矩陣的元素類型信息,通過一個(gè)二元組來定義:<矩陣名,元素類型>。將所有輸入?yún)?shù)矩陣的元素類型按照二元組形式寫入到文件中,提供給推導(dǎo)模塊使用。
2.3.2 后端轉(zhuǎn)換模塊實(shí)現(xiàn)
下面說明后端轉(zhuǎn)換模塊中兩個(gè)子模塊的設(shè)計(jì)與實(shí)現(xiàn)。
(1)解析模塊實(shí)現(xiàn)。解析模塊的工作是對IR 中的AST 進(jìn)行遍歷并生成相應(yīng)的C 代碼。MATLAB 語句生成對應(yīng)的C 語句時(shí),由于變量需要聲明,因此先定義MATLAB 變量類型在C 中的映射規(guī)則。
MATLAB 中的矩陣使用C 中的數(shù)組進(jìn)行模擬。一個(gè)大小為m×n 的矩陣在C 中定義為一個(gè)長度為m×n 的數(shù)組。一行一列的矩陣是特例,在C 中當(dāng)做一個(gè)標(biāo)量來定義。在本文使用的硬件平臺是32 位的情況下,MATLAB 的數(shù)據(jù)類型對應(yīng)的C 的數(shù)據(jù)類型總結(jié)于表2 中。
表2 MATLAB 數(shù)據(jù)類型對應(yīng)的C 數(shù)據(jù)類型
當(dāng)解析過程中發(fā)現(xiàn)新的變量時(shí),它的大小和數(shù)據(jù)類型已經(jīng)在前端轉(zhuǎn)換過程中被推導(dǎo)出來并存儲在IR 中的AST 節(jié)點(diǎn)中,將其聲明補(bǔ)充上即可。
在遍歷AST 的時(shí)候,當(dāng)前AST 節(jié)點(diǎn)決定應(yīng)該進(jìn)行的相應(yīng)操作。MATLAB 整體代碼生成的AST 的根節(jié)點(diǎn)應(yīng)該是語句塊,解析從該語句塊開始。解析過程的算法如下:
算法1:AST 解析算法
輸入:IR 中AST 根節(jié)點(diǎn)Root;
輸出:C 代碼。
其中,ASSIGNMENT 代表賦值語句類型,VEC_OP和FUNC_CALL 代表MATLAB 的矢量運(yùn)算和庫函數(shù)調(diào)用,IF 代表if 語句類型,LOOP 代表循環(huán)語句類型(for/while 循環(huán))。
(2)替換模塊實(shí)現(xiàn)。替換模塊的工作是將MATLAB中的矢量運(yùn)算和庫函數(shù)調(diào)用替換為MKL 庫函數(shù)形成的C 代碼段。首先是庫函數(shù)調(diào)用,可以在MKL 庫中尋找相應(yīng)功能的函數(shù)來進(jìn)行替換,這部分的替換較為簡單,替換規(guī)則與下文矢量運(yùn)算的替換規(guī)則一起考慮。
對于矢量運(yùn)算,首先考慮表達(dá)式不存在嵌套(即一個(gè)表達(dá)式只對應(yīng)一個(gè)MKL 函數(shù))的情況。替換的難點(diǎn)主要在于三方面:①確定矢量運(yùn)算所對應(yīng)的MKL 函數(shù);②同一個(gè)矢量運(yùn)算表達(dá)式由于矩陣類型不同會對應(yīng)不同的MKL 函數(shù)(一對多);③找到MKL函數(shù)后變量如何填入。
本文設(shè)計(jì)了一個(gè)匹配算法解決上述問題。首先定義MATLAB 語句替換為MKL 函數(shù)的替換規(guī)則,該規(guī)則通過一個(gè)三元組來定義:<MATLAB 語句模板,參數(shù)類型,MKL 庫函數(shù)模板>,并通過文件來管理和擴(kuò)展。對上述問題解決方法為:①M(fèi)ATLAB語句模板和參數(shù)類型共同匹配一個(gè)對應(yīng)的MKL 庫函數(shù),相應(yīng)的匹配算法解決了函數(shù)的確定問題;②參數(shù)類型也參與了函數(shù)的確定,為不同的參數(shù)類型添加新的替換規(guī)則,來解決一對多的問題;③規(guī)則中使用的是模板語句,參數(shù)使用占位符,當(dāng)輸出具體的C 語句時(shí)才根據(jù)實(shí)際代碼中的變量名來替換。
匹配算法根據(jù)實(shí)際語句的AST(下稱“SAST”)與MATLAB 語句模板的AST(下稱“TAST”)進(jìn) 行。替換模塊初始時(shí)會讀取替換規(guī)則文件并將MATLAB 語句模板轉(zhuǎn)換為TAST。判斷AST 是否相同即是判斷樹結(jié)構(gòu)是否相同,當(dāng)前的節(jié)點(diǎn)類型相同并且子樹也相同時(shí)說明AST 相同,可以通過對AST 做遍歷完成。在該過程中,變量獲取以及類型信息判斷較為簡單,在算法說明中略去。
如果考慮表達(dá)式存在嵌套,則需要在AST 匹配失敗時(shí)對嵌套的表達(dá)式先輸出對應(yīng)MKL 函數(shù),然后相應(yīng)修改AST,之后繼續(xù)匹配,直到輸出最終結(jié)果。匹配算法如下:
算法2:匹配算法
輸入:SAST 和替換規(guī)則文件;
輸出:MKL 庫函數(shù)調(diào)用語句。
該算法是遞歸的,這是由于表達(dá)式的嵌套(如加法和乘法混合等)。嵌套部分將被提取出來輸出對應(yīng)的MKL 庫函數(shù)調(diào)用語句,然后修改AST,再重新進(jìn)行匹配,直到完成匹配過程,算法在第4 行結(jié)束。嵌套的情況舉例如圖5 所示,表達(dá)式y(tǒng)=a+b-c中(a、b、c 均為長為n 的向量),a+b 的結(jié)果先存放到臨時(shí)變量t 中并輸出相應(yīng)的MKL 函數(shù)語句,然后AST 中用新節(jié)點(diǎn)t 替換子樹,重新匹配y=t-c 得到最終結(jié)果。
圖5 嵌套運(yùn)算匹配示例
本文測試轉(zhuǎn)換系統(tǒng)對MATLAB 代碼轉(zhuǎn)換生成C代碼的正確性以及性能。由于MATLAB 在科學(xué)計(jì)算和數(shù)據(jù)挖掘等方面有著廣泛應(yīng)用,本文選取迭代法解線性方程組和K-means 聚類算法的MATLAB 程序來測試系統(tǒng)。測試1(迭代法求方程組解)分別測試解100、200、400 階線性方程組的時(shí)間,測試2(K-means 聚類算法)分別測試將100、200、400 個(gè)四維點(diǎn)劃分為4 個(gè)聚類的時(shí)間。C 程序的數(shù)據(jù)精度均為double。
生成的C 程序運(yùn)行的硬件環(huán)境為:Intel Core i7-8550U,1.80 GHz,4 核8 處理器CPU;8.0 GB 內(nèi)存。
為了測試本文系統(tǒng)轉(zhuǎn)換生成的C 代碼的正確性以及與人工編寫代碼的性能對比,使用專家級水平的人工代碼進(jìn)行對比測試。本文系統(tǒng)轉(zhuǎn)換生成的C 代碼與人工編寫的C 代碼均使用MKL 函數(shù)庫。對兩個(gè)測試用例,運(yùn)行系統(tǒng)轉(zhuǎn)換生成的C 代碼和人工編寫的C 代碼,使用相同的輸入,兩者的運(yùn)行結(jié)果一致,說明了本文系統(tǒng)能生成正確的C 代碼。
兩個(gè)C 程序在測試用例上的運(yùn)行耗時(shí)如表3和表4 所示。
表3 與人工編寫代碼對比測試1 結(jié)果
表4 與人工編寫代碼對比測試2 結(jié)果
由結(jié)果可以看出,系統(tǒng)轉(zhuǎn)換生成的代碼運(yùn)行時(shí)間和專家級水平的人工代碼運(yùn)行時(shí)間相差不多,排除運(yùn)行環(huán)境浮動(dòng)干擾帶來的誤差,兩者的性能相當(dāng)。本文的系統(tǒng)可以幫助開發(fā)人員將MATLAB 代碼轉(zhuǎn)換到性能更好的C 代碼上,并提供相當(dāng)于專家級水平的人編寫的代碼性能,降低開發(fā)成本。
選擇兩個(gè)已有方法將MATLAB 轉(zhuǎn)換生成C++代碼,這兩個(gè)方法生成的C++代碼實(shí)際上并未使用較多C++特有的頭文件,因此將其與本文的C 代碼進(jìn)行比較。第一個(gè)是MATLAB Coder,使用時(shí)需要指定矩陣變量的元素類型和大小,針對不同的測試需要生成多份C 代碼。第二個(gè)是文獻(xiàn)[14]中的matlab2cpp,使用過程中需要根據(jù)它的自定義規(guī)則將部分不能自動(dòng)轉(zhuǎn)換的代碼段替換為正確的C 代碼段。生成的代碼運(yùn)行耗時(shí)測試結(jié)果如表5 和表6 所示,其中本文方法的結(jié)果沿用3.2 節(jié)中的數(shù)據(jù)。
表5 與已有方法對比測試1 結(jié)果
表6 與已有方法對比測試2 結(jié)果
結(jié)果表明,MATLAB Coder 轉(zhuǎn)換生成的C 代碼的性能最差,以它的運(yùn)行時(shí)間為基準(zhǔn),matlab2cpp 和本文方法對它的加速比如表7 所示。
表7 測試結(jié)果相比于MATLAB Coder 的加速比
結(jié)果顯示本文方法生成的C 代碼的性能略優(yōu)于matlab2cpp,兩者的效果均優(yōu)于MATLAB Coder。對MATLAB Coder 生成的C 代碼分析可以得知,MATLAB Coder 基本上是將MATLAB 代碼中的矢量運(yùn)算以及庫函數(shù)展開為循環(huán),這樣C 代碼的性能對比使用了性能庫的C 代碼性能顯著較差。而matlab2cpp使用了armadillo 庫來提供大部分MATLAB 矢量運(yùn)算和庫函數(shù)的轉(zhuǎn)換,該庫的語法與MATLAB 相似,在轉(zhuǎn)換上能提供部分便利性,且該庫底層也集成了高性能的線性代數(shù)庫,但是由于該庫對底層的封裝,在性能上會帶來部分損失。同時(shí),matlab2cpp 也不能保證轉(zhuǎn)換的完全自動(dòng)化,因?yàn)閍rmadillo 庫對于MATLAB中部分矢量運(yùn)算和庫函數(shù)有所缺失。而本文通過對矢量運(yùn)算和庫函數(shù)設(shè)計(jì)的替換算法能夠保證轉(zhuǎn)換的自動(dòng)化以及擴(kuò)展性,同時(shí)轉(zhuǎn)換后的C 代碼性能在MKL 的提升下也能優(yōu)于已有的方法。
本文設(shè)計(jì)并實(shí)現(xiàn)了一個(gè)MATLAB 代碼自動(dòng)轉(zhuǎn)換到高性能C 代碼的系統(tǒng)。針對大部分自動(dòng)轉(zhuǎn)換方法對特定語言依賴較大的問題,本文引入IR 層,并將系統(tǒng)的整體框架分為前端轉(zhuǎn)換模塊、中間層模塊和后端轉(zhuǎn)換模塊三大模塊進(jìn)行實(shí)現(xiàn),對傳統(tǒng)方法中存在的一些問題作出了改進(jìn)。實(shí)驗(yàn)結(jié)果表明,該系統(tǒng)自動(dòng)生成的高性能C 代碼性能與專家級水平的人工實(shí)現(xiàn)的相當(dāng),且優(yōu)于已有的方法。
目前,該系統(tǒng)只支持MATLAB 代碼的矩陣運(yùn)算代碼轉(zhuǎn)換,對于含更高維度的矢量代碼轉(zhuǎn)換還未實(shí)現(xiàn),并且轉(zhuǎn)換后的C 代碼僅支持使用MKL 庫提升性能,局限性較大,這是本文進(jìn)一步的研究方向。