劉士謙
(廣州海格通信集團(tuán)股份有限公司,廣東 廣州 510663)
隨著5G技術(shù)的日益成熟和廣泛應(yīng)用,人們正高速地邁入一個(gè)手機(jī)、可穿戴設(shè)備乃至智能家用電器等設(shè)備都能夠?qū)崿F(xiàn)彼此互聯(lián),并產(chǎn)生海量信息交互數(shù)據(jù)的數(shù)字化世界。面對(duì)海量信息數(shù)據(jù)的大量涌現(xiàn),圖形處理器GPU憑借其極強(qiáng)的并行計(jì)算處理能力,代替數(shù)字信號(hào)處理器DSP組成GPU+CPU架構(gòu)的平臺(tái)。該架構(gòu)平臺(tái)為現(xiàn)代無(wú)線接入網(wǎng)設(shè)備的信號(hào)處理提供了一種理想的技術(shù)手段。在GPU+CPU平臺(tái)架構(gòu)中,如何有效地跟蹤調(diào)試GPU的運(yùn)行信息,成為GPU程序開發(fā)中必須解決的一個(gè)問(wèn)題。
當(dāng)前計(jì)算機(jī)處理器主要分為中央處理器CPU和圖形處理器GPU兩大類。在傳統(tǒng)的計(jì)算機(jī)架構(gòu)中,GPU只負(fù)責(zé)圖形渲染,大部分的處理都交由CPU完成。
由于圖形渲染的高度并行性,使得GPU可以通過(guò)增加并行處理單元和存儲(chǔ)器控制單元的方式來(lái)提高運(yùn)算處理能力和存儲(chǔ)器帶寬。相對(duì)于CPU而言,它將更多的晶體管用作執(zhí)行單元,從而大大地提高了計(jì)算能力。從而令GPU在處理能力和存儲(chǔ)帶寬上相對(duì)CPU有著非常明顯的優(yōu)勢(shì),在成本和功耗上也不需要付出太大的代價(jià),為提升計(jì)算速度、計(jì)算能力提供了新的解決方案[1]。
為了推廣GPU的應(yīng)用,英偉達(dá)公司于2007年推出了統(tǒng)一計(jì)算設(shè)備架構(gòu)(Compute Unified Device Architecture,CUDA)這一易用編程接口。CUDA是C語(yǔ)言的一種擴(kuò)展,集成了一些CUDA的內(nèi)置應(yīng)用編程接口,它允許使用標(biāo)準(zhǔn)的C語(yǔ)言來(lái)進(jìn)行GPU代碼編程。編寫的代碼既適用于CPU,也適用于GPU[2]。
CUDA編程模型將CPU作為主機(jī)(Host),GPU作為設(shè)備處理器(Device)。Host和若干個(gè)Device協(xié)同工作,Host負(fù)責(zé)執(zhí)行控制部分以及串行運(yùn)算;Device則專注于執(zhí)行高度線程化的并行處理部分。一旦確定了程序中的并行部分,就可以考慮把這部分的計(jì)算任務(wù)分配給Device來(lái)執(zhí)行,運(yùn)行在Device上的CUDA并行計(jì)算函數(shù)稱為核函數(shù)(kernel),一個(gè)完整的CUDA程序由一系列的設(shè)備端kernel函數(shù)和主機(jī)端的串行處理部分共同組成。由于CUDA的易用性,已經(jīng)得到了很多硬件廠商的支持,正逐漸成為首個(gè)有可能發(fā)展成為GPU開發(fā)的候選編程語(yǔ)言[3]。
在GPU+CPU平臺(tái)架構(gòu)中,跟蹤記錄GPU運(yùn)行信息最恰當(dāng)?shù)臅r(shí)間點(diǎn)是在CPU將相關(guān)數(shù)據(jù)交予GPU側(cè)進(jìn)行運(yùn)算處理時(shí),對(duì)輸入及輸出的指令和數(shù)據(jù)進(jìn)行實(shí)時(shí)的跟蹤記錄。為此,在設(shè)備CPU側(cè)的系統(tǒng)軟件中設(shè)計(jì)添加一個(gè)名為GPU Trace的功能模塊,用于記錄相關(guān)的GPU數(shù)據(jù)信息。由于在CPU側(cè)調(diào)用GPU進(jìn)行運(yùn)算處理的軟件功能模塊數(shù)量眾多,本GPU Trace模塊被設(shè)計(jì)劃分為server和client兩部分。其中server部分在設(shè)備啟動(dòng)過(guò)程中,與其他的各個(gè)軟件功能模塊一同由啟動(dòng)腳本先后創(chuàng)建運(yùn)行;client部分則以動(dòng)態(tài)庫(kù)的形式,提供用于跟蹤記錄GPU運(yùn)行信息的接口。各個(gè)調(diào)用GPU進(jìn)行運(yùn)算處理的軟件功能模塊,通過(guò)調(diào)用client部分提供的函數(shù)接口,將需要記錄的GPU運(yùn)行信息數(shù)據(jù)交由server部分進(jìn)行統(tǒng)一的存儲(chǔ)記錄。
GPU Trace模塊server部分程序運(yùn)行流程如圖1所示。當(dāng)GPU Trace模塊中server部分在被創(chuàng)建,并完成對(duì)設(shè)備當(dāng)前GPU Trace記錄的檢索后,阻塞等待由client發(fā)所送過(guò)來(lái)的帶有Trace數(shù)據(jù)句柄的消息。當(dāng)server接收到帶有Trace數(shù)據(jù)句柄的消息,并通過(guò)句柄獲取到所需要的GPU Trace數(shù)據(jù)后,記錄Trace數(shù)據(jù)信息并更新相關(guān)的Trace信息描述記錄。
圖1 模塊server程序運(yùn)行流程
為了確保記錄的實(shí)時(shí)性,GPU Trace功能模塊在內(nèi)存中開辟了一塊存儲(chǔ)空間用以記錄GPU運(yùn)行信息。該存儲(chǔ)空間由GPU Trace目錄和GPU Trace記錄數(shù)據(jù)兩部分組成。GPU Trace目錄部分,主要用于記錄存儲(chǔ)空間的內(nèi)存地址、當(dāng)前GPU Trace記錄序號(hào)、存儲(chǔ)空間使用情況等信息。GPU Trace記錄數(shù)據(jù)部分,除了GPU運(yùn)行數(shù)據(jù)記錄之外,每一條Trace記錄的Record Head還記錄著Trace的序號(hào)、長(zhǎng)度、是由哪個(gè)模塊申請(qǐng),以及執(zhí)行Trace記錄操作的時(shí)間和代碼的位置。GPU Trace記錄數(shù)據(jù)部分采用循環(huán)的形式進(jìn)行存儲(chǔ),當(dāng)存儲(chǔ)空間不足或耗盡時(shí),新的GPU的運(yùn)行記錄信息將會(huì)覆蓋最早的記錄信息。
在設(shè)備運(yùn)行過(guò)程中,各個(gè)需要記錄GPU運(yùn)行信息的軟件功能模塊,通過(guò)調(diào)用GPU Trace模塊中client端的GPU Trace函數(shù)向server端發(fā)送帶有Trace數(shù)據(jù)句柄的消息。該函數(shù)主要代碼如下:
cudaIpcGetMemHandle(&handle, (void *)devPtr);
msg.gpu_msg.handle=handle;
msg.gpu_msg.length=size;memcpy(msg.gpu_msg.module_tag, module_tag, 10);
snprintf(msg.gpu_msg.file, 20, "%s", filename(file));
msg.gpu_msg.line=line;msg_send(&msg, server_mbox, MSG_MY_MBOX);
GPU Trace模塊server端在接收到帶有Trace數(shù)據(jù)句柄的消息后,通過(guò)調(diào)用Fetch_GPU_Data函數(shù)獲得需 要記錄的GPU數(shù)據(jù)。然后將GPU數(shù)據(jù)與client端發(fā)送過(guò)來(lái)的Record Head信息,一同存儲(chǔ)到在內(nèi)存中開辟的GPU Trace存儲(chǔ)空間中的GPU Trace記錄數(shù)據(jù)部分。Fetch_GPU_Data函數(shù)的主要代碼如下:
cudaIpcOpenMemHandle ( devPtr, Handle, cudaIpcMemLazyEnablePeerAccess);
cudaMemcpy ( buff, devPtr, length, cudaMemcpyDeviceToHost);
cudaIpcCloseMemHandle(devPtr);
本文基于CUDA編程接口,設(shè)計(jì)了一款GPU Trace模塊,實(shí)現(xiàn)了在GPU+CPU平臺(tái)架構(gòu)中CPU側(cè)對(duì)GPU運(yùn)行數(shù)據(jù)的獲取和記錄。該GPU Trace模塊為在采用GPU+CPU平臺(tái)架構(gòu)的現(xiàn)代無(wú)線接入網(wǎng)設(shè)備中,跟蹤調(diào)試GPU的運(yùn)行信息提供了一種實(shí)時(shí)高效的技術(shù)手段。