青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

asm, c, c++ are my all
-- Core In Computer
posts - 139,  comments - 123,  trackbacks - 0
[轉]用SIMD指令優化程序之拋磚引玉

小談
CPU 緩存體系

  現在的 CPU 依舊采用馮諾伊曼體系,喜歡像傻子一樣從頭執行到尾,中途沒有任何的跳轉停頓等待。可是現實情況是,大部分程序里面還是少不了 IF ELSE 之類的判斷,循環就更加得多了。如何優化循環大家可以自己琢磨,其實不難,可以參考一下《高質量 C\C++ 編程指南》

  現在 CPU 上都有 Level 1 指令緩存(又叫做 L1 Trace )與 Level 1 數據緩存( L1 Data Cache )。 PMMX P2 P3 為二者都準備了 16kb ,我的 P4 Northwood (以下簡稱 P4NW )有 8kbL1 數據緩存和 12kb 指令緩存。 CPU 讀取 L1 Data Cache 中的數據只需要 1 個時鐘周期,速度非常快,應該是僅次于寄存器了。數據緩存是由 256 或者 512 32bytes 組成的,也就是 32bytes 對齊的,而 P4NW 64bytes 字節對齊的,并行 4 路,總共 128 行。當你處理的數據沒有載入緩存的時候, CPU 將從內存讀取緩存行大小的數據,所以緩存行總是對齊到能被 32 整除的物理地址。 CPU L1 數據緩存中的數據進行操作是最快速的。所以推薦內存地址最起碼是 32byte 對齊的。目前編譯器在這個地方的優化已經非常好了,一般都是 4byte 對齊,當然也都是 32 對齊的。在后面你將會看到, SSE2 要求數據是 16 字節對齊的。

?   緩存類似一個 C++ set 容器,但是不能賦值到一個任意的內存地址。每行本身都有 1 7bit 大小的關聯值( set value )要和目標內存地址的 5 11 位對應( 0-4 位已經忽略了),也可以理解為,關聯值是內存段地址的一部分。 PPro 中,有 128 個關聯值對應到 2 行,所以最多可以為任意的內存單元準備 2 個緩存行。 PMMX P2 P3 P4NW 4 個。由于內存是分段的,所以說 CPU 只能為, 5-11 位地址相同的內存準備 2 或者 4 個不同的緩存行。如何為兩個內存地址賦予相同的關聯值呢?把 2 個地址的低 5bit 去掉,這樣就能被 32 整除了。如果這 2 個截斷了的地址都是 4096 1000H )的倍數,那么這兩個地址就有了相同的關聯值。

?   讓我們用匯編加深一下印象,假設 ESI 中是 32 對齊的地址。

? ??????????????????????????????????????? AGAIN:? MOV? EAX,? [ESI]

MOV? EBX,? [ESI+13*4096+4]

MOV ?ECX,? [ESI+20*4096+28]

DEC? ?EDX

JNZ ??AGAIN

   Oh Year ,這里 3 個地址都有相同的關聯值,而且地址跨度都超過了數據緩存的大小,可這個循環在 PPro 上效率會相當低。當你想讀取 ECX 的值的時候,將沒有空閑的緩存行了 —— 因為共享一個關聯值,而且 2 行已經被使用了。此時 CPU 將騰出最近使用的 2 個緩存行,一個已經被 EAX 使用。然后 CPU 把這個緩存行用 [ESI+20*4096] [ESI+20*4096+31] 的內存數據填充,然后從緩存中讀取 ECX 。聽起來好象相當的煩瑣。更加糟糕的是,當又需要讀取 EAX 的時候,還需要重復上述的過程,需要對內存緩存來回操作,效率相當的低,甚至不如不用緩存。可是,如果我們把第三行改成:

