MIC C編程(offload模式)

MIC C編程(offload模式)

編程特點

簡單---隱藏大量細節,語法與OpenMPI類似(不需要開闢空間)

靈活---OpenMP MPI(但是用的不多)pThread等多種方式

傳統---CPU編程一脈相承

 

MIC C擴展語言結構

編譯指導方式(#pragma

offload

--表示之後的代碼段將使用offload模式運行

  運行在其他設備上(MIC

--標識內存傳遞參數,傳遞過程對用戶透明

  不需要手動寫代碼控制何時傳入、何時傳出

  不需要手動申請卡上內存空間

  不需要講卡上內存與主機端內存空間手動對應

 

簡單示例

#pragma offload target(mic)

for(i=0;i<LEN;i++)

{

printf(“Index:%d\n”,i);

}

循環和printf語句在MIC上執行,沒有數據傳輸

此時循環是串行的,因爲沒有並行引語

 

 

offload語法

#pragma offload specifier[,specifier...]

specifier

示例

含義

target

target(mic:0)

使用什麼設備運行

if

if(N>1000)

是否使用該設備

in

in(p:length(LEN) alloc_if(1))

數據傳入device

out

out(p:length(LEN))

數據從device傳出

inout

inout(p:length(LEN) align(8))

數據既傳入又傳出

nocopy

nocopy(p)

只開闢空間不傳遞

signal

signal(tag)

發送信號

wait

wait(tag1,tag2)

等待信號

mandatory

mandatory

必須用MIC運行

 

 

 

 

 

 

其中in/out/inout/nocopy可用的屬性有

屬性

示例

含義

length

length(LEN)

元素個數

alloc_if

alloc_if(1)

是否開闢內存

free_if

free_if(N>0)

offload後是否釋放

align

align(8)

對齊

alloc

alloc(p[10:100])

開闢數組一部分

into

into(p[10:100])

傳遞數組一部分

 

 

 

語法詳解target

#pragma offload target(mic)  mic這裏目前只支持MIC

--這是必須使用的屬性

--表示下面的代碼段使用MIC運行

--現階段,target的參數只支持“mic

--使用哪塊卡,由驅動決定,如果系統沒有MIC卡,則使用CPU運行
target(mic:num)

--num>=-1;當爲-1時,系統自動選擇一塊mic卡,如果1號卡不存在或者有故障,則程序報錯退出

--設備號=num%mic數量(也就是說num可以大於mic卡數,循環的)

 

語法詳解in

#pragma offload target(mic) in(array)  --傳入CPU中的array,不負責傳出

--可選屬性

--可附加lengthalloc_iffree_ifalignallocinto屬性

--表示進入offload區域時,將數組arrayCPU內存中傳遞到MIC內存中,只傳入不傳出

--只需要傳遞數組,標量會自動以inout方式傳遞

 

 

語法詳解out/inout/nocopy

可選屬性

in基本相似

out表示離開offload區域時,將數組arrayMIC內存傳遞到CPU內存,只傳出不傳入

inout表示進入offload區域時,將數組從CPU內存傳輸到MIC內存,離開時將數組傳回

nocopy表示僅開闢或保留空間,不傳輸數據

注意事項:

array是靜態聲明時,不用加長度參數

array是動態開闢時(堆),需要加長度參數length

array長度相同,或靜態聲明時,可以在一個傳輸區域內傳輸多個。例:in(a,b)

默認進入offload時開闢內存,離開時釋放

in/out/inout/nocopy在一句offload中可以出現多次,但每個數組名只能出現一次

 

 

傳輸屬性詳解length

傳輸數組的元素個數,非數組長度!

只能使用在動態開闢的數組中

數組長度相同時可以共用

示例:

float *pArray,*pArray1;

pArray=(float*)malloc(LEN*sizeof(float));

pArray1=(float*)malloc(LEN*sizeof(float));

#pragma offload target \

in(pArray,pArray1:length(LEN))   共用啦

{……}

 

 

傳輸屬性詳解alloc_if,free_if

控制是否在傳輸前開闢卡上內存空間和傳完是否釋放

常結合nocopy屬性應用

例:

#pragma offload target \

in(pArray:length(LEN) free_if(0))  裏面是boolean型,“0”表示不釋放空間

//進入下一個offload時,pArray的數據仍然存在(計算完後pArray存在於MIC中,不需要再從CPU端傳輸多MIC端了)

#pragma offload target \

nocopy(pArray:length(LEN) alloc_if(0)) 不用再釋放空間了,也不用in再次傳輸了

//此時不需要開闢空間,否則會覆蓋原有數據

 

(這裏優化點:1:傳輸 2:開闢 3:釋放)

 

數據傳輸優化Nocopy

p_c=...//p_c在每次迭代中值不變

for(i=0;i<steps;i++) //迭代次數

{

p_in=...;//每次迭代計算時,p_in的值變化

#pragma offload target(mic) \

in(p_in:length(...)) in(p_c:length(...)) out(p_out:lenth(...))

{

kernel(p_in,p_c,p_out);

}

}

...=p_out;//CPU端在所有迭代完成之後纔用到p_out的值

 

這裏的冗餘是p_c冗餘傳入p_out冗餘輸出

 

優化方案:

p_c=...;//p_c在每次迭代中值不改變

#pragma offload target(mic) \

in(p_c:length(...) alloc_if(1) free_if(0)) \  //開闢不釋放

nocopy(p_in:length(...) alloc_if(1) free_if(0)) \

nocopy(p_out:length(...) alloc_if(1) free_if(0))

{

}//申請空間,並且不釋放,傳遞p_c的值

for(i=0;i<steps;i++){//迭代多次

p_in=...;

#pragma offload target(mic) \

in(p_in:length(...) alloc_if(0) free_if(0)) \   //p_in省去了steps次的開闢釋放空間

nocopy(p_c) nocopy(p_out)   //這裏p_c省去了輸入,p_out省去了輸出

{

kernel(p_in,p_c,p_out);

}}

//以下是把最後的p_out輸出來

#pragma offload target(mic) \

nocopy(p_c:length(...) alloc_if(0) free_if(1)) \

nocopy(p_in:length(...) alloc_if(0) free_if(1)) \

out(p_out:length(...) alloc_if(0) free_if(1))

{...}

...=p_out

 

傳輸屬性詳解align

控制卡上內存開闢的對齊大小

單位爲字節

內存不對齊時會影響性能

一般用於傳輸不規則的結構體(定義順序)

 

 

傳輸屬性詳解alloc/into

alloc開闢卡上內存,大小爲數組的一部分

into傳輸數據,大小爲數組的一部分

不能與inout/nocopy同用

 

傳輸屬性特殊用法

#pragma offload target \

in(p[10:100]:alloc(p[5:1000]))

在設備開闢了1000個元素的數組p,數組下表的可用範圍是從5開始,即5-10004.然後將主機端從p[10]開始的100個元素傳到設備端的p[10]-p[109]的位置(mic卡上)

需要程序員保證不會越界

 

#pragma offload ... \

in(p[0:500]:into(p1[500:500]))

將主機端p[0]開始的500個元素的值,複製到設備端p1[500]-p1[999]的響應位置

如果同一offload語句有多個into,執行順序未知,因此需要注意目的數組範圍不能重疊

into不是簡單拷貝,維度不同不能傳輸

 

語法詳解signal/wait

#pragma offload target(mic) signal(tag)

可選屬性,異步傳輸

等同於offload_transfer/offload_wait,但後者爲單一語句,後面不跟代碼段

在傳輸語句時加signalCPU不等待MIC運行結束即繼續運行。知道遇到wait語句

wait語句等待signal語句傳輸完成再繼續運行

參數爲一個變量或者數組名(即使同事傳遞多個)

示例:

float *in1;

#pragma offload target(mic:0) signal(in1)

{

mic_compute();

}

cpu_compute(); //本函數與上面的MIC函數並行執行

#pragma offload_wait target(mic:0) wait(in1)  //這裏與MIC合流

 

offload+OpenMP

offload語句作用範圍內使用OpenMp,即可在MIC上並行計算

例:

#pragma offload target(mic) out(arr:length(LEN))

#pragma omp parallel for

for(i=0;i<LEN;++i)

{

arr[i]=i*3.0/x;

}

 

變量和函數聲明

_declspec(target(mic))

_attribute_((target(mic)))

修飾後,變量和函數可同時用於CPUMIC,二者等價,attribute時注意有兩層括號

例:

_attribute_((target(mic))) int a;

-attribute_((target(mic))) void fun();

 

變量和函數聲明(批量)

同時聲明多個變量和函數

兩種形式

#pragma offload_attribute(push,target(mic))

//函數或變量聲明

#pragma offload_attribute(pop)

或者:

#pragma offload_attribute(target(mic))

//函數或變量聲明

#pragma offload_attribute(target(none))

 

判斷代碼段是否運行在MIC

檢查是否定義了宏_MIC_

#ifdef_MIC_

...

#else

...

#endif

需要封裝在函數中,而不能直接用於offload代碼段

_attribute_((target(mic))) void offload_check(void)

{

#ifdef _MIC_

printf(“check func:Run on the mic!\n”);

#else

printf(“check func:Run on the cpu!\n”);

#endif

}

 

語法詳解if

#pragma offload target(mic) if(flag)  //flag boolean型的

可選屬性

如果flag爲真,則使用MIC執行代碼段,否則使用CPU執行

例:#pragma offload target(mic) if(N>100)

表示如果N大於100就在MIC卡上執行

可用於不同規模數據,或者CPUMIC協同計算的情況

 

語法詳解mandatory

可選屬性

沒有參數

強制下面的代碼段在MIC上運行,如果MIC設備不可用,則報錯退出--不去CPU上跑

多用於必須在MIC上運行的代碼,例如使用SIMD寫的代碼段

 

程序編譯

使用Intel編譯器

編譯選項與原CPU程序完全一樣

如果只想使用CPU,添加選項”-no-offload”

如果使用了OpenMP,添加選項”-openmp” (如果不加此選項,就在mic的單核上運行)

 

 

 

 

發佈了31 篇原創文章 · 獲贊 11 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章