游戏开发论坛

 找回密码
 立即注册
搜索
查看: 4062|回复: 6

sse汇编高手请近,难道vc6编译器的优化能力比sse指令更强?

[复制链接]

8

主题

109

帖子

127

积分

注册会员

Rank: 2

积分
127
发表于 2005-9-1 18:00:00 | 显示全部楼层 |阅读模式
难道vc6编译器的优化能力比sse指令更强?

任务是将2个数组各项相加,放入第3个数组。即x[4]+y[4]=z[4]。andrew大师说不可能写出比如下内联汇编更高效的c/c++代码,可是我发现vc6编译器release模式帮我做到了这点。难道哪里出错了?注意:debug模式结论比较正常。源代码在下贴。

我初学sse,请高手指点。

_asm
   {
   lea esi, x
   movaps xmm0, [esi]  // move the value of x into XMM0
   addps  xmm0, y  // add the value of y to XMM0
   movaps z, xmm0  // store the results from XMM0 into z   
   } // end asm

运行结果:
E:\projects\c_c++\examples\3d_demos\ssetest\Debug>ssetest
Frequency: 3579545
test 1 average performance counter:22887
test 2 average performance counter:10849

E:\projects\c_c++\examples\3d_demos\ssetest\Debug>ssetest
Frequency: 3579545
test 1 average performance counter:23076
test 2 average performance counter:10961

E:\projects\c_c++\examples\3d_demos\ssetest\Debug>ssetest
Frequency: 3579545
test 1 average performance counter:22938
test 2 average performance counter:10850

E:\projects\c_c++\examples\3d_demos\ssetest\Debug>cd ..\release

E:\projects\c_c++\examples\3d_demos\ssetest\Release>ssetest
Frequency: 3579545
test 1 average performance counter:6
test 2 average performance counter:6061

E:\projects\c_c++\examples\3d_demos\ssetest\Release>ssetest
Frequency: 3579545
test 1 average performance counter:6
test 2 average performance counter:5948

E:\projects\c_c++\examples\3d_demos\ssetest\Release>ssetest
Frequency: 3579545
test 1 average performance counter:6
test 2 average performance counter:6455

E:\projects\c_c++\examples\3d_demos\ssetest\Release>

运行环境:
windows 2000
vc6 sp5 with sse surport,debug和release都重置为默认设置:project->setting->c++->reset
c4 2.0G cpu
768M ddr266 ram

8

主题

109

帖子

127

积分

注册会员

Rank: 2

积分
127
 楼主| 发表于 2005-9-1 18:01:00 | 显示全部楼层

Re:sse汇编高手请近,难道vc6编译器的优化能力比sse指令更

/**
* SIMD_TEST.CPP
*/

#define WIN32_LEAN_AND_MEAN

#include "windows.h"
#include "windowsx.h"
#include <stdio.h>

#define TEST_TIMES                10                        // 测试10次求平均以得到稳定结果
#define COMPUTE_TIMES        1000000        // 每项测试的计算次数
       
