向量化的方法.doc_第1頁
向量化的方法.doc_第2頁
向量化的方法.doc_第3頁
向量化的方法.doc_第4頁
向量化的方法.doc_第5頁
已閱讀5頁,還剩3頁未讀 繼續免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

使用英特爾編譯器進行自動向量化 作者:Yang Wang (Intel)自動向量化是英特爾編譯器提供的一個可以自動的使用SIMD指示的功能。 在處理數據時, 編譯器自動選擇MMX, Intel Streaming SIMD 擴展(Intel SSE, SSE2, SSE3 和SSE4)等指令集, 對數據進行并行的處理。 使用編譯器提供的自動向量化功能是提高程序性能的一個非常有效的手段。自動向量化在IA-32和Intel 64的平臺上均提供很好的支持。英特爾編譯器提供的自動向量化相關的編譯選項如下所示。”/Q”開頭的選項是針對Windows平臺的, “-“開頭的選項是針對Linux*和Mac平臺的。-x, /Qx按照該選項指定的處理器類型生成相應的優化代碼。 比如-xSSE3, 該選項指定編譯器生成Intel SSE3指令的代碼。 又比如-xSSE3_ATOM, 該選項針對Intel Atom 處理器進行優化。-ax, /Qax如果指定該選項, 在生成的單一目標文件中, 不但會生成專門針對指定的處理器類型進行優化的代碼, 同時也生成通用的IA-32架構的代碼。 該選項主要是為了生成代碼的兼容性考慮。-vec, /Qvec打開或者關閉編譯器的向量化優化。 默認情況下自動向量化是打開的。-vec-report, /Qvec-report該選項用戶控制在編譯過程中產生的向量化消息報告。編譯器提供的自動向量化優化默認情況下是打開的。 在編譯過程中我們可以使用-vec-report選項來打開向量化診斷消息報告。 這樣編譯器可以告訴我們有哪些循環被向量化了, 有哪些循環沒有被向量化已經無法向量化的原因。在編譯程序的過程中, 有時候我們會發現編譯器報告說某個循環無法被向量化。 很多時候無法向量化的原因都是因為循環中存在的變量依賴關系。 有時候我們可以修改程序來消除這種依賴關系,有的時候我們可以使用編譯器提供的一些編譯指示來顯示的告訴編譯器如何處理這種依賴關系。 即使在某個循環已經可以被自動向量化的時候, 使用編譯器提供的對向量化的語言支持和編譯指示還可以提高編譯器向量化的效率, 提高程序執行的性能。下面我們來詳細解釋一下編譯器提供的編譯指示以及這些指示對編譯器編譯的影響。在Intel編譯器中, 我們提供下面這樣一些對自動向量化的語言支持和編譯指示。_declspec(align(n)指導編譯器將變量按照n字節對齊_declspec(align(n,off)指導編譯器將變量按照n字節再加上off字節的編譯量進行對齊restrict消除別名分析中的二義性_assume_aligned(a,n)當編譯器無法獲取對齊信息時,假定數組a已經按照n字節對齊#pragma ivdep提示編譯器忽略可能存在的向量依賴關系#pragma vector aligned|unaligned|always指定向量化的方式#pragma novector指定不做向量化下面我們就這些編譯指示做一些詳細的了解。 _declspec(align(n)首先我們來看看如何使用_declspec(align(n)來進行自動向量化。該指示主要是用來告訴編譯器一個變量的對齊方式。 當一個變量的對齊方式為16字節對齊時, 生成的向量化指令是最高效的。 當編譯器不知道一個變量的對齊方式的時候, 他可能沒有辦法對該變量的使用進行向量化, 或者編譯器會不得不生成條件語句來進行有條件的向量化。 我們來看一下下面這個例子。File: vec1.cchar a;void vec1(void)int i;for(i=0;i1024;i+)ai = 1;使用下面命令編譯該程序:icl vec1.c -O2 -c /Qvec-report:3這時編譯器輸出:vec1.cvec1.c(10) (col. 2): remark: LOOP WAS VECTORIZED.我們可以看到編譯器對上面這個程序進行了自動向量化。 但是實際上, 由于編譯器不知道a的對齊字節數, 所以他對變量a數據進行了一些條件處理。 我們可以在編譯的時候加上-S選項來查看編譯器生成的匯編代碼。 實際上, 編譯器對該程序做了如下處理:temp = a&0x0f;if(temp != 0)temp = 16-temp;for(i=0;itemp;i+) ai = 1;/*下面是對齊的訪問*/for(i=temp;i1024;i+) ai = 1;如果我們指定了a的對齊方式, 比如我們使用_declspec(align(16)來定義變量a, 如下所示:_declspec(align(16) char a;void vec1(void)int i;for(i=0;i1024;i+)ai = 1;對于上面這段程序, 編譯器做了自動向量化。 如果我們檢查生成的匯編代碼可以發現,對于a的對齊方式的條件處理代碼已經不見了。正確使用_declspec(align(n)以及其他align相關編譯指示可以幫助編譯器進行自動向量化以及提高編譯器自動向量化的效率。 restrict使用restrict關鍵字可以顯式的告訴編譯器取消指針之間的二義性。 我們還是用下面這個例子來說明restrict的使用。File: vec2.cvoid vec2(char* a, char* b, int n)int i;for(i=0;in;i+)ai = bi;使用以下命令進行編譯:icl vec2.c -O2 -c /Qvec-report:3編譯器輸出:vec2.crestrict.c(5) (col. 2): remark: LOOP WAS VECTORIZED.restrict.c(5) (col. 2): remark: loop skipped: multiversioned.此時編譯器輸出multiversioned向量化代碼, 對同一個循環產生了多個版本的實現。實際上編譯器對代碼進行了條件處理, 如下所示:void vec2(char* a, char* b, int n)int i;if(a+nb | b+na)for(i=0;in;i+) ai = bi; /*向量化循環*/elsefor(i=0;in;i+) ai = bi; /*串行循環*/可以看出,由于編譯器不知道指針a 和b之間是否存在重疊, 所以他對循環進行了條件處理。 如果我們從語義上能夠保證a和b是不會發生重疊的, 那么我們就可以使用restrict關鍵字來顯式的告訴編譯器這一點。void vec2(char* restrict a, char* restrict b, int n)int i;for(i=0;in;i+)ai = bi;此時編譯器輸出沒有multiversioned。restrict.crestrict.c(5) (col. 2): remark: LOOP WAS VECTORIZED.注意C90里面不支持restrict關鍵字, 在windows平臺編譯的時候我們需要加上選項/Qrestrict來讓編譯器認識restrict關鍵字。 #pragma vector使用#pragma vector編譯指示來顯式告訴編譯器使用某種方式來進行自動向量化。 比如在下面這個例子中, 我們可以保證變量a的地址是16字節對齊的,那么我們就可以使用#pragma vector aligned來顯式的告訴編譯器不需要考慮非對齊的情況。這樣產生的向量化代碼是最高效的。File: vec3.c#include void vec3(void)int i;char* a=_aligned_malloc(1024, 16);#pragma vector alignedfor(i=0;i1024;i+)ai = 1;在上面這個例子中, 如果我們不加上#pragma vector aligned, 編譯器會對循環進行條件處理后的向量化。 大家可以對比一下兩種情況下生成的匯編代碼的區別。請注意我們在使用#pragma vector aligned的時候需要保證被處理變量的對齊方式是16字節對齊的, 否則在使用了該編譯指示后可能會產生錯誤的結果。在上面這個例子中, 我們稍作如下修改:#include void vec3(void)int i;char* a=_aligned_malloc(1024, 16);char* b = a+1;#pragma vector alignedfor(i=0;i1023;i+)bi = 1;循環中的b的地址不是16字節對齊的, 但是如果我們還是按照aligned的方式來做向量化, 產生的結果是編譯出來的可執行程序運行時異常。 在上面的例子中, 我們需要使用#pragma vector unaligned 編譯指示來正確的引導編譯器。 #pragma ivdep使用#pragma ivdep顯式的告訴編譯器忽略向量之間可能存在的依賴關系。參考下面這個例子。File: vec4.cvoid vec4(int* a, unsigned int n, unsigned int m)int i;for(i=0;in;i+)ai = ai+m;使用編譯器編譯該程序:icl vec4.c O2 -c /Qvec-report:3編譯器輸出:vec4.cvec4.c(6) (col. 2): remark: loop was not vectorized: existence ofvector dependence.vec4.c(7) (col. 3): remark: vector dependence: assumed ANTI dependence between a line 7 and a line 7.vec4.c(7) (col. 3): remark: vector dependence: assumed FLOW dependence between a line 7 and a line 7.vec4.c(7) (col. 3): remark: vector dependence: assumed FLOW dependence between a line 7 and a line 7.vec4.c(7) (col. 3): remark: vector dependence: assumed ANTI dependence between a line 7 and a line 7.如果我們可以保證a0到an-1和am到am+n-1之間不存在重疊, 那么我們就可以使用#pragma ivdep來顯式的告訴編譯器可以忽略ai和ai+m之間的依賴關系, 修改程序如下:void vec4(int* a, unsigned int n, unsigned int m)int i;#pragma ivdepfor(i=0;i Compiler Options. Many library routines that are part of Intel Compiler are more highly optimized for Intel microprocessors than for other microprocessors. While the compilers and libraries in Intel Compiler offer optimizations for both Intel and Intel-compatible microprocessors, depending on the options you select, your code and other factors, you likely will get extra performance on Intel microprocessors.While the paragraph above describes the basic optimization approach for Intel Compiler, with respect to Intels compilers and associated libraries as a whole, Intel Compiler may or may not optimize to the same degree for non-Intel microprocessors for optimizations that are not unique to Intel microprocessors. These optimizations include Intel Streaming SIMD Extensions 2 (Intel SSE2), Intel Streaming SIMD Extensions 3 (Intel SSE3), and Supplemental Streaming SIMD Extensions 3 (Intel SSSE3) instruction sets and other optimizations. Intel does not guarantee the availability, functionality, or effectiveness of any optimization on microprocessors not manufactured by Intel. Microprocessor-dependent optimizations in this product are intended for use with Intel microprocessors.Intel recommends that you evaluate other compilers to determine which best meet your requirements.使用#pragma simd進行自動向量化#pragma simd該編譯指示(SIMD)是12.0編譯器最新提供的功能。他可以強制性的讓編譯器做自動并行化。 對于其他編譯指示比如#pragma ivdep來說, 如果編譯器編譯時發現用戶提供的編譯指示條件不滿足, 那么編譯器是不會根據編譯指示來進行自動向量化的。也就是說, 編譯器實際上還是會進行編譯時的依賴關系檢查。 而對于#pargam simd來說, 無論編譯時條件如何, 編譯器總是會進行自動向量化。這種情況下, 用戶需要自己去保證被向量化的循環上語義的正確性, 需要自己保證被向量化變量之間的依賴關系的正確性。我們用一個例子來說明編譯器的行為區別。File vec5.cvoid vec5(int* a, int n)int i;for(i=0;in;i+)ai = ai-1;對上面這個例子, 由于存在flow-dependence關系, 程序中的循環明顯是不能被向量化的。vec5.cC:testvec5.c(6) (col. 2): remark: loop was not vectorized: existence of vector dependence.C:testvec5.c(7) (col. 3): remark: vector dependence: assumed FLOW dependence between a line 7 and a line 7.此時我們加上#pragma ivdep想讓編譯器忽略循環之間的依賴關系(當然這種操作是不符合原始語義的)。void vec5(int* a, int n)int i;#pragma ivdepfor(i=0;in;i+)ai = ai-1;這時編譯該程序, 程序的輸出與不加#pragma ivdep時相同。 編譯器在進行編譯的時候檢查發現了循環之間不可避免的依賴關系, 即使有#pragma ivdep存在, 編譯器也還是不會對該循環進行向量化。如果我們加上#pragma simd, 重新編譯程序:void vec5(int* a, int n)int i;#pragma simdfor(i=0;in;i+)ai = ai-1;這時編譯輸出:vec5.cC:testvec5.c(6) (col. 2): remark: SIMD LOOP WAS VECTORIZED.程序中的循環被向量化了, 但是此時我們顯然不會得到一個正確的結果。我們再看一個用SIMD的正確的例子。 比如下面這個程序:void vec5(int* a, int n, int m)int i;for(i=0;in;i+)ai = ai-m;編譯該程序: icl /O2 /c /Qvec_report:3, 編譯器會報告該程序因為存在向量依賴關系而不能被向量化。在該程序中, 如果我們可以保證m大于等于4, 那么我們可以加入#pragma simd指示如下所示:void vec5(int* a, int n, int m)int i;#prgama simdfor(i=0;i Compiler Options. Many library routines that are part of Intel Compiler are more highly optimized for Intel microprocessors than for other microprocessors. While the compilers and libraries in Intel Compiler offer optimizations for both Intel and Intel-compatible microprocessors, depending on the options you select, your code and other factors, you likely will get extra performance on Intel microprocessors.While the paragraph above describes t

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論