程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> vc教程 >> Viusal C++.NET的優化代碼

Viusal C++.NET的優化代碼

編輯:vc教程

  前言

  人們在使用一個新的編程工具時總會感到缺乏自信,本文試圖讓你對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優化,生成使用Streaming 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

  1. 上一頁:
  2. 下一頁:
欄目導航
Copyright © 程式師世界 All Rights Reserved