SSE技術簡介

2021-04-06 15:15:57 字數 4989 閱讀 3753

sse技術簡介

intel公司的單指令多資料流式擴充套件(sse,streaming simd extensions)技術能夠有效增強cpu浮點運算的能力。visual studio .net 2003提供了對sse指令集的程式設計支援,從而允許使用者在c++**中不用編寫彙編**就可直接使用sse指令的功能。msdn中有關sse技術的主題[1]有可能會使不熟悉使用sse彙編指令程式設計的初學者感到困惑,但是在閱讀msdn有關文件的同時,參考一下intel軟體說明書(intel software manuals)[2]會使你更清楚地理解使用sse指令程式設計的要點。

simd(single-instruction, multiple-data)是一種使用單道指令處理多道資料流的cpu執行模式,即在乙個cpu指令執行週期內用一道指令完成處理多個資料的操作。考慮一下下面這個任務:計算乙個很長的浮點型陣列中每乙個元素的平方根。實現這個任務的演算法可以這樣寫:

for each f in array //對陣列中的每乙個元素

f = sqrt(f) //計算它的平方根

為了了解實現的細節,我們把上面的**這樣寫:

for each f in array

具有intel sse指令集支援的處理器有8個128位的暫存器,每乙個暫存器可以存放4個(32位)單精度的浮點數。sse同時提供了乙個指令集,其中的指令可以允許把浮點數載入到這些128位的暫存器之中,這些數就可以在這些暫存器中進行算術邏輯運算,然後把結果放回記憶體。採用sse技術後,演算法可以寫成下面的樣子:

for each 4 members in array //對陣列中的每4個元素

c++程式設計人員在使用sse指令函式程式設計時不必關心這些128位的暫存器,你可以使用128位的資料型別「__m128」和一系列c++函式來實現這些算術和邏輯操作,而決定程式使用哪個sse暫存器以及**優化是c++編譯器的任務。當需要對很長的浮點數陣列中的元素進行處理的時候,sse技術確實是一種很高效的方法。

sse程式設計詳細介紹

包含的標頭檔案:

所有的sse指令函式和__m128資料型別都在xmmintrin.h檔案中定義:

#include

因為程式中用到的sse處理器指令是由編譯器決定,所以它並沒有相關的.lib庫檔案。

資料分組(data alignment)

由sse指令處理的每乙個浮點數陣列必須把其中需要處理的數每16個位元組(128位二進位制)分為一組。乙個靜態陣列(static array)可由__declspec(align(16))關鍵字宣告:

__declspec(align(16)) float m_farray[array_size];

動態陣列(dynamic array)可由_aligned_malloc函式為其分配空間:

m_farray = (float*) _aligned_malloc(array_size * sizeof(float), 16);

由_aligned_malloc函式分配空間的動態陣列可以由_aligned_free函式釋放其占用的空間:

_aligned_free(m_farray);

__m128 資料型別

該資料型別的變數可用做sse指令的運算元,它們不能被使用者指令直接訪問。_m128型別的變數被自動分配為16個位元組的字長。

cpu對sse指令集的支援

如果你的cpu能夠具有了sse指令集,你就可以使用visual studio .net 2003提供的對sse指令集支援的c++函式庫了,你可以檢視msdn中的乙個visual c++ cpuid的例子[4],它可以幫你檢測你的cpu是否支援sse、mmx指令集或其它的cpu功能。

程式設計例項

ssetest專案是乙個基於對話方塊的應用程式,它用到了三個浮點陣列參與運算:

fresult[i] = sqrt( fsource1[i]*fsource1[i] + fsource2[i]*fsource2[i] ) + 0.5

其中i = 0, 1, 2 ... array_size-1

其中array_size被定義為30000。資料來源陣列(source陣列)通過使用sin和cos函式給它賦值,我們用kris jearakul開發的瀑布狀圖表控制項(wate***ll chart control)[3] 來顯示參與計算的源陣列和結果陣列。計算所需的時間(以毫秒ms為單位)在對話方塊中顯示出來。我們使用三種不同的途徑來完成計算:

純c++**;

使用sse指令函式的c++**;

包含sse彙編指令的**。

純c++**:

void cssetestdlg::computearraycplusplus(

float* parray1, // [輸入] 源陣列1

float* parray2, // [輸入] 源陣列2

float* presult, // [輸出] 用來存放結果的陣列

int nsize) // [輸入] 陣列的大小

}下面我們用具有sse特性的c++**重寫上面這個函式。為了查詢使用sse指令c++函式的方法,我參考了intel軟體說明書(intel software manuals)中有關sse彙編指令的說明,首先我是在第一卷的第九章找到的相關sse指令,然後在第二卷找到了這些sse指令的詳細說明,這些說明有一部分涉及了與其特性相關的c++函式。然後我通過這些sse指令對應的c++函式查詢了msdn中與其相關的說明。搜尋的結果見下表:

