体验Visual C++ 2005的现代语言特性(4)

更好的代码优化

  一个好的软件开发者总会想方设法提高软件的执行效率,编译器的编写者是一种特殊类型的开发者,不仅代码要执行效率高,而且由它们生成的代码也必须极有效率。因此,任何一个成功的编译器产品,优秀的后台优化是必不可少的。而在这方面,Visual C++ 2005脱颖而出。

  Visual Studio .NET 2002和Visual Studio .NET 2003在C++编译器中引入了一些非常好的优化方式,也花了很大气力改善本地代码的执行效率,加入了对Intel Pentium 4 CPU的SSE和SSE2指令支持。特别值得一提的是,还加入了全局程序优化WPO(Whole Program Optimization),可允许链接器在链接.obj文件时,对整个程序进行优化。这些.obj文件与一般.obj文件有所不同,因为它们不但包含了本地机器码,而且还包含了一些中间语言数据,以便编译器的前端和后台之间进行沟通。链接器可把这些文件当成一个大的整体单元来优化,生成更多的内联函数,进行更好的堆栈对齐,还可在多种情况下,使用定制的函数调用约定。Visual C++ 2005在基于自上而下、从底至上的程序结构分析基础上,在WPO上进行了改进,使之更进一步,而最大的改进之处就是配置向导优化PGO(Profile Guided Optimization)了。

   对源代码的静态分析,仍留给了编译器许多未解决的问题。就拿对两个变量的比较语句来说,第一个通常比第二个大吗?在switch语句中,哪一个case子句是经常被执行的呢?哪个函数是经常被调用的,而又哪些代码是“冷代码”——即不经常执行的呢?如果编译器在编译时就能知道代码在运行时的状态,就能进行更好的优化,这就是Visual C++ 2005编译器改进的着力之处。


图4:配置向导优化  
   图4图示了PGO的编译流程,第一步是编译代码,并把它们链接成由一系列配置计数探测数据组成的配置文件。在WPO下,编译器生成的.obj文件不再包含本地机器码,而由中间语言数据组成。这些计数数据由两部分组成:数值计数与命中计数;数值计数常用来表示变量数值的柱状图,而命中计数用来跟踪程序中的特定代码区域被执行了多少次。先运行一个应用程序,再进行一些通常的操作,就能从这些计数中收集相应的数据,并写入一个配置数据库中。当原始的.obj文件被送往链接器时,配置数据也同时被送回链接器,此时链接器就可以进行分析,以决定采取怎样的优化,并最终生成一个不含配置信息的程序,而此最终版本就可发布给用户使用。

   配置向导优化可进行多种多样的优化。基于命中计数,能在每个调用点都决定是否采用内联函数;而数值计数,可使switch和if-else结构重新排列,以便找出最常用的数值,从而避免不必要的检查。代码段也能被重新排列,使最常用的代码能一直执行,而不是强制一些不必要的跳转,从而避免TLB(Translation Lookaside Buffer)发生颠簸和页面调度。

   “冷代码”被编译器放置在模块的特定区,以避免上述情况的发生;在某一特定类型的虚拟调用点上,虚拟调用推测能避免vtable查找;局部内联可对“热代码”进行内联化处理。另外,代码的特定区域也能有针对性地进行某种优化,而其他区域进行另外某种优化,例如,“热代码”或小型函数能被指定编译为最快速度(/O2),而“冷代码”或大型函数能被指定编译为占用最小空间(/O1)。

   如果十分清楚程序运行的真实情况,可在配置文件生成时,不断地在此模拟情况下运行程序,而最终的程序执行效率将会得到极大的提升。最近,SQL Server使用PGO重新编译,结果在多数应用环境下,可得到最高30%的效率提升;由此看来,微软会使用此技术来编译它的全部产品。要注意的是,不要在配置文件生成时,试图进行完全代码路径覆盖,PGO的中心点是针对普通使用情况,来决定是否优化,如果试图进行完全代码路径覆盖,只会自食其果。

   Visual C++ 2005也加入了对OpenMP的支持,OpenMP是一个用于创建多线程程序的开放规范,它由一组pragma组成,指示编译器可把某段代码进行并行处理。不依赖前一个迭代结果的大循环代码就非常适合OpenMP,请看下面简单的拷贝函数,它把数组a和b中的数值相加,存放于数组c中:

void copy(int a[], int b[], int c[], int length)
{
 #pragma omp parallel
 for(int i=0; i<length; i++)
 {
  c[i] = a[i] + b[i];
 }
}

  在多处理器电脑上,编译器将生成多线程来执行此循环的迭代,每个线程都会执行拷贝操作的一个子集。需注意,编译器不会去检查循环是否存在依赖性,因而甚至不会阻止你在一此不适合的情况下使用pragma。如果存在依赖,即使程序对规范而言是正确的,也会得到与预期相反的结果。

  虽然OpenMP的最大好处是并行执行如上所示的循环,但顺序代码也能从中得到性能上的提高,“#pragma omp section”可被直接用于区分代码中的非依赖区,允许开发者指定可并行执行的区域,接下来,编译器可生成多线程代码,以在不同的处理器上执行这些代码段。

  对使用 .NET的开发者来说,最重要的一个变化就是,当目标平台为MSIL时,编译器会像对待本地代码平台一样,进行绝大多数都相同的优化。虽然现今的JIT即时编译器是在运行时为优化进行分析,但允许C++编译器在初始编译期间进行优化,仍能产生可观的优化效果(相对JIT即时编译器,C++编译器有更多的时间进行它的分析)。Visual C++ 2005是首次对托管类型进行优化,包括循环优化、表达式优化、内联优化,而通常这些是编译器不能进行 .NET代码优化的地方。例如,因为指针算法的不可验证性,将导致强度消减问题;又因为CLR的严格类型和成员访问需要,某些代码可能不会被内联化。另外,优化MSIL也要根据即时编译器所面对的代码,作出一个平衡,举例来说,你可能不想打开一个循环,并把过多的变量暴露给即时编译器,因此,它就必须进行寄存器分配(一个NP-complete问题)。