MOV? ECX,? [ESI+20*4096+32]

  哦,不好,看起來,我們的地址超過了 32 ,不能被整除了。可是這樣有了不同的關聯值,也就意味著有了 1 個新行,不再共享可憐的 2 個行。這樣一來,對三個寄存器的操作就不需要反復的用 2 個緩存行進行調度了,各有一個了。嘿嘿,這次只需要 3 個時鐘周期了,而上一個要 60 個周期。這是在 PPro 上的,在后來的 CPU 中都是 4 路的,也就不存在上面的問題了。搞笑的是, Intel 的文檔卻錯誤的說 P2 的緩存是 2 路的。雖然說很少人在用那么古老的 CPU ,可是其中的道理大家應該明白。

  可是判斷要訪問的部分數據是否有相同的關聯值,也就是關于緩存是否能夠命中的問題,是相當困難的,匯編還好,用高等級語言編譯過的程序鬼知道是否對緩存做過優化呢。所以么,推薦,在程序的核心部分,對性能要求最高的部分,先對齊數據,然后確保使用的單個數據塊不要超過緩存大小, 2 個數據塊,單個不要超過緩存大小的一半(仔細想想為什么,因為關聯值的問題,可以緩存分為兩部分處理兩塊)。可是大部分情況下,我們都是使用遠比數據緩存大的多的結構,以及編譯器自己返回的指針,然后為了優化你可能希望把所有頻繁使用的變量放到一個連續的數據塊中以充分利用緩存。我們可以這樣做,把靜態變量數值拷貝到棧中的局部變量中,等子函數或者循環結束后再拷貝回來。這樣一來就相當于把靜態變量放入了連續的地址空間中去。

當讀取的數據不在 L1 Cache 內時, CPU 將要從 L2 Cache 讀取 L1 緩存行大小的數據到 L1 里去,大概需要 200ns 的時間(也就是 100Mhz 系統的 20 個時鐘周期),但是直到你能夠使用這些數據前,又需要有 50-100ns 的延遲。最糟糕的是,如果數據也不在 L2 Cache 中,那么就只能從最慢速的內存里讀取了,內存的龜速哪能和全速的緩存相比。

好了,關于緩存的知識可以就此打住了,下面開始講如何優化緩存。無非就是 3 種方法,硬件預取( Prefetch )、軟件預取、使用緩存指令。關于預取的注意事項主要有這些:

<!--[if !supportLists]--> 1、? <!--[endif]--> 合理安排內存的數據,使用塊結構,提高緩存命中率。

<!--[if !supportLists]--> 2、? <!--[endif]--> 使用編譯器提供的預取指令。比如ICC中的_mm_prefetch _mm_stream,甚至_mm_load等比較“傳統”的指令。

<!--[if !supportLists]--> 3、? <!--[endif]--> 盡可能少的使用全局的變量或者指針。

<!--[if !supportLists]--> 4、? <!--[endif]--> 程序盡可能少的進行判斷跳轉循環。

<!--[if !supportLists]--> 5、? <!--[endif]--> 使用const標記,不要在代碼中混合register聲明。

不過要提醒一句,真正提高程序效率的方法不是那種,從頭到尾由于外科手術般的解剖,一個一個地方的優化,請抓住程序最核心的部分進行優化,記住 80-20 規則。

?

使用 SIMD

