望麓自卑—湖南大学最具潜力的校园传媒

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 1995|回复: 2

[电气与信息工程学院] [合集]程序的SSE加速 zz

[复制链接]
发表于 2005-5-28 09:51:50 | 显示全部楼层 |阅读模式
发信人: quzhi (王小波), 信区: CV_Image
标  题: [合集]程序的SSE加速
发信站: 兵马俑BBS (Wed Apr 27 23:06:55 2005), 本站(202.117.1.8)

───────────────────────────────────────
作者 quzhi       时间 Tue Apr 19 18:56:40 2005                    
───────────────────────────────────────

Intel编译器下的SSE优化

───────────────────────────────────────
作者 Shader      时间 Fri Apr 22 17:23:05 2005                    
───────────────────────────────────────
具体问题是什么啊,要用来干什么

【 在 quzhi 的大作中提到: 】
: Intel编译器下的SSE优化

───────────────────────────────────────
作者 quzhi       时间 Fri Apr 22 20:26:14 2005                    
───────────────────────────────────────

哇,老大,你会?我问了很多人都没听过这个
我想做一个算法的加速,想用SSE
我的QQ:16748251
谢谢阿


【 在 Shader (vs & ps) 的大作中提到: 】
: 具体问题是什么啊,要用来干什么
:
: 【 在 quzhi 的大作中提到: 】


───────────────────────────────────────
作者 macintosh    时间 Fri Apr 22 20:32:27 2005                    
───────────────────────────────────────
他是大牛!
【 在 quzhi (王小波) 的大作中提到: 】
: 哇,老大,你会?我问了很多人都没听过这个
: 我想做一个算法的加速,想用SSE
: 我的QQ:16748251
: 谢谢阿
: 【 在 Shader (vs & ps) 的大作中提到: 】
: ...................

───────────────────────────────────────
作者 McGrady      时间 Sat Apr 23 08:05:59 2005                    
───────────────────────────────────────
既然说到这个了
顺便问一下
对一副图像进行双线性插值
用mmx指令优化后性能会不会有提高?
或者说,能有多大的提高?
谢谢了~

【 在 Shader (vs & ps) 的大作中提到: 】
: 具体问题是什么啊,要用来干什么
:
: 【 在 quzhi 的大作中提到: 】


───────────────────────────────────────
作者 Shader      时间 Sat Apr 23 10:07:51 2005                    
───────────────────────────────────────
目前我只涉足3d图形学,对图像处理还非常陌生。

判断一个算法能否用MMX/SSE加速,关键在于是否涉及向量运算或者可以将其转化为向量运算的模型。

例如,32位颜色中的r,g,b,a就可以看成一个向量组,如果对它们同时进行一种运算,就可以考虑采用

MMX/SSE。

【 在 McGrady 的大作中提到: 】
: 既然说到这个了
: 顺便问一下
: 对一副图像进行双线性插值
: 用mmx指令优化后性能会不会有提高?
: 或者说,能有多大的提高?
: 谢谢了~
: 【 在 Shader (vs & ps) 的大作中提到: 】

───────────────────────────────────────
作者 quzhi       时间 Sat Apr 23 14:59:35 2005                    
───────────────────────────────────────

我现在要用到一个算法,时间要控制在30ms以内;但是现在程序实现速度很慢,大约
120ms.

主要是卷积的时间太慢,在每个像素都有两对连续地址的float相乘;我就想把这个
地方SSE一下,因为我查文献看到有人这样做

另外,Y方向卷积的时候寻址很慢;我想问问有什么解决办法

我看有文章说,MMX/SSE加速的瓶颈是寻址

我不懂MMX/SSE,基本的编程也不是非常熟悉,很迷惑



【 在 Shader (vs & ps) 的大作中提到: 】
: 目前我只涉足3d图形学,对图像处理还非常陌生。
:
: 判断一个算法能否用MMX/SSE加速,关键在于是否涉及向量运算或者可以将其转化为向量运算的模型