實現的功能

對應的sse彙編指令

visual c++.net中的sse函式

將4個32位浮點數放進乙個128位的儲存單元。

movss 和 shufps

_mm_set_ps1

將4對32位浮點數同時進行相乘操作。這4對32位浮點數來自兩個128位的儲存單元,再把計算結果(乘積)賦給乙個128位的儲存單元。

mulps

_mm_mul_ps

將4對32位浮點數同時進行相加操作。這4對32位浮點數來自兩個128位的儲存單元,再把計算結果(相加之和)賦給乙個128位的儲存單元。

addps

_mm_add_ps

對乙個128位儲存單元中的4個32位浮點數同時進行求平方根操作。

sqrtps

_mm_sqrt_ps

使用visual c++.net的 sse指令函式的**:

void cssetestdlg::computearraycplusplussse(

float* parray1, // [輸入] 源陣列1

float* parray2, // [輸入] 源陣列2

float* presult, // [輸出] 用來存放結果的陣列

int nsize) // [輸入] 陣列的大小

}使用sse彙編指令實現的c++函式**:

void cssetestdlg::computearrayassemblysse(

float* parray1, // [輸入] 源陣列1

float* parray2, // [輸入] 源陣列2

float* presult, // [輸出] 用來存放結果的陣列

int nsize) // [輸入] 陣列的大小

}最後,在我的計算機上執行計算測試的結果:

純c++**計算所用的時間是26 毫秒

使用sse的c++ 函式計算所用的時間是 9 毫秒

包含sse彙編指令的c++**計算所用的時間是 9 毫秒

以上的時間結果是在release優化編譯後執行程式得出的。

ssesample 示例專案

ssesample專案是乙個基於對話方塊的應用程式,其中它用下面的浮點數陣列進行計算:

fresult[i] = sqrt(fsource[i]*2.8)

其中i = 0, 1, 2 ... array_size-1

這個程式同時計算了陣列中的最大值和最小值。array_size被定義為100000,陣列中的計算結果在列表框中顯示出來。其中在我的機子上用下面三種方法計算所需的時間是:

純c++**計算 6 毫秒

使用sse的c++ 函式計算 3 毫秒

使用sse彙編指令計算 2 毫秒

大家看到,使用sse彙編指令計算的結果會好一些,因為使用了效率增強了的ssx暫存器組。但是在通常情況下,使用sse的c++ 函式計算會比彙編**計算的效率更高一些,因為c++編譯器的優化後的**有很高的運算效率,若要使彙編**比優化後的**運算效率更高,這通常是很難做到的。

純c++**:

// 輸入: m_finitialarray

// 輸出: m_fresultarray, m_fmin, m_fmax

void cssesampledlg::onbnclickedbuttoncplusplus()

}使用visual c++.net的 sse指令函式的**:

// 輸入: m_finitialarray

// 輸出: m_fresultarray, m_fmin, m_fmax

void cssesampledlg::onbnclickedbuttonssec()

// 計算max128的最大值和min128的最小值

union u

x;x.m = min128;

m_fmin = min(x.f[0], min(x.f[1], min(x.f[2], x.f[3])));

x.m = max128;

m_fmax = max(x.f[0], max(x.f[1], max(x.f[2], x.f[3])));

}使用sse彙編指令的c++函式**:

// 輸入: m_finitialarray

// 輸出: m_fresultarray, m_fmin, m_fmax

void cssesampledlg::onbnclickedbuttonsseassembly()

union u

x;x.m = min128;

m_fmin = min(x.f[0], min(x.f[1], min(x.f[2], x.f[3])));

x.m = max128;

m_fmax = max(x.f[0], max(x.f[1], max(x.f[2], x.f[3])));

}

python技術簡介 Python簡介

python 簡介 python是乙個高層次的 結合了解釋性 編譯性 互動性和物件導向的指令碼語言。python的設計具有很強的可讀性,相比其他語言經用使用英文關鍵字,其他語言的一些標點符號,它具有比其他語言更有特色語法結構。python 是一種解釋型語言 這意味著開發過程中沒有了編譯這個環節,類似...

SSE優化引擎

週末在家嘗試著使用sse對引擎進行優化。關於如何使用sse這裡並不多說,有很多資料,這裡提一下,使用sse無非就是直接使用彙編或是使用函式指令,如果是諸如解碼器核心之類的推薦使用彙編直接進行優化,畢竟可以將核心全部用彙編實現,其他情況下使用sse函式指令即可。接下來說一下sse在3d引擎中的優化。可...

載入操作 SSE

記憶體和初始化載入操作 mm load ss 載入低值並清除三個最大值 mm loadu ps和 mm storeu ps,不要求位元組對齊 float op1 4 float op2 4 float result 4 載入 m128 a mm loadu ps op1 m128 b mm load...