国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發(fā)設(shè)計 > 正文

C++ 性能剖析 (一)

2019-11-15 01:46:06
字體:
供稿:網(wǎng)友
C++ 性能剖析 (一)C++ 性能剖析 (一)

性能問題也不是僅僅用“技術(shù)”可以解決的,它往往是架構(gòu),測試,假設(shè)等綜合難題。不過,對于一個工程師來說,必須從小做起,把一些“明顯”的小問題解決。否則的話積小成多,千里堤壩,潰于蟻穴。

C++ 的性能為什么總是排在C之后 (見http://benchmarksgame.alioth.debian.org/u32/performance.php?test=binarytrees 等網(wǎng)站的最新測試結(jié)果)?我認為這是3個方面的原因:

1)用于測試的C++ 編譯器沒有使用最新的優(yōu)化技術(shù)

2)C++ 附加的價值沒有考慮到測試之中

3)C++ 應(yīng)用層面的“微妙性”(可參考我的關(guān)于C++的其他博客)使得一般程序員往往望而卻步,選擇“教科書用例”,使得一些副作用沒有在應(yīng)用層面被剔出。

記得10多年前,我在微軟做開發(fā)時,曾向C++最早編譯器的作者李伯曼(Stan Lippman)(時任微軟VC++架構(gòu)師)咨詢過一系列我們小組的C++性能難題,在他的幫助下,我們在關(guān)鍵地方用了諸如inline,RVO等技術(shù),完全解決了性能問題,還找出了VC++ 的幾個不小的錯誤。我認識到,C++的性能問題多數(shù)在于我們對C++認識的淺薄,多數(shù)都是不難解決的。

下面用一例子,來做一下對比,看看一些微妙的細節(jié)是如何影響程序性能的。

struct intPair

{

int ip1;

int ip2;

intPair(int i1, int i2) : ip1(i1), ip2(i2) {}

intPair(int i1) : ip1(i1), ip2(i1) {}

};

// Calc sum (usinh value semantic)

Int Sum1(intPair p)

{

return p.ip1 + p.ip2;

}

// Calc sum (usinh ref semantic)

int Sum2(intPair &p)

{

return p.ip1 + p.ip2;

}

// Calc sum (usinh const ref semantic)

Int Sum3(const intPair& p)

{

return p.ip1 + p.ip2;

}

上面這個簡單的struct,有三個Sum函數(shù),作的事情完全一樣,但是性能是否一樣呢?我們用下面的程序來測試:

double Sum(int t, int loop)

{

using namespace std;

if (t == 1)

{

clock_t begin = clock();

int x =0;

for(int i = 0; i < loop; ++i)

{

x += Sum1(intPair(1,2));

}

clock_t end = clock();

return double(end - begin) / CLOCKS_PER_SEC;

}

else if (t == 2)

{

clock_t begin = clock();

int x =0;

intPair p(1,2);

for(int i = 0; i < loop; ++i)

{

x += Sum1(p);

}

clock_t end = clock();

return double(end - begin) / CLOCKS_PER_SEC;

}

else if (t == 3)

{

clock_t begin = clock();

int x =0;

intPair p(1,2);

for(int i = 0; i < loop; ++i)

{

x += Sum2(p);

}

clock_t end = clock();

return double(end - begin) / CLOCKS_PER_SEC;

}

else if (t == 4)

{

clock_t begin = clock();

int x =0;

intPair p(1,2);

for(int i = 0; i < loop; ++i)

{

x += Sum3(p);

}

clock_t end = clock();

return double(end - begin) / CLOCKS_PER_SEC;

}

else if (t == 5)

{

clock_t begin = clock();

int x =0;

for(int i = 0; i < loop; ++i)

{

x += Sum3(10);

}

clock_t end = clock();

return double(end - begin) / CLOCKS_PER_SEC;

}

return 0;

}

我們用了5個案列,對Sum1和Sum3 風別用了兩種調(diào)用方式,對Sum2用了一種調(diào)用方式。我們測試了10萬次調(diào)用:

double sec = Sum(1, 100000);

sec = Sum(2, 100000);

printf("Sum1 (use no c'tor) time: %f /n", sec);

sec = Sum(3, 100000);

printf("Sum2 time: %f /n", sec);

sec = Sum(4, 100000);

printf("Sum3 without conversion time: %f /n", sec);

sec = Sum(5, 100000);

printf("Sum3 with conversion time: %f /n", sec);

我們在VisualStidio 2010 中測試,結(jié)果是:

用例1 18ms

用例2 9ms

用例3 6ms

用例4 7ms

用例5 12ms

也就是說:用例1和5最慢,其他基本沒有差別。

細心的讀者不難看出,

1)用例5的性能問題,是因為Sum3用了C++的implicit conversion ,將整數(shù)自動轉(zhuǎn)化成intPair 的臨時變量。這是一個應(yīng)用層面的問題,如果我們不得不將整數(shù)作這個轉(zhuǎn)換,也就不得不付出這個性能上的代價。

2)用例1的問題和5類似,都是因為不得不每次創(chuàng)建臨時變量。當然,可以強迫constructor inline 來使得臨時變量的生成成本降低。

3)用例2用了在函數(shù)調(diào)用前了編譯自生的copy constructor,不過因為 intPair object 很小,影響可以忽略不計了。

4)用例3性能是穩(wěn)定的,但是它用了“間接”方式(詳情請看我關(guān)于reference的博克),所以產(chǎn)生的指令比用例2多兩條。但對性能的影響不大,估計和Intel的L1,L2 緩存有關(guān)。

*注意到OOP函數(shù)如果僅僅對 this 的成員存取數(shù)據(jù),一般可以充分利用緩存,除非 object 過大。

5)用例4 和用例3生成代碼完全一樣,應(yīng)該沒有差別。const 只是編譯時有用,生成的代碼與const 與否無關(guān)。

性能問題的話題太多,本文只是蜻蜓點水,但是已經(jīng)觸及了C++的兩個最大的性能隱患:

  a) 臨時變量

  b) Implicit conversion (沉默轉(zhuǎn)換)

2014-6-20 西雅圖


發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 瑞金市| 高唐县| 北碚区| 达州市| 三亚市| 泗洪县| 武山县| 台中县| 通城县| 巴里| 东莞市| 辽宁省| 常宁市| 阳泉市| 吴桥县| 拉孜县| 海口市| 夏津县| 富宁县| 仙桃市| 托里县| 延川县| 宁武县| 芦溪县| 南召县| 马尔康县| 荥阳市| 广元市| 迁安市| 买车| 健康| 仁布县| 建平县| 宁南县| 广灵县| 车致| 额尔古纳市| 沧州市| 南昌县| 当阳市| 锦屏县|