。例如,32位颜色中的r,g,b,a就可以看成一个向量组,如果对它们同时进行一种运算,就可以考虑采

用MMX/SSE。
:
: 【 在 McGrady 的大作中提到: 】
: ...................

───────────────────────────────────────
作者 Shader      时间 Sat Apr 23 16:09:13 2005                    
───────────────────────────────────────
连续地址?你看看能不能组织成如下的形式
a[0] * b[0] -> c[0]
a[1] * b[1] -> c[1]
a[2] * b[2] -> c[2]
a[3] * b[3] -> c[3]
...
...

这样效率可以最高。

算法方面我恐怕没有什么办法,你把要加速的程序段贴出来。

【 在 quzhi 的大作中提到: 】
: 我现在要用到一个算法,时间要控制在30ms以内;但是现在程序实现速度很慢,大约
: 120ms.
: 主要是卷积的时间太慢,在每个像素都有两对连续地址的float相乘;我就想把这个
: 地方SSE一下,因为我查文献看到有人这样做
: 另外,Y方向卷积的时候寻址很慢;我想问问有什么解决办法
: 我看有文章说,MMX/SSE加速的瓶颈是寻址
: 我不懂MMX/SSE,基本的编程也不是非常熟悉,很迷惑
: 【 在 Shader (vs & ps) 的大作中提到: 】
: (以下引言省略...)

───────────────────────────────────────
作者 McGrady      时间 Sat Apr 23 16:57:55 2005                    
───────────────────────────────────────
肯定是可以转化为向量运算
现在的问题是
有没有可能正常写了代码
编译的时候编译器就已经进行了优化?
因为用了MMX加速后效率似乎没有多少提高
- -\"

【 在 Shader (vs & ps) 的大作中提到: 】
: 目前我只涉足3d图形学,对图像处理还非常陌生。
:
: 判断一个算法能否用MMX/SSE加速,关键在于是否涉及向量运算或者可以将其转化为向量运算的模型

。例如,32位颜色中的r,g,b,a就可以看成一个向量组,如果对它们同时进行一种运算,就可以考虑采

用MMX/SSE。
:
: 【 在 McGrady 的大作中提到: 】
: ...................

───────────────────────────────────────
作者 Cybergate    时间 Sun Apr 24 09:20:00 2005                    
───────────────────────────────────────
这个要看具体的程序结构了。MMX的加速本来就比较有限,而且还要看MMX占整个处理过程的比例是多

少,以及程序的其他部分代码的效率怎么样。

纯C代码的优化是最彻底的,但是,如果你在C中嵌入汇编,就等于把一个可以优化的程序从中间截断

,编译器的优化功能就要受到影响。

因此如果要使用MMX/SSE加速,最好是整个函数都用汇编完成。

【 在 McGrady 的大作中提到: 】
: 肯定是可以转化为向量运算
: 现在的问题是
: 有没有可能正常写了代码
: 编译的时候编译器就已经进行了优化?
: 因为用了MMX加速后效率似乎没有多少提高
: - -\"
: 【 在 Shader (vs & ps) 的大作中提到: 】
: (以下引言省略...)


───────────────────────────────────────
作者 Shader 时间 Thu Apr 28 11:48:24 2005
标  题: 我用sse封装的float4和float4x4类,可以快速进行向量运算。
───────────────────────────────────────

我用sse封装的float4和float4x4类,可以快速进行向量运算。
需要vs2003或者vs6 sp5以上版本

直接嵌入汇编的话编译器不会优化,所以采用vs提供的库来进行,全部采用inline函数实现。通过分

析反汇编代码,编译器的优化工作做得相当好!

debug模式比release模式要慢20倍以上。所以大家不要用debug模式来测速

昨晚做的,有详细注释。应该没太大的问题。如果有什么bug请联系

如果排版系统把前面的缩进去掉了,在拷贝到vs2003之后用自动缩进功能就可以恢复原貌了。

// float4.cpp : 定义控制台应用程序的入口点。

#pragma once