int main(int argc, char* argv[]){
        __declspec(align(16)) float x[4] = {1,2,3,4};
        __declspec(align(16)) float y[4] = {5,6,7,8};
        __declspec(align(16)) float z[4] = {0,0,0,0};
        __declspec(align(16)) float c[4] = {0.5, 0.5, 0.5, 0.5};

        // 使用高精度计时器,随系统的不同可以提供微秒级的计数。
        LARGE_INTEGER t1, t2, tc;
        QueryPerformanceFrequency(&tc);
        printf("Frequency: %u\n", tc.QuadPart);

        int tav1 = 0;    // 测试1(常规方法)的平均用时
        int tav2 = 0;    // 测试2(SSE汇编)的平均用时

        for(int j = 0; j < TEST_TIMES; j ++){
                // test 1......
                int i = 0;

                QueryPerformanceCounter(&t1);

                for(i = 0; i < COMPUTE_TIMES; i ++){
                        z[0] = x[0] + y[0];
                        z[1] = x[1] + y[1];
                        z[2] = x[2] + y[2];
                        z[3] = x[3] + y[3];
                }
/* z = x*x+y*y+0.5
                for(i = 0; i < 1000000; i ++){
                        z[0] = x[0]*x[0] + y[0]*y[0] + c[0];
                        z[1] = x[1]*x[1] + y[1]*y[1] + c[1];
                        z[2] = x[2]*x[2] + y[2]*y[2] + c[2];
                        z[3] = x[3]*x[3] + y[3]*y[3] + c[3];
                }
*/
                QueryPerformanceCounter(&t2);
                tav1 += (t2.QuadPart - t1.QuadPart);

                //printf("x[%f, %f, %f, %f]\n", x[0], x[1], x[2], x[3]);
                //printf("y[%f, %f, %f, %f]\n", y[0], y[1], y[2], y[3]);
                //printf("z[%f, %f, %f, %f]\n", z[0], z[1], z[2], z[3]);

                //printf("used performance counter:%u\n", t2.QuadPart - t1.QuadPart);

                // test 2......
                QueryPerformanceCounter(&t1);
               
                for(i = 0; i < COMPUTE_TIMES; i ++){
                        _asm{
                                movaps xmm0, x
                                addps  xmm0, y
                                movaps z, xmm0
                        }
/* z = x*x+y*y+0.5
                        _asm{
                                movaps xmm0, x
                                mulps  xmm0, xmm0

                                movaps xmm1, y
                                mulps  xmm1, xmm1

                                addps  xmm0, xmm1

                                movaps xmm1, c
                                addps  xmm0, xmm1

                                movaps z, xmm0
                        }
*/
                }
               
                QueryPerformanceCounter(&t2);
                tav2 += (t2.QuadPart - t1.QuadPart);

                //printf("x[%f, %f, %f, %f]\n", x[0], x[1], x[2], x[3]);
                //printf("y[%f, %f, %f, %f]\n", y[0], y[1], y[2], y[3]);
                //printf("z[%f, %f, %f, %f]\n", z[0], z[1], z[2], z[3]);

                //printf("used performance counter:%u\n", t2.QuadPart - t1.QuadPart);
        }
        printf("test 1 average performance counter:%u\n", tav1/TEST_TIMES);
        printf("test 2 average performance counter:%u\n", tav2/TEST_TIMES);

        return 0;
}

//~end of file

1

主题

5

帖子

5

积分

新手上路

Rank: 1

积分
5
发表于 2005-9-1 23:46:00 | 显示全部楼层

Re:sse汇编高手请近,难道vc6编译器的优化能力比sse指令更

其实是M$的编译器太聪明了
for(i = 0; i < COMPUTE_TIMES; i ++)
{
z[0] = x[0] + y[0];
z[1] = x[1] + y[1];
z[2] = x[2] + y[2];
z[3] = x[3] + y[3];
}
这段代码不管运行多少次结果都和运行一次一样,,所以release下根本就没给她生成代码,,
而是预先计算了一次结果,,debug下没优化是生成代码的,,所以结果正确

8

主题

109

帖子

127

积分

注册会员

Rank: 2

积分
127
 楼主| 发表于 2005-9-1 23:52:00 | 显示全部楼层

Re:sse汇编高手请近,难道vc6编译器的优化能力比sse指令更

多谢,我郁闷了很久。终于想到了这点。毫无疑问是这样的。

8

主题

109

帖子

127

积分

注册会员

Rank: 2

积分
127
 楼主| 发表于 2005-9-2 01:32:00 | 显示全部楼层

搞懂了,sse确实强大。最终代码如下。

/**
* SIMD_TEST.CPP
* 本程序测试SSE指令的性能如何。设计了两个任务来进行比较。
* 使用微秒级计时器GetPerformanceCounter,以便精确反映运算时间,执行较少运算次
* 数即可显出差别。
* 测试1:常规方法
* 测试2:SSE汇编
* 效果:做简单任务时,性能提高大概是100%,做复杂任务时,性能提高接近300%。
* 注意:请在vc6 debug模式下编译测试,如使用release模式,需禁用代码优化功能。
* 白龙(oglpc@263.net)
*/

