c#

位置:IT落伍者 >> c# >> 浏览文章

Viusal C++.NET 2003 的优化代码


发布日期:2021年11月10日
 
Viusal C++.NET 2003 的优化代码

前言

人们在使用一个新的编程工具时总会感到缺乏自信本文试图让你对VC的代码优化有更直观的感觉希望你能通过阅读本文从VC中得到更多的东西

Visual C++ NET

VCNET 不仅带来了两个新的优化选项它还改进了VCNET 中一些优化的性能

第一个新增选项是/G它告诉编译器对Intel Pentium 和AMD Athlon处理器进行优化

使用/G选项编译的程序当我们和VCNET 生成的代码比较时发现它通常能使典型的程序的运行速度提高个百分点如果使用了大量浮点代码甚至能提高个百分点而提高的优化程度可能很高也可能较低在一些使用最新CPU和/G选项的测试中甚至提高了%的性能

使用/G选项不代表生成的代码只能运行在Intel Pentium 和AMD Athlon处理器上这些代码仍可以运行在老的CPU上只是在性能表现上可能有小小的惩罚另外我们观察到一些程序使用/G后在AMD Athlon上运行的比用Intel Pentium 更慢

当没使用/Gx选项时编译器会默认使用/GB选项此时为blended优化模式在VCNET 和VCNET /GB代表/G即为Intel Pentium Pro Pentium II Pentium III处理器优化

这儿有一个例子它展示了做与常整数乘法时使用Pentium /G的优化效果下面是源代码

int i;

// Do something that assigns a value to i

return i*;

当使用/G生成了目标代码

mov eax DWORD PTR _i$[esp]

imul eax

当使用/G生成了更快(可惜更长)的代码它没用imul(乘)指令在Pentium 上执行只需要个周期目标代码如下

mov ecx DWORD PTR _i$[esp]

mov eax ecx

shl eax

sub eax ecx

第二个优化选项是/arch:[argument]用它可对SSE或SSE优化生成使用Streaming SIMD Extensions (SSE) 和 Streaming SIMD Extensions (SSE) 指令集的程序当使用/arch:SSE选项时目标代码只能运行在支持SSE指令(如CMOV FCOMI FCOMIP FUCOMI FUCOMIP)的CPU上当使用/arch:SSE选项时目标代码只能运行在支持SSE指令集的CPU上

相比于/G使用了SSE或SSE优化的程序一般能减少%的运行时间个别测试中甚至能减少%的运行时间

使用/arch:SSE可得到以下效果

在使用单精度浮点数时使用SSE指令对其处理

使用CMOV指令它最早被Pentium Pro支持

使用FCOMI FCOMIP FUCOMI FUCOMIP指令它们也是最早被Pentium Pro支持的

使用/arch:SSE的话可以得到所有/arch:SSE选项的效果另外还有以下几个效果

在使用双精度浮点数时使用SSE指令对其处理

使SSE指令集做位切换(原文Making use of SSE instructions for bit shifts)

还有其它的好处在同时使用/arch:SSE/arch:SSE/GL(全程优化)选项选项时编译器会对浮点参数和浮点返回值做函数调用规则优化

上面说的几点优化特性已经包括于VCNET 里了另外还有一点就是能消除死参数从没被用过的参数比如

int

f(int i int j int k)

{

return i + k;

}

int

main()

{

int n = a+b+c+d;

m = f( n );

return ;

}

在函数f()中第二个参数从没被使用过当我们用/GL(全程优化)选项时编译器将产生如下目标代码来调用f()

mov eax

mov ecx

call ?f@@YAHHHH@Z

mov DWORD PTR ?m@@HA eax

在这个例子里变量n从没被运算只有两个参数被f()使用所以只传递那两个参数(并且它们是从寄存器传过去的这比使用栈传更快)另外编译这个例子时要禁止内联(inlining)否则函数f()就不存在了而直接给m赋予值

Visual C++ NET

VCNET 引入了全程优化(Whole Program Optimization缩写为WPO)的概念/GL选项代表使用全程优化全程优化意味着编译器在obj文件中存放的是代码的中间表达而不是目标代码在连接时连接器对其优化处理并生成真正的目标代码

全程优化的一个主要好处在于我们可以跨越源文件进行函数内联这将大大提高程序的性能还有一个好处在于编译器可以跟蹤内存和寄存器的使用以便优化使函数调用的开销更小

下面的代表展示了全程优化的表现

// File

extern void func (int * int *);

int g h;

int

main()

{

int i = ;

int j = ;

g = ;

h = ;

func(&I &j);

g = g + i;

h = h + i;

return ;

}

// File

extern int g;

extern int h;

void

func(int *pi int *pj)

{

*pj = g;

h = *pi;

}

当不使用/GL选项时生成了如下代码

sub esp

lea eax DWORD PTR _j$[esp+]

push eax

lea ecx DWORD PTR _i$[esp+]

push ecx

mov DWORD PTR _i$[esp+]

mov DWORD PTR _j$[esp+]

mov DWORD PTR ?g@@HA

mov DWORD PTR ?h@@HA

call ?func@@YAXPAH@Z

mov eax DWORD PTR _i$[esp+]

mov edx DWORD PTR ?g@@HA

mov ecx DWORD PTR ?h@@HA

add edx eax

add ecx eax

mov DWORD PTR ?g@@HA edx

mov DWORD PTR ?h@@HA ecx

xor eax eax

add esp

ret

当使用了/GL你会看到下面的代码现在的代码短多了注意编译这个例子时同样要注意关掉内联优化

sub esp

lea ecx DWORD PTR _j$[esp+]

lea edx DWORD PTR _i$[esp+]

mov DWORD PTR _i$[esp+]

mov DWORD PTR ?g@@HA

mov DWORD PTR ?h@@HA

call ?func@@YAXPAH@Z

mov DWORD PTR ?g@@HA

xor eax eax

add esp

ret

               

上一篇:C#窗体的应用

下一篇:使用ADO.NET2.0提升数据交互性能(1)