#include <xmmintrin.h>
#include <math.h>

// 四维向量
union __declspec(align(16)) float4 {

// 可以通过x,y,z,w或者r,g,b,a来访问, 如v.x, v.y等等
struct { float x, y, z, w; };
struct { float r, g, b, a; };

float m[4];
__m128 vec;

float4(__m128 vec0): vec(vec0) { }
operator __m128() const { return vec; }


// 构造函数: // 构造方式: 可通过4个标量, 或者一个连续float数组
float4(void) {}
float4(float x0, float y0, float z0, float w0): vec( _mm_set_ps(w0, z0, y0, x0) ) {}
float4(float *first) { memcpy(m, first, sizeof(float)*4); }

// 通过[]索引各个元素, 下标从0-3
float &operator[](int i) { return m; }
const float &operator[](int i) const { return m; }

// 返回首地址, 方便拷贝到数组中
float* floatptr() { return m; }

// 四则运算, 逻辑运算
float4 &operator +=(float4 &u) { return *this = _mm_add_ps(vec,u); }
float4 &operator -=(float4 &u) { return *this = _mm_sub_ps(vec,u); }
float4 &operator *=(float4 &u) { return *this = _mm_mul_ps(vec,u); }
float4 &operator /=(float4 &u) { return *this = _mm_div_ps(vec,u); }
float4 &operator &=(float4 &u) { return *this = _mm_and_ps(vec,u); }
float4 &operator |=(float4 &u) { return *this = _mm_or_ps(vec,u); }
float4 &operator ^=(float4 &u) { return *this = _mm_xor_ps(vec,u); }

};

// 快速构造0向量
inline float4 zero4() { return _mm_setzero_ps(); }  
// 快速返回一个向量,每个元素都是f, 运用这个可以实现向量放缩
// 如 v1 = v2 * fill4(2.0f) 表示放大2倍
// 尽量使用乘法而不是除法来实现放缩!
inline float4 fill4(float f) { return _mm_set1_ps(f); }
// 快速返回一个向量,只有x才是f,其余的都是0
inline float4 scalar4(float f) { return _mm_set_ss(f); }

// 二元运算重载
inline float4 operator &(const float4 &u, const float4 &v) { return _mm_and_ps(u,v); }
inline float4 operator |(const float4 &u, const float4 &v) { return _mm_or_ps(u,v); }
inline float4 operator ^(const float4 &u, const float4 &v) { return _mm_xor_ps(u,v); }
inline float4 operator +(const float4 &u, const float4 &v) { return _mm_add_ps(u,v); }
inline float4 operator -(const float4 &u, const float4 &v) { return _mm_sub_ps(u,v); }
inline float4 operator *(const float4 &u, const float4 &v) { return _mm_mul_ps(u,v); }
inline float4 operator /(const float4 &u, const float4 &v) { return _mm_div_ps(u,v); }

// 返回四个元素之和
inline float add4h(const float4 &u) {
return float4(_mm_add_ss(u,_mm_add_ss(_mm_shuffle_ps(u, u,

1),_mm_add_ss(_mm_shuffle_ps(u, u, 2),_mm_shuffle_ps(u, u, 3))))).x;
}

// 返回前三个元素之和
inline float add3h(const float4 &u) {
return float4(_mm_add_ss(u,_mm_add_ss(_mm_shuffle_ps(u, u, 1), _mm_shuffle_ps(u, u,

2)))).x;
}

// 返回一个新的向量, 每个元素都取平方根
inline float4 sqrt(const float4 &u) { return _mm_sqrt_ps(u); }
// 返回一个新的向量, 每个元素都取倒数
inline float4 rcp(const float4 &u) { return _mm_rcp_ps(u); }
// 返回一个新的向量, 每个元素都取平方根倒数
inline float4 rsqrt(const float4 &u) { return _mm_rsqrt_ps(u); }

// 返回一个新的向量,每个元素的值都选较小的一个
inline float4 min4(const float4 &u, const float4 &v) { return _mm_min_ps(u,v); }

