亚洲免费av电影一区二区三区,日韩爱爱视频,51精品视频一区二区三区,91视频爱爱,日韩欧美在线播放视频,中文字幕少妇AV,亚洲电影中文字幕,久久久久亚洲av成人网址,久久综合视频网站,国产在线不卡免费播放

        ?

        基于晶格Boltzmann方法的CUDA加速優(yōu)化

        2022-10-26 04:29:42張乾毅韋華健赫軼男李華兵
        桂林電子科技大學學報 2022年3期
        關鍵詞:格點內(nèi)核線程

        張乾毅, 韋華健, 赫軼男, 李華兵

        (桂林電子科技大學 材料科學與工程學院,廣西 桂林 541004)

        隨著處理器時鐘頻率極限及“功耗墻”等問題的出現(xiàn),單核解決方案被摒棄,基于多核架構的圖像處理單元(GPU)逐漸出現(xiàn)在人們的視野中。2007年,英偉達公司為GPU增加了一個易用的編程接口——統(tǒng)一計算架構(compute unified device architecture,簡稱CUDA)[1]。它以標準C為基礎進行擴展,使程序員可以在C、C++及Fortran等開發(fā)環(huán)境進行并行程序編寫,將利用GPU進行并行計算的門檻大大降低。近年來,人工智能在深度學習的不斷推動下高速發(fā)展,這離不開GPU的強大計算能力和優(yōu)秀的GPU編程環(huán)境。CUDA技術已經(jīng)獲得廣泛關注,并被應用到流體力學、生物計算、氣象分析、金融分析等眾多領域。

        晶格玻爾茲曼方法(LBM)是一種介觀尺度的模擬方法,在流體力學方面的模擬中被廣泛應用,如多孔介質(zhì)流[2]、血液流[3]、多相流[4]淋巴流[5]等。LBM物理背景清晰,易于并行計算,邊界條件處理簡單,因而十分適用于大規(guī)模GPU并行計算。如T?lke等[6]使用CUDA實現(xiàn)了LBM多孔介質(zhì)流動模型的計算加速。鄭彥奎等[7]實現(xiàn)了LBM方腔模型的計算加速。

        鑒于此,通過線性尋址和下標尋址方法實現(xiàn)了LBM模型中的泊松流算例。將程序分別用CPU和GPU進行計算,比較2種尋址方法分別在2種處理單元上的計算時間,并算得加速比。

        1 GPU與CUDA

        基于設計目標的差異,GPU在設備架構上與CPU存在很大區(qū)別。CPU需要很強的通用性來處理各種不同的數(shù)據(jù)類型,同時邏輯判斷又會引入大量的分支跳轉(zhuǎn)和中斷處理。因此,CPU中分布著多樣的計算、控制單元和占據(jù)大量空間的存儲單元。而GPU的設計主要是用來解決大量邏輯上相對簡單的任務,因而GPU采用了數(shù)量眾多的核心和算術邏輯單元(ALU),其數(shù)量遠超CPU,通常CPU的核心數(shù)不會超過2位數(shù),但GPU只配備了簡單的控制邏輯和簡化了的存儲單元。

        CUDA編程模型將CPU作為主機端,GPU作為設備端,二者各自擁有相互獨立的存儲地址空間:主機端內(nèi)存和設備端顯存。一個典型的CUDA程序包括并行代碼和與其互補的串行代碼。由CPU執(zhí)行復雜邏輯處理和事務處理等不適合數(shù)據(jù)并行的串行代碼,并調(diào)用GPU計算密集型的大規(guī)模數(shù)據(jù)并行計算代碼,即內(nèi)核函數(shù)。當設備端開始執(zhí)行內(nèi)核函數(shù)時,設備中會產(chǎn)生大量的線程,線程是內(nèi)核函數(shù)的基本單元,負責執(zhí)行內(nèi)核函數(shù)的指定語句[8]。CUDA程序模型如圖1所示,由一個內(nèi)核啟動所產(chǎn)生的所有線程統(tǒng)稱為一個線程網(wǎng)格,同一網(wǎng)格中的所有線程共享相同的全局內(nèi)存空間。一個網(wǎng)格又由多個線程塊構成,同一線程塊內(nèi)的線程協(xié)作可通過同步和共享內(nèi)存的方式實現(xiàn),不同塊內(nèi)的線程不能協(xié)作。每個GPU設備包含一組流多處理器(SM),一個SM又由多個流處理器(SP)和一些其他硬件組成。CUDA程序執(zhí)行過程中會把線程塊中的所有線程以線程束(Warp,含32個線程)為執(zhí)行單位分配給SM中的不同SP來進行計算。

        圖1 CUDA程序模型

        GPU采用了內(nèi)存分層架構,并通過多級緩存機制來提高讀寫效率。CUDA內(nèi)存模型如圖2所示,GPU中主要的內(nèi)存空間包括寄存器、共享內(nèi)存、全局內(nèi)存、常量內(nèi)存、紋理內(nèi)存和本地內(nèi)存。每個SM都擁有獨立的一級緩存,所有SM共享二級緩存。GPU致力于為每個線程分配真實的寄存器,當寄存器使用到達上限時,編譯器會將數(shù)據(jù)放在片外的本地內(nèi)存中。共享內(nèi)存是可受程序員控制的一級緩存,每個SM中的一級緩存與共享內(nèi)存公用同一個內(nèi)存段[9],它僅對正在執(zhí)行的線程塊中的每個線程可見。

        圖2 CUDA內(nèi)存模型

        2 晶格玻爾茲曼方法(LBM)

        McNamara等[10]用單粒子分布函數(shù)fi取代了格子氣細胞自動機中的布爾變量,其LBM演化方程為

        fi(x+eiδt,t+δt)-fi(x,t)=Ω(fi),

        (1)

        其中:i為微觀速度的索引,對于D2Q9模型,i取值1~9;fi(x,t)為在x位置t時刻具有ei速度的粒子的分布函數(shù);δt為時間增量;Ω(fi)為碰撞因子,表示碰撞對于fi的影響。文獻[11-13]采用單弛豫時間來替代碰撞因子項。繼而,LBM方程可寫為

        (2)

        其中:fi(eq)為局域平衡分布函數(shù);τ為弛豫時間。求出粒子分布函數(shù)后,則宏觀密度、流體的流速分別為

        (3)

        (4)

        采用圖3所示的D2Q9模型(D指維度,Q指粒子運動方向總數(shù))模型[14]進行計算,其平衡分布函數(shù)具體定義為

        圖3 D2Q9模型

        (5)

        其中:c為基準速度,通常情況下取1;ωi為各方向的權重系數(shù)。當i=0時,ωi=4/9;當i=1,2,3,4時,ωi=1/9;當i=5,6,7,8時,ωi=1/36。ei的形式為

        3 算法實現(xiàn)及優(yōu)化

        一個典型的LBM計算案例主要分為3個步驟:1)聲明變量并進行分布函數(shù)的初始化;2)進行格點的碰撞、遷徙流動和邊界處理,并進行宏觀量的計算;3)進行穩(wěn)定性條件判斷,決定是否結束步驟2)的迭代。由文獻[15]知,步驟2)的迭代計算占整個計算時間的98%,因此該步驟應在GPU上進行并行加速。本計算以淋巴管為物理背景,將淋巴管內(nèi)流動的淋巴液視作等截面圓形管道內(nèi)的泊松流,進行模擬計算。嘗試用線性尋址和下標尋址2種不同的尋址方法進行計算,比較這2種尋址方法分別在GPU與CPU上執(zhí)行計算時間的差異。

        3.1 線性尋址程序設計

        LBM的基本變量是分布函數(shù),進而由分布函數(shù)計算求得格子點的密度和x、y方向上的速度等宏觀量。在串行程序的D2Q9模型中,分布函數(shù)通常被設為三維數(shù)組df[i][j][k]并存儲在主存中,i、j表示整個線程網(wǎng)格中格點的坐標(0≤i≤width,0≤j≤height;width、height均為固定值,分別表示線程網(wǎng)格的寬度和高度),k為格點運動方向數(shù),k=0,1,…,8。

        在設備端聲明指針double*df,調(diào)用cudaMallocManaged()函數(shù)在設備端開辟大小為width*height*9*sizeof(double)的一維線性內(nèi)存空間,用于存放每個格點上9個方向的分布函數(shù),并將在顯存上獲得的內(nèi)存空間首地址賦值給df。使用cudaMallocManaged()函數(shù)開辟的存儲空間,無論是在串行代碼中還是并行代碼中,都可使用這塊內(nèi)存,因此只需定義一個指針即可在主機和設備端通用。繼續(xù)開辟多個設備端內(nèi)存空間,用于存放其他計算變量的數(shù)據(jù)。指針double *dd指向存儲格子點密度的內(nèi)存空間,指針double *dvx、*dvy分別指向存放x和y方向上速度的內(nèi)存空間。

        基于上述在全局內(nèi)存中使用三維數(shù)組來儲存分布函數(shù)及其他變量的方式,設計了3個在CPU端執(zhí)行的collide()、stream()、calculate()函數(shù),分別代表格點的碰撞、遷徙流動和宏觀量的計算等步驟,并將其命名為方案一。方案二則是將迭代計算過程放在GPU端并行執(zhí)行,對應設計了addKernelCollide()、addKernelCopy()、addKernelStream()、addKernelCalculate()四個內(nèi)核函數(shù)來實現(xiàn)。相較于方案一中執(zhí)行各個步驟都需要嵌套for循環(huán)來遍歷讀寫每個格點上的數(shù)據(jù),方案二則通過內(nèi)核函數(shù)用GPU映射出大量線程,同時對每個格點數(shù)據(jù)進行操作。

        首先,調(diào)用cudaMallocManaged()函數(shù),在GPU端為分布函數(shù)、密度等變量開辟內(nèi)存空間,再定義一個parameter結構體,為之后格子點遷徙流動做鋪墊。對4個內(nèi)核函數(shù)進行如下討論:

        1)碰撞步:啟動addKernelCollide<<>>(df,iSol,…,dev_p)內(nèi)核函數(shù),其中grid為線程網(wǎng)格中線程塊數(shù),將其設為width;block為每個線程塊中的線程數(shù),設為9*height;iSol為用于判斷格點是否位于邊界上的變量;dev_p為parameter結構體變量。聲明變量i、j、k并賦值,i=blockIdx.x,j=threadIdx.y,k=threadIdx.x。在函數(shù)體內(nèi)分別計算出線程訪問分布函數(shù)一維數(shù)組的下標索引id=adr(i,j,k)=k+(j+i* height)*9和其他變量的下標索引ind=adr(i,j)=j+i* i*height。通過一次if判斷,保留格子邊界以外的所有格子點進行計算,每個線程利用式(2)計算對應格子點的分布函數(shù):

        df[id]=df[id]-(df[id]-

        feq(k,dd[ind],dvx[ind],dvy[ind]))/Tau。

        feq()為平衡分布函數(shù),Tau為弛豫時間。

        2)流動遷徙步:啟動addKernelCopy<<>(df,dfbak)內(nèi)核函數(shù),聲明變量并賦值,計算出線程訪問的下標索引,方法同上。將df[id]中的數(shù)據(jù)傳遞給dfbak[id]。啟動addKernelStream<<>>(df,dfbak,iSol,…)內(nèi)核函數(shù),將dfbak[id]的值賦給df[id],此時dfbak[id]中

        id=k+[(j-dev_Prjy[k])+(i-

        dev_Prjx[k])*height)]*9。

        3)計算宏觀量步:啟動addKernelCalculate<<>>(df,iSol,…)內(nèi)核函數(shù),聲明變量并放入共享內(nèi)存中。

        __shared__ double sdf[9];//9個分布函數(shù)

        __shared__ double ddd;//格子點密度

        __shared__ double vx;//x方向速度

        __shared__ double vy;//y方向速度

        ……

        for(k=0;k<9;k++)

        {

        sdf[k]=df[adr(i,j,k)];

        }

        利用sdf[k]計算得到ddd、vx、vy的值,最后將共享內(nèi)存中的數(shù)據(jù)傳回主存中。

        3.2 下標尋址程序設計

        基于之前的線性尋址方法對程序做以下修改。

        1)聲明指針double *df0、double **df1、double ***df,在GPU上開辟3個內(nèi)存空間,并將首地址分別賦值給df0、df1、df,具體操作如下:

        cudaMallocManaged(void(**)&df0,width*height*9*sizeof(double));

        cudaMallocManaged(void(**)&df1,width*height*sizeof(double*));

        for(i=0;i

        {

        for(j=0;j

        {df1[i*height+j]=&df0[(i*height+j)*9];}

        }

        cudaMallocManaged(void(**)&df,width*height*sizeof(double**));

        for(i=0;i

        {df[i]=&df1[i*height];}

        2)聲明指針double *dd0、double **dd,在GPU上開辟2次內(nèi)存空間,并將首地址分別賦值給dd0、dd,具體操作如下:

        cudaMallocManaged(void(**)&dd0,width*height*sizeof(double));

        cudaMallocManaged(void(**)&dd,width*sizeof(double*));

        for(i=0;i

        {dd[i]=&dd0[i*height];}

        3)其他宏觀量修改方法同上。

        在各計算步驟中,用多維數(shù)組表示不同格點位置上的分布函數(shù)和其他宏觀量,形如df[i][j][k]、dd[i][j]、dvx[i][j]、dvy[i][j]。將方案一、二按上述內(nèi)容進行修改,并分別命名為方案三、四。

        4 計算結果分析

        采用含有8個Nvidia Quadro GP100顯卡集群的服務器完成計算,GP100顯卡擁有3 584個CUDA并行計算處理核心,處理雙精度浮點數(shù)的能力為5.2 TFlop/s,搭配16 GiB HBM2顯存,理論帶寬高達717 GiB/s。同時服務器搭載了Intel(R) Xeon(R)CPU E-52620 v4處理器,核心數(shù)為8個,主頻為2.1 GHz,編譯環(huán)境為CUDA10.0,運行環(huán)境為Linux Ubuntu。

        表1 4種泊松流模擬方案運行時間

        以平面泊松流為算例,在保證計算結果正確性的前提下驗證2種尋址方法對程序計算時間的影響。圖4為4種方案迭代4 000步時的模擬結果,4種方案結果一致,表明了程序修改的正確性。表1為迭代4 000步時,4種方案模擬的計算時間。從表1可看出,基于線性尋址方式的方案一、二,GPU相對CPU的加速比約為71倍,而基于下標尋址方法的加速比只有約25倍;方案一、三都用CPU完成迭代計算步,方案三的計算時間減少了將近三分之二,因而使用下標尋址的方式更適合CPU端的迭代計算;方案二、四計算時間無太大變化,表明下標尋址對GPU端的并行計算無明顯幫助。

        圖4 4種泊松流模擬方案結果

        5 結束語

        采用CUDA實現(xiàn)了LBM的泊松流算例。設計了線性尋址、下標尋址2種尋址方法,并實現(xiàn)了這2種尋址方法分別在主機端和設備端上的4種LBM計算方案。4種方案計算結果一致,表明了程序設計的正確性。用線性尋址方法獲得了71倍的加速比,表明用CUDA對LBM計算效率的提升有很大幫助,也展現(xiàn)了GPU在大規(guī)??茖W計算中的巨大潛力。

        猜你喜歡
        格點內(nèi)核線程
        帶有超二次位勢無限格點上的基態(tài)行波解
        萬物皆可IP的時代,我們當夯實的IP內(nèi)核是什么?
        一種電離層TEC格點預測模型
        強化『高新』內(nèi)核 打造農(nóng)業(yè)『硅谷』
        基于嵌入式Linux內(nèi)核的自恢復設計
        Linux內(nèi)核mmap保護機制研究
        帶可加噪聲的非自治隨機Boussinesq格點方程的隨機吸引子
        淺談linux多線程協(xié)作
        格點和面積
        Linux線程實現(xiàn)技術研究
        无码无套少妇毛多18pxxxx| 用力草我小逼视频在线播放| 久久久人妻精品一区bav| 无码人妻一区二区三区免费看| 国产性生交xxxxx免费| 国产va精品免费观看| 亚洲伊人av综合福利| 午夜影视免费| 午夜成人理论无码电影在线播放 | 麻豆国产人妻欲求不满| 久久精品国产久精国产69| 日韩av一区二区三区精品久久 | 加勒比黑人在线| av男人天堂网在线观看| 久久国产人妻一区二区| 免费人成视频x8x8| 亚洲AV无码乱码精品国产草莓| 国产日产亚洲系列首页| 国产色在线 | 日韩| 最好看2019高清中文字幕视频| 不打码在线观看一区二区三区视频 | 亚洲综合自拍| 色婷婷一区二区三区77| 亚洲av日韩av激情亚洲| 亚洲欧洲偷自拍图片区| 国产成人香蕉久久久久| 美女露出奶头扒开内裤的视频| 韩国三级中文字幕hd| 欧美日本国产三级在线| 久久老熟女乱色一区二区| 噜噜噜噜私人影院| 少妇spa推油被扣高潮| 国产女主播强伦视频网站| 亚洲香蕉av一区二区三区| 双腿张开被9个男人调教| 国产在线观看黄| 亚洲一区二区蜜桃视频| 99久久精品免费观看国产| 可以免费在线看黄的网站| 亚洲视频在线免费观看一区二区| 大地资源在线影视播放|