当前位置:早雪网网络学院编程文档其他语言 → Viusal C++的优化代码

Viusal C++的优化代码

减小字体 增大字体 作者:未知  来源:supcode.com收集整理  发布时间:2005-7-1 14:56:50

Mark Lacey

Microsoft Corporation

April 2003

翻译:cnss



概要:这篇文章介绍了Visual C++.NET 2003中的代码优化。另外,有些读者可能对VC.N
ET 2002的优化不太了解,所以我们会简短介绍一下全程优化(Whole Program
Optimization)。最后我们用一些例子充分表现一下VC.NET的优化性能,并对其讨论。



本文适用于:Visual C++ .NET 2003



-------------------------------------------------------------------



前言

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



Visual C++ .NET 2003
    VC.NET 2003不仅带来了两个新的优化选项,它还改进了VC.NET 2002中一些优化
性能。



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



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



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



    当没使用"/Gx"选项时,编译器会默认使用"/GB"选项,此时为"blended"优化模式。
在VC.NET 2002和VC.NET 2003中,"/GB"代表"/G6",即为Intel Pentium Pro,
Pentium II, Pentium III处理器优化



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



int i;



// Do something that assigns a value to i.



return i*15;



当使用"/G6"时,生成了目标代码:

mov   eax, DWORD PTR _i$[esp-4]

imul   eax, 15



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

mov   ecx, DWORD PTR _i$[esp-4]

mov   eax, ecx

shl   eax, 4

sub   eax, ecx



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



    相比于"/G7",使用了SSE或SSE2优化的程序,一般能减少2-3%的运行时间,个别测
试中甚至能减少5%的运行时间。



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

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

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

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



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

    1。在使用双精度浮点数时,使用SSE2指令对其处理。

    2。使SSE2指令集做64位切换。(原文:Making use of SSE2 instructions for
64-bit shifts)



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



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

int

f1(int i,  int j,  int k)

{

   return i + k;

}



int

main()

{

   int n = a+b+c+d;



   m = f1(3, n, 4);

   return 0;

}

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

mov   eax, 4

mov   ecx, 3

call   ?f1@@YAHHHH@Z

mov   DWORD PTR ?m@@3HA, eax

   


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





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



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



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

// File 1

extern void func (int *, int *);



int g, h;



int

main()

{

   int i = 0;

   int j = 1;



   g = 5;

   h = 6;



   func(&I, &j);



   g = g + i;

   h = h + i;



   return 0;

}



// File 2



extern int g;

extern int h;



void

func(int *pi, int *pj)

{

   *pj = g;

   h = *pi;

}

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

sub   esp, 8

lea   eax, DWORD PTR _j$[esp+8]

push   eax

lea   ecx, DWORD PTR _i$[esp+12]

push   ecx

mov   DWORD PTR _i$[esp+16], 0

mov   DWORD PTR _j$[esp+16], 1

mov   DWORD PTR ?g@@3HA, 5

mov   DWORD PTR ?h@@3HA, 6

call   ?func@@YAXPAH0@Z

mov   eax, DWORD PTR _i$[esp+16]

mov   edx, DWORD PTR ?g@@3HA

mov   ecx, DWORD PTR ?h@@3HA

add   edx, eax

add   ecx, eax

mov   DWORD PTR ?g@@3HA, edx

mov   DWORD PTR ?h@@3HA, ecx

xor   eax, eax

add   esp, 16

ret   0

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

sub   esp, 8

lea   ecx, DWORD PTR _j$[esp+8]

lea   edx, DWORD PTR _i$[esp+8]

mov   DWORD PTR _i$[esp+8], 0

mov   DWORD PTR ?g@@3HA, 5

mov   DWORD PTR ?h@@3HA, 6

call   ?func@@YAXPAH0@Z

mov   DWORD PTR ?g@@3HA, 5

xor   eax, eax

add   esp, 8

ret   0



表现优化的最好例子

    VC编译器包括两个主要的优化参数,"/O1"和"/O2"。"/O1"代表最小尺寸,选了它编
译器认为用了以下选项。

    1./Og  全局优化,比如经常用到的变量使用寄存器保存,或者循环内的计算优化

    2./Os  程序(exe或

[1] [2]  下一页


Tags:Viusal,++,优化,代码
[数据载入中...] [返回上一页] [打 印]