// 返回一个新的向量,每个元素的值都选较大的一个
inline float4 max4(const float4 &u, const float4 &v) { return _mm_max_ps(u,v); }

// 返回两个向量的点积, 考虑四个元素 x,y,z,w. 也就是u.x*v.x+u.y*v.y+u.z*v.z+u.w*v.w
inline float dot4(const float4 &u, const float4 &v) { return add4h(u*v); }
// 返回两个向量的点积, 仅考虑前三个元素x,y,z. 也就是u.x*v.x+u.y*v.y+u.z*v.z
inline float dot3(const float4 &u, const float4 &v) { return add3h(u*v); }

// 返回向量长度的平方, 当成四维向量处理, 也就是(x*x+y*y+z*z+w*w)
inline float len4sq(const float4 &u) { return add4h(u*u); }
// 返回向量长度的平方, 当成三维向量处理, 也就是(x*x+y*y+z*z)
inline float len3sq(const float4 &u) { return add3h(u*u); }

// 返回长度, 当成四维向量处理
inline float len4(const float4 &u) { return sqrt(len4sq(u)); }
// 返回长度, 当成三维向量处理
inline float len3(const float4 &u) { return sqrt(len3sq(u)); }

// 返回叉积, 当成三维向量处理, 忽略输入的w元素, 返回的w为0
inline float4 cross3(const float4 &u, const float4 &v)
{
float4 u1=_mm_shuffle_ps(u, u, _MM_SHUFFLE(3,0,2,1));
float4 v1=_mm_shuffle_ps(v, v, _MM_SHUFFLE(3,1,0,2));
float4 u2=_mm_shuffle_ps(u, u, _MM_SHUFFLE(3,1,0,2));
float4 v2=_mm_shuffle_ps(v, v, _MM_SHUFFLE(3,0,2,1));
return u1*v1-u2*v2;
}

// 4x4矩阵类
struct float4x4 {

float4 m[4];

// 构造方式: 可通过4个行向量, 或者16个标量, 或者一个连续float数组
float4x4() {}
float4x4(const float4 &r0, const float4 &r1, const float4 &r2, const float4 &r3) {
m[0]=r0; m[1]=r1; m[2]=r2; m[3]=r3;
}

float4x4( float m00, float m01, float m02, float m03,
float m10, float m11, float m12, float m13,
float m20, float m21, float m22, float m23,
float m30, float m31, float m32, float m33 )
{
m[0] = float4(m00, m01, m02, m03);
m[1] = float4(m10, m11, m12, m13);
m[2] = float4(m20, m21, m22, m23);
m[3] = float4(m30, m31, m32, m33);
}

float4x4(float *first) { memcpy(m[0].m, first, sizeof(float)*16); }

// 可以通过m[j]或者m(i,j)的形式访问各个元素, i为行, j为列, 取值0-3
float &operator()(int i, int j) { return m[j]; }
const float &operator()(int i, int j) const { return m[j]; }
float4 &operator[](int i) { return m; }
const float4 &operator[](int i) const { return m; }

// 返回首地址
float* floatptr() { return m[0].m; }

// 矩阵运算, 每个元素执行相同的操作, 这里省略了乘除法, 为了避免和矩阵乘法混淆
float4x4 &operator +=(float4x4 &u) { m[0]+=u[0]; m[1]+=u[1], m[2]+=u[2], m[3]+=u[3];

return *this; }
float4x4 &operator -=(float4x4 &u) { m[0]-=u[0]; m[1]-=u[1], m[2]-=u[2], m[3]-=u[3];

return *this; }
float4x4 &operator &=(float4x4 &u) { m[0]&=u[0]; m[1]&=u[1], m[2]&=u[2], m[3]&=u[3];

return *this; }
float4x4 &operator |=(float4x4 &u) { m[0]|=u[0]; m[1]|=u[1], m[2]|=u[2], m[3]|=u[3];

return *this; }
float4x4 &operator ^=(float4x4 &u) { m[0]^=u[0]; m[1]^=u[1], m[2]^=u[2], m[3]^=u[3];

return *this; }

// 根据比例因子进行放缩
float4x4 &operator *=(float f) { float4 u=fill4(f); m[0]*=u; m[1]*=u, m[2]*=u, m[3]*=u;

return *this; }
float4x4 &operator /=(float f) { return (*this)*=1.0f/f; }

};

