帶你玩轉Visual Studio——效能分析與最佳化

來源:互聯網
上載者:User

標籤:

上一篇文章帶你玩轉Visual Studio——VC++的多線程開發講了VC++中多線程的主要用法。多線程是提升效能和解決並發問題的有效途經。在商用程式的開發中,效能是一個重要的指標,程式的效能最佳化也是一個重要的工作。

找到效能瓶頸

二八法則適合很多事物:最重要的只佔其中一小部分,約20%,其餘80%的儘管是多數,卻是次要的。在程式碼中也是一樣,決定應用效能的就那20%的代碼(甚至更少)。因此最佳化實踐中,我們將精力集中最佳化那20%最耗時的代碼上,這那20%的代碼就是程式的效能瓶頸,主要針對這部分代碼進行最佳化。

常見最佳化方法:

這部分我就不寫,直接參見《效能調優攻略》,因為我沒有自信能寫出比這更好的。

如果不想這麼深入地瞭解,看看《C++程式常見的效能調優方式》這篇文章也是不錯的。

應用案例

我們以一個應用案例來講解,以至於不會那麼乏味難懂。

我們知道能被1和它本身整除的整數叫質數,假設1到任意整數N的和為Sn(Sn=1+2+3+…+n)。現在要求10000到100000之間所有質數和Sn。

可能你會覺得這問題不是So Easy嗎!都不用腦袋想,咣當一下就把代碼寫完了,代碼如下:

#include <iostream>#include <windows.h>// 定義64位整形typedef __int64 int64_t;// 擷取系統的目前時間,單位微秒(us)int64_t GetSysTimeMicros(){    // 從1601年1月1日0:0:0:000到1970年1月1日0:0:0:000的時間(單位100ns)#define EPOCHFILETIME   (116444736000000000UL)    FILETIME ft;    LARGE_INTEGER li;    int64_t tt = 0;    GetSystemTimeAsFileTime(&ft);    li.LowPart = ft.dwLowDateTime;    li.HighPart = ft.dwHighDateTime;    // 從1970年1月1日0:0:0:000到現在的微秒數(UTC時間)    tt = (li.QuadPart - EPOCHFILETIME) / 10;    return tt;}// 計算1到n之間所有整數的和int64_t CalculateSum(int n){    if (n < 0)    {        return -1;    }    int64_t sum = 0;    for (int i = 0; i < n; i++)    {        sum += i;    }    return sum;}// 判斷整數n是否為質數bool IsPrime(int n){    if (n < 2)    {        return false;    }    for (int i = 2; i < n; i++)    {        if (n %i == 0)        {            return false;        }    }    return true;}void PrintPrimeSum(){    int64_t startTime = GetSysTimeMicros();    int count = 0;    int64_t sum = 0;    for (int i = 10000; i <= 100000; i++)    {        if (IsPrime(i))        {            sum = CalculateSum(i);            std::cout << sum << "\t";            count++;            if (count % 10 == 0)            {                std::cout << std::endl;            }        }    }    int64_t usedTime = GetSysTimeMicros() - startTime;    int second = usedTime / 1000000;    int64_t temp = usedTime % 1000000;    int millise = temp / 1000;    int micros = temp % 1000;    std::cout << "執行時間:" << second << "s " << millise << "‘ " << micros << "‘‘" << std::endl;}

然後一運行,耗時9s 659’ 552”(9秒659毫秒552微秒)。我想這肯定不是你要的結果(太慢了),如果你覺得還滿意,那下面的就可以不用看了。

VS的效能分析工具效能分析工具的選擇

開啟一個“效能分析”的會話:Debug->Start Diagnotic Tools Without Debugging(或按Alt+F2),VS2013在Analysis菜單中。


效能分析

CPU Usage

檢測CPU的效能,主要用於發現影響CPU瓶頸(消耗大量CPU資源)的代碼。

GPU Usage

檢測GPU的效能,常用於圖形引擎的應用(如DirectX程式),主要用於判斷是CPU還是GPU的瓶頸。

Memory Usage

檢測應用程式的記憶體,發現記憶體。

Performance Wizard

效能(監測)嚮導,綜合檢測程式的效能瓶頸。這個比較常用,下面再逐一說明。