时间: 2024-10-27 07:37:55

体验Visual C++ 2005的现代语言特性(4)的相关文章

体验Visual C++ 2005的现代语言特性(5)

可靠的安全 在2002年,Bill Gates宣布进行的可信赖计算,已对微软公司开发的所有产品带来了深刻的影响.Windows操作系统的开发者花了数月的时间来进行安全方面的训练及代码重审,带来的结果就是,Windows Server 2003成了该公司有史以来发布的最安全的操作系统.Microsoft Office 2003也包含了许多的安全功能,像IRM(Information Rights Management).加强的宏安全.Outlook中阻止下载HTML等等.而Visual C++ 2

体验Visual C++ 2005的现代语言特性(1)

当年Visual Studio.NET 2003 C++编译器的面世,令无数C++语言爱好者都对此垂涎不已:它与ISO C++标准保持98%的一致--这比以前任何一个版本都更加接近,和一体化的语言支持特性,如局部模板特定化:同时也包括了增强的缓冲区安全检查和改进的编译器诊断功能.以往使用C#和Visual Basic.NET的开发者,通过简单的拖放操作,就能生成稳健的Windows窗体应用程序,如今,C++的开发者也加入了进来,而且,这个编译器还对Intel Pentium 4和AMD Athl

体验Visual C++ 2005的现代语言特性(2)

新的Interop 在Visual Studio .NET 2003的所有基于 .NET Framework的语言当中,Visual C++ 2005提供了最好的interop功能.它可不像是纸上谈兵,如今具有了足够的能力来实现真实世界中的场景,一个最好的例子就是把Quake II移植到 .NET Framework平台上,而Visual C++ 2005则更加扩展了这项功能. 在本地和托管世界中,.NET有四种主要的方法可进行interop.对COM的interop可使用RCW(Runtime

体验Visual C++ 2005的现代语言特性(3)

It Just Works 在Visual Studio .NET 2003,C++的interop技术叫做IJW或者"It Just Works",在新版本中,已换成了更贴切的"Interop技术".那它的工作原理是怎样的呢?对程序中的每一个本地方法,编译器同时生成一个托管和非托管进入点,它们中只有一个是真正方法的实现,另一个则是转发器,可进行相应的转换和必要的调度.托管进入点通常是真正方法的实现,除非代码不能解释为MSIL或开发者使用"#pragma

体验Visual Studio 2005中C++语言

Viusal Studio2005极大地丰富了它的库,可以说是科研背后的清障机和加速器,对于这一点,我想大部分人都是这么认为的.它带来的大量工具及新增的功能性函数使开发人员的生活越来越快乐.简单.但对于我来说,所有这些与Visual Studio2005在C++上做的改变相比却都显得是那么苍白无力.这篇文章中,我着重叙述即将向用户发行的Viusal Studio2005版本给C++带来的变化. 一.对下划线说再见 Visual Studio.NET 2002在C++中引入了可扩展的托管,这种扩展

LINQ体验(2)——C# 3.0新语言特性和改进(上篇)

在第一篇中,知道了Visual Studio 2008新特性,从这篇开始进入此系列的 第二部分--介绍C# 3.0新语言特性和改进. 总体来说, Visual Studio 2008和.NET 3.5是建立在.NET2.0核心的基础之上,.NET2.0核心 本身将不再变化(如果不了解.NET2.0的朋友,请参看MSDN或者一些经典的书籍 ),C# 3.0新语言特性在.NET2.0基础上进行了改进,这些改进的功能可以大大 简化我们编写程序.关于C# 3.0新语言特性在博客园里的很多朋友都介绍了,我

LINQ体验(3)——C# 3.0新语言特性和改进(下篇)

上一篇我们介绍了C# 3.0新语言特性和改进上部分,这篇我们继续介绍剩下 的部分. C# 3.0新语言特性和改进包括: 自动属性(Auto- Implemented Properties) 隐含类型局部变量(Local Variable Type Inference) 匿名类型(Anonymous Types) 对象与集合初始化器 (Object and Collection Initializers) 扩展方法(Extension Methods) Lambda表达式和Lambda表达式树 (

体验Visual Studio 2005之类设计器

Visual Studio 类设计器是通用语言运行库的多功能.可视化设计环境.使用 Visual Studio 类设计器可以显现类和其他类型的结构,还可以通过可视化表示方法编辑它们的源代码.对类图的更改将直接反映在代码中,且对代码的更改会直接影响设计器的外观.设计器和代码之间的同步关系,使得可视化创建和配置复杂的 CLR 类型变得容易. 类设计器包含一些专门设计的功能,这些功能将有助于重构代码.方便地重命名标识符以及重载方法.您可以自动生成类和结构,并通过自动生成存根可以实现接口. 最后,类设计

Visual Studio 2005 中的新特性

http://www.c-sharpcorner.com/UploadFile/mahesh/VS2005Editor11162005003633AM/VS2005Editor.aspx?ArticleID=8de67dd3-cc4e-4fb8-a76e-a002d4c0d16e