SSE 加速运算例子详解:乘法、加法、平方、最小值、最大值、与操作
2016-04-20 23:17
941 查看
SSE(Streaming SIMD Extensions)是英特尔在AMD的3D Now!发布一年之后,在其计算机芯片Pentium III中引入的指令集,是MMX的超集。AMD后来在Athlon XP中加入了对这个指令集的支持。这个指令集增加了对8个128位寄存器XMM0-XMM7的支持,每个寄存器可以存储4个单精度浮点数。使用这些寄存器的程序必须使用FXSAVE和FXRSTR指令来保持和恢复状态。但是在Pentium III对SSE的实现中,浮点数寄存器又一次被新的指令集占用了,但是这一次切换运算模式不是必要的了,只是SSE和浮点数指令不能同时进入CPU的处理线而已。
库文件说明
#ifndef __METHOD #define __METHOD void ScaleValue1(float *pArray, DWORD dwCount, float fScale);//乘法 void ScaleValue2(float *pArray, DWORD dwCount, float fScale); void Add1(float *pArray, DWORD dwCount, float fScale);//加法 void Add2(float *pArray, DWORD dwCount, float fScale); void Sqrt1(float *pArray, DWORD dwCount, float fScale);//平方 void Sqrt2(float *pArray, DWORD dwCount, float fScale); void Min1(float *pArray, DWORD dwCount, float fScale);//最小值 void Min2(float *pArray, DWORD dwCount, float fScale);//最小值 void Max1(float *pArray, DWORD dwCount, float fScale);//最小值 void Max2(float *pArray, DWORD dwCount, float fScale);//最小值 void And1(float *pArray, DWORD dwCount, float fScale);//与操作 void And2(float *pArray, DWORD dwCount, float fScale);//与操作 #endif
#include <xmmintrin.h> #include <Windows.h> #include <math.h> void ScaleValue1(float *pArray, DWORD dwCount, float fScale)//乘法 { DWORD dwGroupCount = dwCount/4; __m128 e_Scale = _mm_set_ps1(fScale);//设置所有4个值为同一值 for (DWORD i=0; i<dwGroupCount; i++) { *(__m128*)(pArray + i*4) = _mm_mul_ps( *(__m128*)(pArray + i*4),e_Scale); } } void ScaleValue2(float *pArray, DWORD dwCount, float fScale) { for (DWORD i =0; i<dwCount; i++) { pArray[i] *= fScale; } } void Add1(float *pArray, DWORD dwCount, float fScale)//加法 { DWORD dwGroupCount = dwCount/4; __m128 e_Scale = _mm_set_ps1(fScale);//设置所有4个值为同一值 for (DWORD i=0; i<dwGroupCount; i++) { *(__m128*)(pArray + i*4) = _mm_add_ps( *(__m128*)(pArray + i*4),e_Scale); } } void Add2(float *pArray, DWORD dwCount, float fScale) { for (DWORD i =0; i<dwCount; i++) { pArray[i] += fScale; } } void Sqrt1(float *pArray, DWORD dwCount, float fScale)//平方 { DWORD dwGroupCount = dwCount/4; __m128 e_Scale = _mm_set_ps1(fScale);//设置所有4个值为同一值 for (DWORD i=0; i<dwGroupCount; i++) { *(__m128*)(pArray + i*4) = _mm_sqrt_ps(e_Scale); } } void Sqrt2(float *pArray, DWORD dwCount, float fScale) { for (DWORD i =0; i<dwCount; i++) { pArray[i] = sqrt(fScale); } } void Min1(float *pArray, DWORD dwCount, float fScale)//最小值 { DWORD dwGroupCount = dwCount/4; __m128 e_Scale = _mm_set_ps1(fScale);//设置所有4个值为同一值 for (DWORD i=0; i<dwGroupCount; i++) { *(__m128*)(pArray + i*4) = _mm_min_ps( *(__m128*)(pArray + i*4),e_Scale); } } void Min2(float *pArray, DWORD dwCount, float fScale) { for (DWORD i =0; i<dwCount; i++) { pArray[i] = (pArray[i]>fScale? fScale : pArray[i]); } } void Max1(float *pArray, DWORD dwCount, float fScale)//最大值 { DWORD dwGroupCount = dwCount/4; __m128 e_Scale = _mm_set_ps1(fScale);//设置所有4个值为同一值 for (DWORD i=0; i<dwGroupCount; i++) { *(__m128*)(pArray + i*4) = _mm_max_ps( *(__m128*)(pArray + i*4),e_Scale); } } void Max2(float *pArray, DWORD dwCount, float fScale) { for (DWORD i =0; i<dwCount; i++) { pArray[i] = (pArray[i]<fScale? fScale : pArray[i]); } } void And1(float *pArray, DWORD dwCount, float fScale)//与操作 { DWORD dwGroupCount = dwCount/4; __m128 e_Scale = _mm_set_ps1(fScale);//设置所有4个值为同一值 for (DWORD i=0; i<dwGroupCount; i++) { *(__m128*)(pArray + i*4) = _mm_and_ps( *(__m128*)(pArray + i*4),e_Scale); } } void And2(float *pArray, DWORD dwCount, float fScale) { for (DWORD i =0; i<dwCount; i++) { pArray[i] = (int)(pArray[i]) & (int)(fScale); } }
采用SSE和不采用SSE的数学计算操作速度对比:
#include <xmmintrin.h> #include <Windows.h> #include <iostream> #include "Method.h" using namespace std; #define ARRAYCOUNT 1000 #define COUNTSIZE 10000 class CTimer { public: __forceinline CTimer(void) { QueryPerformanceFrequency(&m_Frequency);// 获取时钟周期 QueryPerformanceCounter(&m_StartCount);// 获取时钟计数 } __forceinline void Reset(void) { QueryPerformanceCounter(&m_StartCount); } __forceinline double End(void) { QueryPerformanceCounter(&m_EndCount); return ( m_EndCount.QuadPart - m_StartCount.QuadPart )*1000/m_Frequency.QuadPart; } private: LARGE_INTEGER m_Frequency; LARGE_INTEGER m_StartCount; LARGE_INTEGER m_EndCount; }; int __cdecl main() { float __declspec(align(16))Array[ARRAYCOUNT]; //__declspec(align(16))做为数组定义的修释符,这表示该数组是以16字节为边界对齐的, //因为SSE指令只能支持这种格式的内存数据 memset(Array, 0, sizeof(float)*ARRAYCOUNT); CTimer t; double dTime; //乘法 cout<<"乘法:"<<endl; t.Reset(); for (int i=0; i<COUNTSIZE; i++) { ScaleValue1(Array, ARRAYCOUNT, 1000.0f); } dTime = t.End(); cout<<"Use SSE: "<<dTime<<"毫秒"<<endl; t.Reset(); for (int i=0; i<COUNTSIZE; i++) { ScaleValue2(Array, ARRAYCOUNT, 1000.0f); } dTime = t.End(); cout<<"Not Use SSE: "<<dTime<<"毫秒"<<endl; //加法 cout<<"加法:"<<endl; t.Reset(); for (int i=0; i<COUNTSIZE; i++) { Add1(Array, ARRAYCOUNT, 1000.0f); } dTime = t.End(); cout<<"Use SSE: "<<dTime<<"毫秒"<<endl; t.Reset(); for (int i=0; i<COUNTSIZE; i++) { Add2(Array, ARRAYCOUNT, 1000.0f); } dTime = t.End(); cout<<"Not Use SSE: "<<dTime<<"毫秒"<<endl; //平方 cout<<"平方:"<<endl; t.Reset(); for (int i=0; i<COUNTSIZE; i++) { Sqrt1(Array, ARRAYCOUNT, 1000.0f); } dTime = t.End(); cout<<"Use SSE: "<<dTime<<"毫秒"<<endl; t.Reset(); for (int i=0; i<COUNTSIZE; i++) { Sqrt2(Array, ARRAYCOUNT, 1000.0f); } dTime = t.End(); cout<<"Not Use SSE: "<<dTime<<"毫秒"<<endl; //最小值 cout<<"最小值:"<<endl; t.Reset(); for (int i=0; i<COUNTSIZE; i++) { Min1(Array, ARRAYCOUNT, 1000.0f); } dTime = t.End(); cout<<"Use SSE: "<<dTime<<"毫秒"<<endl; t.Reset(); for (int i=0; i<COUNTSIZE; i++) { Min2(Array, ARRAYCOUNT, 1000.0f); } dTime = t.End(); cout<<"Not Use SSE: "<<dTime<<"毫秒"<<endl; //最大值 cout<<"最大值:"<<endl; t.Reset(); for (int i=0; i<COUNTSIZE; i++) { Max1(Array, ARRAYCOUNT, 1000.0f); } dTime = t.End(); cout<<"Use SSE: "<<dTime<<"毫秒"<<endl; t.Reset(); for (int i=0; i<COUNTSIZE; i++) { Max2(Array, ARRAYCOUNT, 1000.0f); } dTime = t.End(); cout<<"Not Use SSE: "<<dTime<<"毫秒"<<endl; //与操作 cout<<"与操作:"<<endl; t.Reset(); for (int i=0; i<COUNTSIZE; i++) { And1(Array, ARRAYCOUNT, 1000.0f); } dTime = t.End(); cout<<"Use SSE: "<<dTime<<"毫秒"<<endl; t.Reset(); for (int i=0; i<COUNTSIZE; i++) { And2(Array, ARRAYCOUNT, 1000.0f); } dTime = t.End(); cout<<"Not Use SSE: "<<dTime<<"毫秒"<<endl; system("pause"); return 0; }
相关文章推荐
- CPU也有远程攻击漏洞 英特尔匆匆修补
- 英特尔前 CEO 安迪·葛洛夫去世,他对科技的贡献甚至超过了史蒂夫·乔布斯
- 对L2和B2的阐述
- U盘启动CDlinux,U盘启动BT5,关键命令!原创!新加图文教程。新加0.971版制作方法。
- U盘启动CDlinux,U盘启动BT5,关键命令!原创!新加图文教程。新加0.971版制作方法。
- AMD CEO罗瑞德称将调整战略 应对市场变化
- Intel超线程技术有多少种?
- 英特尔Nehalem微架构三级缓存原理学习
- 英特尔与数字标牌
- 红帽新RHEL 7.1企业版发布
- 英特尔酷睿2家族命名规则
- 英特尔发布新产品Nehalem
- 直击CES 2015:英特尔“变酷”进行时
- 摩尔定理
- 平衡架构 惠普BL460 G7刀片服务器评测
- 苹果公司推出新款iMac产品
- 了解TOP500、Green500、Graph500的最新世界排名、看看哪些超级计算机是来自中国
- 视频:Chromebook简评 基于ARM芯片性价比高
- 给IT界增添一抹幽默
- 无人驾驶不是梦?CES上海大会探讨未来(转自太平洋电脑网)