// 矩阵运算, 每个元素执行相同的操作, 这里省略了乘除法, 为了避免和矩阵乘法混淆
inline float4x4 operator+ (float4x4 &u, float4x4 &v) { return float4x4(u[0]+v[0],

u[1]+v[1], u[2]+v[2], u[3]+v[3]); }
inline float4x4 operator- (float4x4 &u, float4x4 &v) { return float4x4(u[0]-v[0],

u[1]-v[1], u[2]-v[2], u[3]-v[3]); }
inline float4x4 operator& (float4x4 &u, float4x4 &v) { return float4x4(u[0]&v[0],

u[1]&v[1], u[2]&v[2], u[3]&v[3]); }
inline float4x4 operator| (float4x4 &u, float4x4 &v) { return float4x4(u[0]|v[0],

u[1]|v[1], u[2]|v[2], u[3]|v[3]); }
inline float4x4 operator^ (float4x4 &u, float4x4 &v) { return float4x4(u[0]^v[0],

u[1]^v[1], u[2]^v[2], u[3]^v[3]); }

// 向量变换: 向量*矩阵, 或者矩阵*向量.
// 尽量采用向量*矩阵的方式, 速度快很多
inline float4 operator* (const float4 &vec, const float4x4 &mat) { return

mat[0]*fill4(vec[0]) + mat[1]*fill4(vec[1]) + mat[2]*fill4(vec[2]) +

mat[3]*fill4(vec[3]); }
inline float4 operator* (const float4x4 &mat, const float4 &vec) { return

float4(dot4(mat[0], vec), dot4(mat[1], vec), dot4(mat[2], vec), dot4(mat[3], vec)); }

// 矩阵乘法: 矩阵*矩阵
inline float4x4 operator* (const float4x4 &u, const float4x4 &v) { return

float4x4(u[0]*v, u[1]*v, u[2]*v, u[3]*v); }

// 矩阵放缩
inline float4x4 operator *(const float4x4 &mat, float f) { float4 u=fill4(f); return

float4x4(mat[0]*u, mat[1]*u, mat[2]*u, mat[3]*u); }
inline float4x4 operator *(float f, const float4x4 &mat) { return mat*f; }
inline float4x4 operator /(const float4x4 &mat, float f) { return mat*(1.0f/f); }

// 求矩阵转置
inline float4x4 transpose(const float4x4 &mat) {
float4x4 tmp(
_mm_shuffle_ps(mat[0], mat[1], 0x44),
_mm_shuffle_ps(mat[2], mat[3], 0x44),
_mm_shuffle_ps(mat[0], mat[1], 0xEE),
_mm_shuffle_ps(mat[2], mat[3], 0xEE) );        

return float4x4(
_mm_shuffle_ps(tmp[0], tmp[1], 0x88),
_mm_shuffle_ps(tmp[0], tmp[1], 0xDD),
_mm_shuffle_ps(tmp[2], tmp[3], 0x88),         
_mm_shuffle_ps(tmp[2], tmp[3], 0xDD) );
}


--
※ 来源:.兵马俑BBS http://202.117.1.8 [FROM: 219.245.175.10]
发表于 2005-6-9 14:21:23 | 显示全部楼层
好强,太深了
 楼主| 发表于 2005-6-10 17:24:56 | 显示全部楼层
可惜,没有人用到
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

每日推荐上一条 /1 下一条

小黑屋|手机版|湖南大学望麓自卑校园传媒 ( 湘ICP备14014987号 )

GMT+8, 2024-11-28 18:16 , Processed in 0.452936 second(s), 21 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表