前面我们用VC6测试了位掩码代替分支的速度。VC6是1998年发售的,离现在有14年了。在14年里,Intel与AMD的CPU都换了好几套微架构了,VC6编译器很可能无法充分发挥它们的性能。而且,从2003年AMD推出了64位处理器开始,现在64位系统越来越普及,我们希望测试64位下的性能。
于是选择最新的VC系列编译器——Visual C++ 2010,它是2010年发售的,支持x64平台。一、代码改进
1.1 通用字符处理——tchar.h
传统的Windows程序一般使用ANSI+DBCS字符集。而从Windows NT开始,Windows内核采用Unicode字符集。但那时基于ANSI+DBCS的Win9X系统还很流行,所以VC6默认使用ANSI+DBCS字符集。
虽然VC6中也有用于通用字符处理的“tchar.h”。但考虑到传统的C语言教学,一般很少用到它。如今WinXP替代Win9X已经有很多年了,甚至都快被Win7取代了,ANSI+DBCS字符集已经退出历史舞台。于是VC2010默认使用Unicode字符集。我们应使用“tchar.h”做通用字符处理。使用要点有——
1.字符类型。用“_TCHAR”替代“char”。2.字符串常量。用“_T”这个宏来定义字符串常量。如“_T("\n")”。3.字符串函数。相对于传统的C语言标准函数,tchar函数的特点是函数名前面多了“_t”。如“_tprintf(_T("\n"));”4.程序入口。传统C语言程序的入口是“main”函数,而现在是“_tmain”函数。如“int _tmain(int argc, _TCHAR* argv[])”。 1.2 检测64位环境因考虑到程序会在64位环境下运行,所以需要检测64位环境。检测方法——
VC 64位程序开发心的——获得程序位数和操作系统位数 二、全部代码全部代码——
// 用位掩码做饱和处理.用求负生成掩码 #define LIMITSU_FAST(n, bits) ( (n) & -((n) >= 0) | -((n) >= (1<<(bits))) ) #define LIMITSU_SAFE(n, bits) ( (LIMITSU_FAST(n, bits)) & ((1<<(bits)) - 1) ) #define LIMITSU_BYTE(n) ((BYTE)(LIMITSU_FAST(n, 8))) // 用位掩码做饱和处理.用带符号右移生成掩码 #define LIMITSW_FAST(n, bits) ( ( (n) | ((signed short)((1<<(bits)) - 1 - (n)) >> 15) ) & ~((signed short)(n) >> 15) ) #define LIMITSW_SAFE(n, bits) ( (LIMITSW_FAST(n, bits)) & ((1<<(bits)) - 1) ) #define LIMITSW_BYTE(n) ((BYTE)(LIMITSW_FAST(n, 8))) // 数据规模 #define DATASIZE 16384 // 128KB / (sizeof(signed short) * 4) // 缓冲区 signed short bufS[DATASIZE*4]; // 源缓冲区。64位的颜色(4通道,每通道16位) BYTE bufD[DATASIZE*4]; // 目标缓冲区。32位的颜色(4通道,每通道8位) // 测试时的函数类型 typedef void (*TESTPROC)(BYTE* pbufD, const signed short* pbufS, int cnt); // 用if分支做饱和处理 void f0_if(BYTE* pbufD, const signed short* pbufS, int cnt) { const signed short* pS = pbufS; BYTE* pD = pbufD; int i; for(i=0; i255) ? 255 : (BYTE)pS[0] ); pD[1] = (pS[1]<0) ? 0 : ( (pS[1]>255) ? 255 : (BYTE)pS[1] ); pD[2] = (pS[2]<0) ? 0 : ( (pS[2]>255) ? 255 : (BYTE)pS[2] ); pD[3] = (pS[3]<0) ? 0 : ( (pS[3]>255) ? 255 : (BYTE)pS[3] ); // next pS += 4; pD += 4; } } // 用min、max饱和处理 void f1_min(BYTE* pbufD, const signed short* pbufS, int cnt) { const signed short* pS = pbufS; BYTE* pD = pbufD; int i; for(i=0; i ")); _getch(); } _tprintf(_T("\n")); // 进行测试 runTest(_T("f0_if"), f0_if); runTest(_T("f1_min"), f1_min); runTest(_T("f2_neg"), f2_neg); runTest(_T("f3_sar"), f3_sar); // 结束前提示 if (argc<=1) { _tprintf(_T(" ")); _getch(); } _tprintf(_T("\n")); return 0; }
3.1 输出汇编代码
配置方法如下——
1.点击菜单栏的 项目->属性,打开项目的属性页。2.在左边的功能树中选择 配置属性->C/C++->输出文件。3.在右边的“汇编程序输出”中选择“带源代码的程序集”。 3.2 配置winmm.lib库配置方法如下——
1.点击菜单栏的 项目->属性,打开项目的属性页。2.在左边的功能树中选择 配置属性->链接器->输入。3.在右边的“附加依赖项”中添加“Winmm.lib”。 3.3 配置x64平台点击菜单栏的 生成->配置管理器,打开“配置管理器”对话框,新建平台“x64”。
具体细节可参考MSDN——
如何:针对 64 位平台配置 Visual C++ 项目 3.4 编译生成点击菜单栏的 生成->批生成。生成Release版。
四、测试结果运行“Release\noifVC2010.exe”,在32位winXP上的测试结果——
== noif:VC2010(32) on 32bit ==f0_if[1]: 1793 f0_if[2]: 1812 f0_if[3]: 1733 f1_min[1]: 2112 f1_min[2]: 2111 f1_min[3]: 2132 f2_neg[1]: 511 f2_neg[2]: 519 f2_neg[3]: 512 f3_sar[1]: 442 f3_sar[2]: 436 f3_sar[3]: 437
运行“Release\noifVC2010.exe”,在64位win7上的测试结果——
== noif:VC2010(32) on 64bit ==f0_if[1]: 1731 f0_if[2]: 1716 f0_if[3]: 1685 f1_min[1]: 2106 f1_min[2]: 2106 f1_min[3]: 2090 f2_neg[1]: 500 f2_neg[2]: 514 f2_neg[3]: 515 f3_sar[1]: 437 f3_sar[2]: 421 f3_sar[3]: 437
运行“x64\Release\noifVC2010.exe”,在64位win7上的测试结果——
== noif:VC2010(64) on 64bit ==f0_if[1]: 1638 f0_if[2]: 1623 f0_if[3]: 1622 f1_min[1]: 1997 f1_min[2]: 1997 f1_min[3]: 2012 f2_neg[1]: 421 f2_neg[2]: 437 f2_neg[3]: 421 f3_sar[1]: 328 f3_sar[2]: 327 f3_sar[3]: 328
硬件环境——
CPU:Intel Core i3-2310M, 2100 MHz内存:DDR3-1066
源码下载——
(建议阅读编译器生成的汇编代码,位于“Release\noifVC2010.asm”、“x64\Release\noifVC2010\noifVC2010.asm”)