日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

提高C++性能的编程技术笔记:跟踪实例+测试代码

發布時間:2023/11/27 45 豆豆
生活随笔 收集整理的這篇文章主要介紹了 提高C++性能的编程技术笔记:跟踪实例+测试代码 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

當提高性能時,我們必須記住以下幾點:

(1). 內存不是無限大的。虛擬內存系統使得內存看起來是無限的,而事實上并非如此。

(2). 內存訪問開銷不是均衡的。對緩存、主內存和磁盤的訪問開銷不在同一個數量級之上。

(3). 我們的程序沒有專用的CPU,只能間歇地獲得一個時間片。

(4). 在一臺單處理器的計算機上,并行的線程并不是真正地并行執行,它們是輪詢的。

“性能”可以有幾種衡量標準,最常見的兩種是空間效率和時間效率。空間效率標準尋求占用最小內存的軟件解決方案。相似的,時間效率標準尋求占用最少處理器周期的解決方案。時間效率通常以響應時間和吞吐量來作為衡量標準。其它衡量標準還有編譯時間和可執行文件的大小。

許多C++程序員在跟蹤代碼時通常的做法是,定義一個簡單的Trace類將診斷信息打印到日志文件中。程序員可以在每個想要跟蹤的函數中定義一個Trace對象,在函數的入口和出口Trace類可以分別寫一條信息。盡管Trace對象將增加程序額外的執行開銷,但是它能夠幫助程序員找出問題而無須使用調試器。

最理想的跟蹤性能優化的方法應該能夠完全消除性能開銷,即把跟蹤調用嵌入在#ifdef塊內。使用這種方法的不足在于必須重新編譯程序來打開或關閉跟蹤。還有一種選擇:可以通過與正在運行的程序通信來動態地控制跟蹤。Trace類能夠在記錄任何跟蹤信息之前先檢查跟蹤狀態。

影響C++性能的因素:I/O的開銷是高昂的;函數調用的開銷是要考慮的一個因素,因此我們應該將短小的、頻繁調用的函數內聯;復制對象的開銷是高昂的,最好選擇傳遞引用,而不是傳遞值。

內聯對大塊頭函數的影響是無足輕重的。只有在針對那些調用和返回開銷占全部開銷的絕大部分的小型函數時,內聯對性能的改善才有較大的影響。內聯消除了常被使用的小函數調用所產生的函數開銷。完美適合內聯的函數就恰好是非常不適合跟蹤的。

對象定義會觸發隱形地執行構造函數和析構函數。我們稱其為”隱性執行”而不是”隱性開銷”是因為對象的構造和銷毀并不總是意味產生開銷。

通過引用傳遞對象還是不能保證良好的性能,所以避免對象的復制的確有利于提高性能,但是如果我們不必一開始就創建和銷毀該對象的話,這種處理方式將更有利于性能的提升。

在完成同樣的簡單工作時,char指針有時可以比string對象更有效率。

以下是測試代碼(the_tracing_war_story.cpp),分別有Trace1,Trace2,Trace3三個簡單的類,它們的性能逐漸提高:

#include "the_tracing_war_story.hpp"
#include <string>
#include <iostream>
#include <chrono>namespace tracing_war_story_ {
//
// 較差的Trace1類設計
class Trace1 {
public:Trace1(const std::string& name);~Trace1();void debug(const std::string& msg);static bool traceIsActive;
private:std::string theFunctionName;
};inline Trace1::Trace1(const std::string& name) : theFunctionName(name)
{if (traceIsActive) {std::cout << "Enter function: " << name << std::endl;}
}inline Trace1::~Trace1()
{if (traceIsActive) {std::cout <<"Exit function: " << theFunctionName << std::endl;}
}inline void Trace1::debug(const std::string& msg)
{if (traceIsActive) {std::cout << msg << std::endl;}
}bool Trace1::traceIsActive = false; // 默認設置為false關閉跟蹤;可以在test_tracing_war_story中設置是否開啟還是關閉跟蹤int addOne0(int x)
{return x+1;
}int addOne1(int x)
{std::string name = "addOne1";Trace1 t(name);return x+1;
}///
// Trace2類是對Trace1類的改進:將函數參數string類型調整為const char*
class Trace2 {
public:Trace2(const char* name);~Trace2();void debug(const char* msg);static bool traceIsActive;
private:std::string theFunctionName;
};inline Trace2::Trace2(const char* name) : theFunctionName(name)
{if (traceIsActive) {std::cout << "Enter function: " << name << std::endl;}
}inline Trace2::~Trace2()
{if (traceIsActive) {std::cout <<"Exit function: " << theFunctionName << std::endl;}
}inline void Trace2::debug(const char* msg)
{if (traceIsActive) {std::cout << msg << std::endl;}
}bool Trace2::traceIsActive = false; // 默認設置為false關閉跟蹤;可以在test_tracing_war_story中設置是否開啟還是關閉跟蹤int addOne2(int x)
{char* name = "addOne2";Trace2 t(name);return x+1;
}/
// Trace3類是對Trace2類的改進:消除包含在Trace2類內的string成員對象的無條件的創建
class Trace3 {
public:Trace3(const char* name);~Trace3();void debug(const char* msg);static bool traceIsActive;
private:// string指針可以把string對象的創建推遲到確定跟蹤處于打開狀態以后std::string* theFunctionName;
};inline Trace3::Trace3(const char* name) : theFunctionName(nullptr)
{if (traceIsActive) {std::cout << "Enter function: " << name << std::endl;theFunctionName = new std::string(name);}
}inline Trace3::~Trace3()
{if (traceIsActive) {std::cout <<"Exit function: " << theFunctionName << std::endl;delete theFunctionName;}
}inline void Trace3::debug(const char* msg)
{if (traceIsActive) {std::cout << msg << std::endl;}
}bool Trace3::traceIsActive = false; // 默認設置為false關閉跟蹤;可以在test_tracing_war_story中設置是否開啟還是關閉跟蹤int addOne3(int x)
{char* name = "addOne3";Trace3 t(name);return x+1;
}int test_tracing_war_story()
{Trace1::traceIsActive = false;/*Trace1實現就是一個無用對象對性能帶來破壞性影響的實例:即創建和后面的銷毀預計要使用卻沒有使用的不必要的對象在關閉跟蹤情況下產生的開銷:引發一系列計算:(1). 創建一個作用域為test_tracing_war_story的string型變量name(2). 調用Trace1的構造函數(3). Trace1的構造函數調用string的構造函數來創建一個string在此函數的結尾,Trace1對象和兩個string對象被銷毀:(1). 銷毀string型變量name(2). 調用Trace1的析構函數(3). Trace1的析構函數為成員string調用string的析構函數在跟蹤被關閉的情況下,string的成員對象從未被使用,Trace1對象本身也未被使用,所有這些用于對象的創建和銷毀的計算都是純碎的浪費*/std::string name = "test_tracing_war_story";Trace1 t(name);std::string moreInfo = "more interesting info";t.debug(moreInfo);using namespace std::chrono;high_resolution_clock::time_point timeStart, timeEnd;int count = 1000000;// 通過addOne0和addOne1測試Trace1對象的性能開銷timeStart = high_resolution_clock::now();for (int i = 0; i < count; ++i) {addOne0(i);}timeEnd = high_resolution_clock::now();std::cout<< "addOne0 time spen: " <<(duration_cast<duration<double>>(timeEnd-timeStart)).count()<<" seconds"<<std::endl;timeStart = high_resolution_clock::now();for (int i = 0; i < count; ++i) {addOne1(i);}timeEnd = high_resolution_clock::now();std::cout<< "addOne1 time spen: " <<(duration_cast<duration<double>>(timeEnd-timeStart)).count()<<" seconds"<<std::endl;Trace2::traceIsActive = false;// 通過addOne2測試Trace2對象的性能開銷timeStart = high_resolution_clock::now();for (int i = 0; i < count; ++i) {addOne2(i);}timeEnd = high_resolution_clock::now();std::cout<< "addOne2 time spen: " <<(duration_cast<duration<double>>(timeEnd-timeStart)).count()<<" seconds"<<std::endl;Trace3::traceIsActive = false;// 通過addOne3測試Trace3對象的性能開銷timeStart = high_resolution_clock::now();for (int i = 0; i < count; ++i) {addOne3(i);}timeEnd = high_resolution_clock::now();std::cout<< "addOne3 time spen: " <<(duration_cast<duration<double>>(timeEnd-timeStart)).count()<<" seconds"<<std::endl;return 0;
}} // namespace tracing_war_story

執行結果如下:

GitHub:https://github.com/fengbingchun/Messy_Test

總結

以上是生活随笔為你收集整理的提高C++性能的编程技术笔记:跟踪实例+测试代码的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。