#define WIN32_LEAN_AND_MEAN

#include "windows.h"
#include "windowsx.h"
#include <stdio.h>

#define COMPUTE_TIMES        1000000//000//00000000// 每项测试的计算次数
       
int main(int argc, char* argv[]){
        __declspec(align(16)) float x[4] = {1,2,3,4};
        __declspec(align(16)) float y[4] = {5,6,7,8};
        __declspec(align(16)) float z[4] = {0,0,0,0};
        __declspec(align(16)) float c[4] = {0.5, 0.5, 0.5, 0.5};

        // 使用高精度计时器,随系统的不同可以提供微秒级的计数。
        LARGE_INTEGER t1, t2, tc;
        QueryPerformanceFrequency(&tc);
        printf("timer Frequency: %u\n", tc.QuadPart);


        // test 1......
        int i = 0;

        QueryPerformanceCounter(&t1);

        for(i = 0; i < COMPUTE_TIMES; i ++){
/* 简单任务
                z[0] = x[0] + y[0];
                z[1] = x[1] + y[1];
                z[2] = x[2] + y[2];
                z[3] = x[3] + y[3];
//*/

///* //z = x*x+y*y+0.5 复杂任务
                z[0] = x[0]*x[0] + y[0]*y[0] + c[0];
                z[1] = x[1]*x[1] + y[1]*y[1] + c[1];
                z[2] = x[2]*x[2] + y[2]*y[2] + c[2];
                z[3] = x[3]*x[3] + y[3]*y[3] + c[3];
//*/
        }

        QueryPerformanceCounter(&t2);

        printf("x[%f, %f, %f, %f]\n", x[0], x[1], x[2], x[3]);
        printf("y[%f, %f, %f, %f]\n", y[0], y[1], y[2], y[3]);
        printf("z[%f, %f, %f, %f]\n", z[0], z[1], z[2], z[3]);

        printf("used performance counter:%u\n", t2.QuadPart - t1.QuadPart);

        // test 2......
        QueryPerformanceCounter(&t1);
               
        for(i = 0; i < COMPUTE_TIMES; i ++){
/*
                _asm{
                        movaps xmm0, x
                        addps  xmm0, y
                        movaps z, xmm0
                }
//*/
//* z = x*x+y*y+0.5
                _asm{
                        movaps xmm0, x
                        mulps  xmm0, xmm0

                        movaps xmm1, y
                        mulps  xmm1, xmm1

                        addps  xmm0, xmm1

                        movaps xmm1, c
                        addps  xmm0, xmm1

                        movaps z, xmm0
                }
//*/
        }
       
        QueryPerformanceCounter(&t2);

        printf("x[%f, %f, %f, %f]\n", x[0], x[1], x[2], x[3]);
        printf("y[%f, %f, %f, %f]\n", y[0], y[1], y[2], y[3]);
        printf("z[%f, %f, %f, %f]\n", z[0], z[1], z[2], z[3]);

        printf("used performance counter:%u\n", t2.QuadPart - t1.QuadPart);
       
        return 0;
}

//~end of file

2

主题

177

帖子

177

积分

注册会员

Rank: 2

积分
177
发表于 2005-9-2 17:51:00 | 显示全部楼层

Re:sse汇编高手请近,难道vc6编译器的优化能力比sse指令更

不要拿一两个例子来说明手写的ASM不如编译器优化的
Microsoft 的 C run-time library里的mem和string函数之类都是人手工优化的

8

主题

109

帖子

127

积分

注册会员

Rank: 2

积分
127
 楼主| 发表于 2005-9-2 18:08:00 | 显示全部楼层

Re:sse汇编高手请近,难道vc6编译器的优化能力比sse指令更

不好意思,这么简单的问题,麻烦大家了。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

作品发布|文章投稿|广告合作|关于本站|游戏开发论坛 ( 闽ICP备17032699号-3 )

GMT+8, 2025-12-27 16:55

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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