程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> PHP編程 >> 關於PHP編程 >> C++ 性能剖析 (一),性能剖析

C++ 性能剖析 (一),性能剖析

編輯:關於PHP編程

C++ 性能剖析 (一),性能剖析


C++ 性能剖析 (一)

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

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

1)用於測試的C++ 編譯器沒有使用最新的優化技術

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

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

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

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

 

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函數,作的事情完全一樣,但是性能是否一樣呢?我們用下面的程序來測試:

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 風別用了兩種調用方式,對Sum2用了一種調用方式。我們測試了10萬次調用:

double sec = Sum(1, 100000);

printf("Sum1 (use  ctor) time: %f \n", sec);

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 中測試,結果是:

 

用例1    18ms 

用例2    9ms

用例3    6ms

用例4    7ms

用例5    12ms

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

細心的讀者不難看出,

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

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

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

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

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

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

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

  a) 臨時變量

  b) Implicit conversion (沉默轉換)

 

2014-6-20 西雅圖


內部排序算法的性可以分析

沒時間幫你寫程序需說個思路就閃人了 你先把3種排序的書上的例子抄下來 寫成3個函數, 每個函數裡面開頭和結尾取一次系統時間 最後相減得出開銷時間 在打印出來
 

用c語言完成:1哈夫曼編碼/譯碼器2內部排序算法的性可以分析

我把網上的程序修改了一下,並整合了,你看看
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define M 50
#define MAX 100000;

typedef struct
{
int weight;//結點權值
int parent,lchild,rchild;
}HTNODE,*HUFFMANTREE;

typedef char** HUFFMANCODE;//動態分配數組存儲哈夫曼編碼表

typedef struct
{
int key; /*關鍵字*/
}RecordNode; /*排序節點的類型*/

typedef struct
{
RecordNode *record;
int n; /*排序對象的大小*/
}SortObject; //待排序序列

HUFFMANTREE huffmantree(int n,int weight[])//構建哈夫曼樹
{
int m1,m2,k;
int i,j,x1,x2;
HUFFMANTREE ht;
ht=(HUFFMANTREE)malloc((2*n)*sizeof(HTNODE));
for(i=1;i<(2*n);i++)//初始化哈夫曼樹中各結點的數據,沒初始值的賦值為0
{
ht[i].parent=ht[i].lchild=ht[i].rchild=0;
if(i<=n)
ht[i].weight=weight[i];
else
ht[i].weight=0;
}
for(i=1;i<n;i++)//每一重循環從森林中選擇最小的兩棵樹組建成一顆新樹
{
m1=m2=MAX;
x1=x2=0;
for(j=1;j<(n+i);j++)
{
if((ht[j].weight<m1)&&(ht[j].parent==0))
{
m2=m1;
x2=x1;
m1=ht[j].weight;
x1=j;
}
else if((ht[j].weight<m2)&&(ht[j].parent==0))
{
m2=ht[j].weight;
x2=j;
}
}
k=n+i;
ht[x1].parent=ht[x2].parent=k;
ht[k].weight=m1+m2;
ht[k].lchild=x1;
ht[k].rchild=x2;
}
return ht;
}

void huffmancoding(int n,HUFFMANCODE hc,HUFFMANTREE ht,char str[])
{
int i,start,child,father;
char *cd;
hc=(HUFFMANCODE)malloc((n+1)*sizeof(char*));//分配n個字符編碼的頭指針
cd=(char*)malloc(n*sizeof(char));//分配求編碼的工作空間
cd[n-1]='\0';//編碼結束符
f......余下全文>>
 

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