为什么VC的内联汇编函数性能不如C++函数
小弟最近编一段程序,性能要求比较高,花了两天功夫,将C++函数改写成汇编函数,结果发现汇编函数的性能俱然不如C++函数,狂郁闷。
下面将代码贴出,各路高手帮我测试一下。
//------------------------begin-----------------
//使用到的一些结构
//直线
typedef struct LINEtag
{
floata;
floatb;
floatc;
floatd;
}LINE;
//顶点
typedef struct XPOINT32Ftag
{
floatx;
floaty;
}POINT32F,*PPOINT32F;
//多边形
typedef struct XRGN32Ftag XRgn32F;
struct XRGN32Ftag
{
POINT32F *v;
intiV;
floatx; //原点X
floaty; //原点Y
floatw; //多边形外接矩形宽度
floath; //多边形外接矩形高度
XRgn32F *next ;
LINE*line ; //多边形边的直线
} ;
//该函数求组成多边形的每一条边的直线,该函数使用汇编代码编写,对3280个顶点
//测试,使用时间为5004纳秒
//POINT32F *pPos [IN] 存放组成多边形的各点
//LINE *lines [OUT] 输出每条边的直线
//int nPos [IN] 多边形的顶点数,也就是pPos数组的维数
inline void cxMakeLines32F_asm(POINT32F *pPos, LINE *lines,int nPos)
{
_asm
{
mov ebx,0;
mov ecx,nPos;
mov esi,dword ptr [pPos] ;
mov edi,dword ptr [lines] ;
//{: Begin Loop 0 ----i=0
mov eax,ecx;
sub eax,1;
imul eax,8;
fninit;
fld [esi+eax] ;
fld [esi+eax+4] ;
fld [esi] ;
fld [esi+4] ;
fld st(0) ;//取出y2
fsub st(0),st(3) ;//y2-y1
fldz ;//将0压栈
fucomp st(1) ;//tl.a <0
jnge _mlnext;//如果小于0,就跳转_mlnext0
fchs;//-1*tl.a
fstp dword ptr [edi];//保存结果 a
fld st(3) ;//将x1压栈
fsub st(0),st(2);//x1-x2
fchs;//-1*tl.b
fstp dword ptr [edi+4];//保存结果 b
fld st(3) ;//将x1压栈
fmul st(0),st(1) ;//x1*y2
fstp st(5);//将st0数据放到st5,并将st0弹出栈
fld st(2) ;//将y1压栈
fmul st(0),st(2) ;//y1*x2
fsub st(0),st(5) ;//y1*x2-x1*y2
fchs;//-1*tl.c
fstp dword ptr [edi+8];//保存结果 c
jmp _mlout ;//跳转到_mlout
_mlnext:
fstp dword ptr [edi];//保存结果
fld st(3) ;//将x1压栈
fsub st(0),st(2);//x1-x2
fstp dword ptr [edi+4];//保存结果
fld st(3) ;//将y1压栈
fmul st(0),st(1) ;//x1*y2
fstp st(5);//将st0数据放到st5,并将st0弹出栈
fld st(2) ;//将y1压栈
fmul st(0),st(2) ;//y1*x2
fsub st(0),st(5) ;//y1*x2-x1*y2
fstp dword ptr [edi+8];//保存结果
_mlout:
//:} End Loop 0
dec ecx;
add edi,16;
//{: Begin Loop --- i = 0 to nPos
_beginloop:
//{: Begin make line
_beginmakeline:
fninit;
fld [esi] ;
fld [esi+4] ;
fld [esi+8] ;
fld [esi+12] ;
fld st(0) ;//取出y2
fsub st(0),st(3) ;//y2-y1
fldz ;//将0压栈
fucomp st(1) ;//tl.a <0
jnge _makelinenext;//如果小于0,就跳转_mlnext0
fchs;//-1*tl.a
fstp dword ptr [edi];//保存结果 a
fld st(3) ;//将x1压栈
fsub st(0),st(2);//x1-x2
fchs;//-1*tl.b
fstp dword ptr [edi+4];//保存结果 b
fld st(3) ;//将x1压栈
fmul st(0),st(1) ;//x1*y2
fstp st(5);//将st0数据放到st5,并将st0弹出栈
fld st(2) ;//将y1压栈
fmul st(0),st(2) ;//y1*x2
fsub st(0),st(5) ;//y1*x2-x1*y2
fchs;//-1*tl.c
fstp dword ptr [edi+8];//保存结果 c
jmp _endmakeline ;//跳转到_mlout
_makelinenext:
fstp dword ptr [edi];//保存结果
fld st(3) ;//将x1压栈
fsub st(0),st(2);//x1-x2
fstp dword ptr [edi+4];//保存结果
fld st(3) ;//将y1压栈
fmul st(0),st(1) ;//x1*y2
fstp st(5);//将st0数据放到st5,并将st0弹出栈
fld st(2) ;//将y1压栈
fmul st(0),st(2) ;//y1*x2
fsub st(0),st(5) ;//y1*x2-x1*y2
fstp dword ptr [edi+8];//保存结果
_endmakeline:
//:} End make line
add esi,8;
add edi,16;
inc ebx;
cmp ebx,ecx;
jnge _beginloop ;
_endloop:
//:} End Loop
}
}
// 根据已知两点坐标,求过这两点的直线解析方程: a*x+b*y+c = 0 (a > = 0)
LINE makeline(float x1,float y1,float x2,float y2)
{
LINE tl;
int sign = 1;
tl.a=y2-y1;
if(tl.a <0)
{
sign = -1;
tl.a=sign*tl.a;
}
tl.b=sign*(x1-x2);
tl.c=sign*(y1*x2-x1*y2);
return tl;
}
//该函数求组成多边形的每一条边的直线,使用该函数对3280个顶点
//测试,使用时间为3128纳秒
//POINT32F *pPos [IN] 存放组成多边形的各点
//LINE *lines [OUT] 输出每条边的直线
//int nPos [IN] 多边形的顶点数,也就是pPos数组的维数
void cxMakeLines32F(POINT32F *pPos, LINE *lines,int nPos)
{
int i0 = nPos-1 ;
int i =0 ;
lines[i] = makeline(pPos[i0].x,pPos[i0].y,pPos[i].x,pPos[i].y);
for ( i = 1 ; i < nPos; i++ )
{
i0 = i-1;
lines[i] = makeline(pPos[i0].x,pPos[i0].y,pPos[i].x,pPos[i].y);
}
}
//从文本文件当中读取多边形
//char *file [IN] 文本文件名称
//文件格式:x y
//218.90 319.20
//321.81 234.09
//......略
XRgn32F readRgn(char *file)
{
ifstream inf(file);
POINT32F *ps0 = new POINT32F[5000];
POINT32F *ps1 = ps0 ;
int np = 0 ;
float right,bottom;
right = bottom = 0 ;
while( !inf.eof() )
{
inf> > ps1-> x> > ps1-> y ;
np++;
if ( right < ps1-> x ) right = ps1-> x ;
if ( bottom < ps1-> y ) bottom = ps1-> y ;
ps1++;
}
XRgn32F rgn;
rgn.v = ps0;
rgn.iV = np-1;
rgn.x = rgn.y = 0;
rgn.w = right;
rgn.h = bottom;
return rgn ;
}
//测试性能的代码
void Test()
{
//读取多边形
XRgn32F rgn = readRgn( "F:\\Bin\\pos2.txt ");
rgn.line = new LINE[5000];
LARGE_INTEGER litmp;
double dCountsNow,dCountsNext,dCountsDif;
//超精确时间函数
//取当前CPU时钟计数器计数
QueryPerformanceCounter(&litmp);
dCountsNow=(double)litmp.QuadPart;
//cxMakeLines32F( rgn.v,rgn.line,rgn.iV ) ; //使用C++函数计算
cxMakeLines32F_asm( rgn.v,rgn.line,rgn.iV ) ; //使用汇编函数计算
QueryPerformanceCounter(&litmp);
dCountsNext=(double)litmp.QuadPart;
dCountsDif = dCountsNext-dCountsNow ; //计算使用时间
}
[解决办法]
内联汇编调用C/C++函数必须自己清除堆栈
[解决办法]
哎还是别手工优化了,用编译器的优化功能吧
[解决办法]
要分析一下代码消耗的时间主要在什么部分 .....
如果是在外部数据读取上,
那么用汇编能提高什么啊 ~
[解决办法]
这种不使用CPU特别的指令的东东手工汇编应该很难超过编译器优化吧, 偶觉得你这样照着翻译的汇编代码超过机器优化应该很难, 还是考虑考虑SSE啥的可能有点希望 ...
[解决办法]
非专业人士,很难写出比编译器最优化后更快的代码,不值得太浪费时间。
[解决办法]
差了一个数量级啊