效能(監測)嚮導
  1. 指定效能分析方法;

    效能分析方法
    CPU Sampling(CPU採樣):
    進行採樣統計,以低開銷水平監視佔用大量CPU的應用程式。這個對於計算量大的程式可大大節省監控時間。
    Instrumentation(檢測):
    完全統計,測量函數調用計數和用時
    .NET memory allocation(.NET 記憶體配置):
    跟蹤託管記憶體配置。這個好像只有Managed 程式碼(如C#)才可用,一般以C++代碼好像不行。
    Resource contention data(並發):
    檢測等待其他線程的線程,多用於多線程的並發。
  2. 選擇要檢測的模組或應用程式;
  3. 啟動剖析器進行監測。
效能分析報告

程式分析完成之後會產生一個分析報告,這就是我們需要的結果。


效能分析報告概要

檢視類型

有幾個不同的視圖可供我們切換,下面加粗的部分是個人覺得比較方便和常用的視圖。
Summary(概要):整個報告概要說明
Call Tree(調用樹):以樹形表格的方式展開函數之間的關係。
Module(模組):分析調用的不同的程式模組,如不同的DLL、lib模組的耗時
Caller/Callee(調用與被調用):以數值顯示的調用與被調用的關係
Functions(函數統計):以數值顯示的各個函數的執行時間和執行次數統計值
Marks(標記):
Processers(進程):
Function Detials(函數詳情):以圖表的方式形象地顯示:調用函數-當前函數-被調用子函數之間的關係和時間比例。



調用樹

函數詳情

函數統計

專用術語

如果是第一次看這報告,你還不一定能看懂。你需要先瞭解一些專用術語(你可以對照著Call Tree視圖和Functions視圖去理解):
Num of Calls:(函數)調用次數
Elapsed Inclusive Time:功能內含耗用 (Elapsed Inclusive) 時間
Elapsed Exclusive Time:功能專屬耗用 (Elapsed Exclusive) 時間
Avg Elapsed Inclusive Time:平均功能內含耗用 (Elapsed Inclusive) 時間
Avg Elapsed Exclusive Time:平均功能專屬耗用 (Elapsed Exclusive) 時間
Module Name:模組名稱,一般為可執行檔(.exe)、動態庫(.dll)、靜態庫(.lib)的名稱。

也許看完你還迷糊,只要理解什麼是獨佔與非獨佔你就都明白了。

什麼是獨佔與非獨佔

非獨佔樣本數是指的包括了子函數執行時間的總執行時間
獨佔樣本數是不包括子函數執行時間的函數體執行時間,函數執行本身花費的時間,不包括子(函數)樹執行的時間。

解決應用案例問題

我們已經大致瞭解了VS2015效能分析工具的使用方法。現在迴歸本質,解決上面提及的應用案例的問題。

1、我們選擇Function Detials視圖,從根函數開始依據百分比最大的項選擇,直到選擇PrintPrimeSum,這時可以看到如:


找出效能瓶頸1
我們可以看到IO佔了50%多(49.4%+9.7%)的時間,所以IO是最大的效能瓶頸。其實,有一定編程經驗的人應該都能明白,在控制台輸出資訊是很耗時的。我們只是需要結果,不一定非要在控制中全部輸出(這樣還不便查看),我們可以將結果儲存到檔案,這樣也比輸出到控制台快。

註:所示的時間,應該是內含時間的百分比。

知道了瓶頸,就改進行代碼最佳化吧:

void PrintPrimeSum(){    int64_t startTime = GetSysTimeMicros();    std::ofstream outfile;    outfile.open("D:\\Test\\PrimeSum.dat", std::ios::out | std::ios::app);    int count = 0;    int64_t sum = 0;    for (int i = 10000; i <= 100000; i++)    {        if (IsPrime(i))        {            sum = CalculateSum(i);            outfile << sum << "\t";            count++;            if (count % 10 == 0)            {                outfile << std::endl;            }        }    }    outfile.close();    int64_t usedTime = GetSysTimeMicros() - startTime;    int second = usedTime / 1000000;    int64_t temp = usedTime % 1000000;    int millise = temp / 1000;    int micros = temp % 1000;    std::cout << "執行時間:" << second << "s " << millise << "‘ " << micros << "‘‘" << std::endl;}

再次執行,發現時間一下減小到:3s 798’ 218”。效果很明顯!

2、但這還不夠,繼續檢查別的問題,對新代碼再次用效能分析工具檢測一下。


找出效能瓶頸2

我們發現IsPrime函數佔用了62%的時間,這應該是一個瓶頸,我們能不能對其進行演算法的最佳化?仔細想想,上面求質數的方法其實是最笨的方法,稍微對其進行最佳化一下:

// 判斷整數n是否為質數bool IsPrime(int n){    if (n < 2)    {        return false;    }    if (n == 2)    {        return true;    }    //把2的倍數剔除掉    if (n%2 == 0)    {        return false;    }    // 其實不能被小於n的根以下的數整除,就是一個質數    for (int i = 3; i*i <= n; i += 2)    {        if (n % i == 0)        {            return false;        }    }    return true;}

再次執行,發現時間一下減小到:1s 312’ 75”,幾乎減了一半的時間。

3、這還是有點慢,再看看還能不能進行最佳化。對新代碼再次用效能分析工具檢測一下。


找出效能瓶頸2

CalculateSum函數佔了88.5%的時間,這絕對是影響目前程式效能的主要因素。對其進行。仔細想想,求1到N的和其實就是求1、2、3 … N的等差數列的和。最佳化代碼如下:

// 計算1到n之間所有整數的和int64_t CalculateSum(int n){    if (n < 0)    {        return -1;    }    //(n * (1 + n)) / 2    return ( n * (1 + n) ) >> 1;}

再次執行,發現時間一下減小到:0s 91’ 6”,一秒中之內,基本上可以滿足要求子。

總結

程式效能調優,就是數上面這樣一點點地改進的過程,直到滿足應用的要求。上面只用了一個視圖的一種統計指標(各函數所用時間佔總時間的百分比),就解決了問題。對於大型的複雜應用程式,我們可以結果多種視圖的多種統計指標進行綜合判斷,找出程式效能的瓶頸!

上一篇回顧:
帶你玩轉Visual Studio——VC++的多線程開發

下一篇要講述的內容:
帶你玩轉Visual Studio——單元測試

帶你玩轉Visual Studio——效能分析與最佳化

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.