先復習一下對齊指令, __declspec(aliagn(#)) # 替換為字節數。比如想聲明一個 16 字結對齊的浮點數組, __declspec(aliagn(16)) float Array[128] 。需要注意的是,最好充分了解你 CPU 的類型,支持哪些指令集。 SIMD 主要使用在需要同時操作大量數據的工作領域,比如 3D 圖形處理(游戲),物理建模( CAD ),加密,以及科學計算領域。據我所知,目前 GPGPU 也是使用 SIMD 的代表之一。

MMX

主要特性: 57 條指令, 64bit FP 寄存器 MM0-MM7 ,對齊到 8 80bit FP 寄存器 ST0-ST7 。需要數據 8 字節對齊,也就是使用 Packed 數字。

PS :這里冒出了一個問題,為什么 Intel 要把 MMX 的寄存器和 FPU 的寄存器混合起來使用呢?因為這里牽涉到一個 FPU 狀態切換問題,后面會提到,當你在一段代碼中又要用到 MMX 指令又要用到傳統的 FPU 指令,那么需要保存 FPU 狀態,或者退出 MMX 。可是這種操作對于 FPU 來說非常昂貴,而且對于多任務操作系統來說,近乎于不可能完成的任務 —— 同時有許多程序,有些需要 MMX ,有些不需要,而正確地進行調度會變得非常困難。所以 Intel 將保存狀態的工作完全交給了 CPU 自己,軟件人員無須作太多這方面的工作,這樣一來,就向前向后兼容了多任務操作系統,比如 Windows Linux 。后來隨著操作系統和 CPU 的不斷升級,操作系統開發人員發布了一個補丁包,就可以讓操作系統使用新的寄存器。這時人們都發現 Intel 的這種做法是相當短視的,這可以當作一個重大的失誤。后來 Intel 通過引入了新的浮點指令集,這時才加入 XMM 寄存器。可造成這段故事的原因卻根本不是技術問題,保證兼容性也是一個方面,總之真的說不清楚。你只要記得無法同時使用 MMX FPU 就可以了, CPU 要進行模式切換。

SSE1

主要特性: 128bit FP 寄存器 XMM0-XMM7 。增加了數據預取指令。額外的 64bit 整數支持。支持同時處理 4 個單精度浮點數,也就是 C\C++ 里的 float

適用范圍:多媒體信號處理

SSE2

主要特性: 128bit FP 寄存器支持處理同時處理 2 個雙精度 double 浮點數,以及 16byte 8word 4dword 2quadword 整數。

適用范圍: 3D 處理 語音識別 視頻編碼解碼

SSE3

主要特性:增加支持非對稱 asymmetric 和水平 horizontal 計算的 SIMD 指令。為 SIMD 提供了一條特殊的寄存器 load 指令。線程同步指令。

適用范圍:科學計算 多線程程序

手頭工具

1 、選擇一個合適的編譯器,推薦用 Intel C++ Compiler (以下簡稱 ICC ),以及 Visual Studio .NET 2003 及以上 IDE 附帶的 C++ 編譯器。同時, Microsoft C++ Compiler 也支持 AMD 3DNow GCC C++ Compiler 沒有測試。

2 Intel 以及 AMD 的匯編指令集手冊。這個是必需的,強烈建議每個C++ Coder人手準備一份。

? 所有的都用 C++ 混合變成的方式實現

使用范例:

向量乘法在 3D 處理中非常非常多,多半用于計算單位矢量的夾角。

我們先定義一個頂點結構。

__declspec(align( 16 ))? struct ?Vertex{
????
float
?x,y,z,w;
};
??? 16字節對齊的結構,其實本身也是16字節的東西。如果沒有對齊,運行時會報錯。

w是其次坐標系的參數,處理向量的時候不需要用到。我的函數是這樣的:

float ?Dot(Vertex * ?v1,Vertex * ?v2)
{
????Vertex?tmp;
????__asm{
????????MOV?EAX,[v1];
????????MOVAPS?XMM0,[EAX];
????????MOV?EAX,[v2];
????????MOVAPS?XMM1,[EAX];
????????MULPS?XMM0,XMM1;
????????MOVAPS?tmp,XMM0;
????};
????
return ?tmp.x? + ?tmp.y? +
?tmp.z;
};

??? VC中反匯編之:
?1?float?Dot(Vertex*?v1,Vertex* ?v2)
?2?
{
?3?
0041C690??push????????ebx??
?4?
0041C691??mov?????????ebx,esp?
?5?0041C693??sub?????????esp,8
?
?6?
0041C696??and?????????esp,0FFFFFFF0h?
?7?0041C699??add?????????esp,4
?
?8?
0041C69C??push????????ebp??
?9?0041C69D??mov?????????ebp,dword?ptr?[ebx+4
]?
10?0041C6A0??mov?????????dword?ptr?[esp+4
],ebp?
11?
0041C6A4??mov?????????ebp,esp?
12?
0041C6A6??sub?????????esp,0E8h?
13?
0041C6AC??push????????esi??
14?
0041C6AD??push????????edi??
15?0041C6AE??lea?????????edi,[ebp-
0E8h]?
16?
0041C6B4??mov?????????ecx,3Ah?
17?
0041C6B9??mov?????????eax,0CCCCCCCCh?
18?
0041C6BE??rep?stos????dword?ptr?[edi]?
19?
????Vertex?tmp;
20?
????__asm{
21?
????????MOV?EAX,[v1];
22?
0041C6C0??mov?????????eax,dword?ptr?[v1]?
23?
????????MOVAPS?XMM0,[EAX];
24?
0041C6C3??movaps??????xmm0,xmmword?ptr?[eax]?
25?
????????MOV?EAX,[v2];
26?
0041C6C6??mov?????????eax,dword?ptr?[v2]?
27?
????????MOVAPS?XMM1,[EAX];
28?
0041C6C9??movaps??????xmm1,xmmword?ptr?[eax]?
29?
????????MULPS?XMM0,XMM1;
30?
0041C6CC??mulps???????xmm0,xmm1?
31?
????????MOVAPS?tmp,XMM0;
32?
0041C6CF??movaps??????xmmword?ptr?[tmp],xmm0?
33?
????};
34?????return?tmp.x?+?tmp.y?+
?tmp.z;
35?
0041C6D3??fld?????????dword?ptr?[tmp]?
36?0041C6D6??fadd????????dword?ptr?[ebp-
1Ch]?
37?0041C6D9??fadd????????dword?ptr?[ebp-
18h]?
38?};
??? 前面都是保護現場入Stack的代碼,沒有必要管。我之所以這樣,在Stack中聲明了一個零時變量返回之,是為了減少代碼的行數。有興趣地可以參考本文后面引用資料中的Intel范例,代碼多的多,功能卻一樣。這樣就可以利用SIMD計算點乘了。圖示:
??? 這種頂點格式稱為AoS(Array of structure),這種結構的好處是,能夠和現有的程序結構,比如D3D中的FVF頂點格式,和GL中的頂點格式。但是,由于許多情況下,并沒有使用第四各浮點數,這就讓SIMD指令浪費了25%的性能。于是有了SoA格式,讓我們重新來過。
??? 我借用了一下上面一個結構的指令,還是沒有用_mm_128格式,讓大家看得清楚一些:
__declspec(align( 16 ))? struct ?Vertex_soa{
?????
float ?x[ 4 ],y[ 4 ],z[ 4 ],w[ 4
];
};
??? 依舊16字節對齊。計算函數如下:
?1?void?Dot(Vertex_soa*?v1,Vertex*?v2,float* ?result)
?2?
{
?3?
????Vertex?tmp1,tmp2;
?4?
????__asm{
?5?
????????MOV?ECX,v1;
?6?
????????MOV?EDX,v2;
?7?

?8? ????????MOVAPS?XMM7,[ECX];
?9?????????MOVAPS?XMM6,[ECX+16
];
10?????????MOVAPS?XMM5,[ECX+32
];
11?????????MOVAPS?XMM4,[ECX+48
];
12?
????????MOVAPS?XMM0,XMM7;
13?
????????UNPCKLPS?XMM7,XMM6;
14?
????????MOVLPS?[EDX],XMM7;
15?????????MOVHPS?[EDX+16
],XMM7;
16?
????????UNPCKHPS?XMM0,XMM6;
17?????????MOVLPS?[EDX+32
],XMM0;
18?????????MOVHPS?[EDX+48
],XMM0;
19?

20? ????????MOVAPS?XMM0,XMM5;
21?
????????UNPCKLPS?XMM5,XMM4;
22?
????????UNPCKHPS?XMM0,XMM4;
23?????????MOVLPS?[EDX+8
],XMM5;
24?????????MOVHPS?[EDX+24
],XMM5;
25?????????MOVLPS?[EDX+40
],XMM0;
26?????????MOVHPS?[EDX+56
],XMM0;
27?

28? ????????MOVAPS?XMM3,[EDX];
29?????????MOVAPS?XMM2,[EDX+16
];
30?????????MOVAPS?XMM1,[EDX+32
];
31?????????MOVAPS?XMM0,[EDX+48
];
32?

33? ????????MULPS?XMM3,XMM2;
34?
????????MULPS?XMM1,XMM0;
35?
????????MOVAPS?tmp2,XMM1;
36?
????????MOVAPS?tmp1,XMM3;
37?
????};
38?????result[0]?=?tmp1.x?+?tmp1.y?+
?tmp1.z;
39?????result[1]?=?tmp2.x?+?tmp2.y?+
?tmp2.z;
40?};
??? Oh Year,就是這樣了,同時計算了1對乘法。我在代碼中借用了一下前面的頂點結構,這樣方便一些。至于SOA格式,請看前面的聲明。很多代碼都是轉換Stack中的內存格式,轉換成AOS格式,這樣才能使用SIMD指令計算。

??? 通過上面的演示,想必大家已經對SIMD有了個直觀地認識,其實在自己的代碼中加入這些是非常方便與容易的。雖然說現在的CPU性能已經提高了許多,性能也強了許多,可是在諸多對性能要求高的地方,還是非常烤煙程序員的水平的。
posted on 2006-08-24 21:00 Jerry Cat 閱讀(656) 評論(0)  編輯 收藏 引用

只有注冊用戶登錄后才能發表評論。
網站導航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理



<2006年9月>
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567

常用鏈接

留言簿(7)

隨筆檔案

最新隨筆

搜索

  •  

最新評論

閱讀排行榜

評論排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            国产啪精品视频| 国产精品国产三级国产普通话三级 | 久久精品日韩一区二区三区| 亚洲视频在线观看视频| 欧美午夜一区二区三区免费大片 | 国产精品国产三级国产a| 亚洲一区二区精品在线观看| 日韩视频专区| 国产精品久久久久久久久久久久久 | 亚洲国产欧美在线| 欧美电影在线观看| 欧美喷水视频| 亚洲午夜精品久久| 亚洲欧美一区二区三区极速播放| 国产欧美一二三区| 免费观看日韩| 欧美激情一区二区三区在线视频观看| 中文欧美日韩| 午夜国产不卡在线观看视频| 一区二区亚洲精品| 亚洲国产视频一区| 欧美色图天堂网| 久久人人九九| 欧美久久久久久久久久| 欧美一区二区三区在| 久久尤物视频| 亚洲一区二区3| 久久久免费观看视频| 在线视频你懂得一区| 欧美一区综合| 一区二区三区不卡视频在线观看| 小黄鸭精品密入口导航| 亚洲日本成人女熟在线观看| 一个色综合av| 亚洲大黄网站| 亚洲欧美另类中文字幕| 在线精品视频在线观看高清| 国产精品99久久久久久久久久久久 | 亚洲视频网站在线观看| 伊人久久av导航| 一个人看的www久久| 一区在线影院| 亚洲欧美久久久| 一区二区动漫| 久久综合久久综合久久综合| 欧美在线免费观看| 欧美激情精品久久久久久蜜臀| 久久久久国产精品一区三寸| 欧美日韩a区| 欧美成人国产一区二区| 国产午夜亚洲精品不卡| 日韩一级黄色片| 99re6这里只有精品| 久久深夜福利| 久久久久久亚洲综合影院红桃 | 亚洲欧美国产一区二区三区| 99国内精品久久| 久久午夜电影| 久久性天堂网| 国产专区精品视频| 亚洲一区二区三| 亚洲手机在线| 欧美日韩久久| 亚洲韩国精品一区| 91久久在线播放| 久久精品成人一区二区三区| 欧美一区二区三区四区视频| 国产精品你懂的在线| 99re66热这里只有精品3直播| 亚洲精品国产精品乱码不99| 美女日韩欧美| 91久久国产综合久久| 亚洲欧洲中文日韩久久av乱码| 老司机成人在线视频| 欧美激情精品久久久久| 亚洲国产精品久久| 久久综合一区二区| 欧美国产精品一区| 亚洲日本成人网| 欧美日本一区二区高清播放视频| 亚洲精品国产品国语在线app | 激情懂色av一区av二区av| 亚洲欧美视频在线| 久久福利资源站| 亚洲成色精品| 欧美激情成人在线| 99国产精品久久久久久久成人热| 亚洲天堂免费在线观看视频| 国产精品成人一区二区艾草| 午夜影视日本亚洲欧洲精品| 噜噜噜在线观看免费视频日韩| 在线观看一区视频| 欧美久久久久久久久| 亚洲影院免费观看| 另类酷文…触手系列精品集v1小说| 一区二区三区在线视频免费观看 | 亚洲免费在线观看| 母乳一区在线观看| 99人久久精品视频最新地址| 国产精品看片你懂得| 久久国产精品第一页| 欧美国产日韩一区二区在线观看| 99精品久久| 国产日韩一区在线| 欧美成人a∨高清免费观看| 亚洲特级毛片| 欧美大片第1页| 午夜精品免费在线| 136国产福利精品导航网址| 欧美日韩在线三级| 久久夜色精品国产欧美乱| 宅男噜噜噜66国产日韩在线观看| 久久久久免费视频| 亚洲午夜极品| 亚洲国产精品久久精品怡红院| 国产精品日韩一区| 欧美岛国在线观看| 欧美一区二区三区免费大片| 91久久夜色精品国产九色| 久久久久久亚洲精品不卡4k岛国| 制服丝袜激情欧洲亚洲| 在线观看欧美日韩国产| 国产欧美二区| 欧美性猛交一区二区三区精品| 久久久久久久一区| 亚洲女ⅴideoshd黑人| 亚洲人www| 欧美肥婆在线| 久久人体大胆视频| 欧美怡红院视频一区二区三区| 一本色道婷婷久久欧美| 亚洲高清视频在线观看| 国内精品久久久久久| 国产精品羞羞答答| 国产精品盗摄久久久| 欧美日韩成人免费| 欧美大片一区| 欧美高清视频| 另类图片国产| 久久久999成人| 欧美有码在线视频| 香蕉成人伊视频在线观看 | 亚洲国产高清在线| 亚洲大片在线| 亚洲第一精品福利| 亚洲国产岛国毛片在线| 男女激情久久| 欧美/亚洲一区| 欧美成人dvd在线视频| 免费日韩av| 亚洲第一精品电影| 亚洲韩日在线| 亚洲六月丁香色婷婷综合久久| 91久久国产综合久久蜜月精品 | 91久久久久| 亚洲免费成人av电影| 9l视频自拍蝌蚪9l视频成人| 亚洲免费激情| 亚洲一区二区精品视频| 亚洲欧美日韩系列| 久久精彩免费视频| 久久久在线视频| 欧美高清在线| 国产精品日韩高清| 极品尤物av久久免费看| 亚洲电影网站| 亚洲神马久久| 久久久久九九视频| 免费久久精品视频| 91久久久一线二线三线品牌| 亚洲香蕉在线观看| 欧美亚洲一区二区三区| 美脚丝袜一区二区三区在线观看 | 久久国产精品99国产精| 美女亚洲精品| 国产精品久久久一区麻豆最新章节| 国产日韩成人精品| 亚洲第一区色| 亚洲尤物在线视频观看| 久久精品伊人| 亚洲精品日韩久久| 午夜精品成人在线| 欧美好骚综合网| 国产精品资源在线观看| 亚洲国产日韩欧美| 午夜精品久久久久影视| 欧美成在线观看| 亚洲一区视频在线观看视频| 欧美一区二区三区精品| 欧美激情区在线播放| 国产一区视频网站| 亚洲区中文字幕| 久久精品欧洲| 一本久久a久久精品亚洲| 久久久久国产一区二区| 另类综合日韩欧美亚洲| 亚洲美女网站| 蜜桃久久av一区| 国产视频观看一区| 夜夜嗨网站十八久久|