C++統(tǒng)計(jì)函數(shù)執(zhí)行時(shí)間的最佳實(shí)踐
前言
在軟件開(kāi)發(fā)過(guò)程中,性能分析是優(yōu)化程序的重要環(huán)節(jié)。特別是在C++這樣的高性能語(yǔ)言中,了解函數(shù)的執(zhí)行時(shí)間分布對(duì)于識(shí)別性能瓶頸至關(guān)重要。今天我們來(lái)介紹一個(gè)輕量級(jí)的C++函數(shù)執(zhí)行時(shí)間統(tǒng)計(jì)工具,它能夠幫助開(kāi)發(fā)者快速定位性能問(wèn)題。
工具特性
這個(gè)函數(shù)計(jì)時(shí)器具有以下核心特性:
功能完備性
- 統(tǒng)計(jì)函數(shù)調(diào)用次數(shù)、總執(zhí)行時(shí)間、平均時(shí)間、最小時(shí)間、最大時(shí)間
- 支持多函數(shù)同時(shí)監(jiān)控
- 提供統(tǒng)計(jì)報(bào)告輸出和數(shù)據(jù)清理功能
易用性
- 使用RAII(Resource Acquisition Is Initialization)機(jī)制自動(dòng)計(jì)時(shí)
- 一行宏定義即可啟用監(jiān)控:
TIMER_SCOPE("函數(shù)名") - 無(wú)侵入性設(shè)計(jì),不影響原有代碼邏輯
線程安全性
- 使用互斥鎖保護(hù)共享數(shù)據(jù)
- 支持多線程環(huán)境下的并發(fā)使用
性能友好
- 基于
std::chrono::steady_clock提供高精度計(jì)時(shí) - 單例模式減少內(nèi)存開(kāi)銷(xiāo)
核心設(shè)計(jì)
1. 數(shù)據(jù)結(jié)構(gòu)設(shè)計(jì)
struct FunctionStats {
std::string functionName;
long totalTimeMs; // 總執(zhí)行時(shí)間
int callCount; // 調(diào)用次數(shù)
long minTimeMs; // 最小執(zhí)行時(shí)間
long maxTimeMs; // 最大執(zhí)行時(shí)間
double avgTimeMs; // 平均執(zhí)行時(shí)間
};
FunctionStats 結(jié)構(gòu)體封裝了單個(gè)函數(shù)的完整統(tǒng)計(jì)信息,通過(guò) addExecution 方法動(dòng)態(tài)更新統(tǒng)計(jì)數(shù)據(jù)。
2. 單例模式管理器
FunctionTimer 類(lèi)采用線程安全的單例模式,確保全局只有一個(gè)統(tǒng)計(jì)管理器實(shí)例:
static FunctionTimer* getInstance() {
std::lock_guard<std::mutex> lock(instanceMutex);
if (instance == nullptr) {
instance = std::unique_ptr<FunctionTimer>(new FunctionTimer());
}
return instance.get();
}
3. RAII自動(dòng)計(jì)時(shí)
ScopedTimer 類(lèi)是整個(gè)工具的核心,利用C++的RAII特性實(shí)現(xiàn)自動(dòng)計(jì)時(shí):
class ScopedTimer {
std::string functionName;
std::chrono::steady_clock::time_point startTime;
public:
explicit ScopedTimer(const std::string& funcName);
~ScopedTimer(); // 析構(gòu)時(shí)自動(dòng)記錄執(zhí)行時(shí)間
};
當(dāng)對(duì)象創(chuàng)建時(shí)記錄開(kāi)始時(shí)間,當(dāng)對(duì)象銷(xiāo)毀(離開(kāi)作用域)時(shí)自動(dòng)計(jì)算并記錄執(zhí)行時(shí)間。
使用方法
基本用法
#include "function_timer.h"
void someFunction() {
TIMER_SCOPE("someFunction"); // 添加這一行即可
// 原有的函數(shù)邏輯
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
int main() {
// 執(zhí)行一些被監(jiān)控的函數(shù)
for(int i = 0; i < 10; i++) {
someFunction();
}
// 打印統(tǒng)計(jì)報(bào)告
FunctionTimer::getInstance()->printStats();
return 0;
}
高級(jí)用法
// 獲取特定函數(shù)的統(tǒng)計(jì)信息
FunctionStats stats = FunctionTimer::getInstance()->getFunctionStats("someFunction");
std::cout << "函數(shù)調(diào)用了 " << stats.callCount << " 次" << std::endl;
// 獲取所有統(tǒng)計(jì)數(shù)據(jù)
auto allStats = FunctionTimer::getInstance()->getAllStats();
for(const auto& pair : allStats) {
std::cout << pair.first << ": " << pair.second.avgTimeMs << "ms" << std::endl;
}
// 清理統(tǒng)計(jì)數(shù)據(jù)
FunctionTimer::getInstance()->clearStats();
輸出示例
========== 函數(shù)執(zhí)行時(shí)間統(tǒng)計(jì)報(bào)告 ==========
函數(shù)名稱 | 調(diào)用次數(shù) | 總時(shí)間(ms) | 平均時(shí)間(ms) | 最小時(shí)間(ms) | 最大時(shí)間(ms)
----------------------------------------------------------------------
someFunction | 10 | 1005 | 100 | 99 | 102
anotherFunction | 5 | 250 | 50 | 48 | 53
==========================================
實(shí)現(xiàn)亮點(diǎn)
1. 線程安全保證
使用std::mutex和std::lock_guard確保多線程環(huán)境下的數(shù)據(jù)一致性:
void recordExecution(const std::string& functionName, long executionTimeMs) {
std::lock_guard<std::mutex> lock(statsMutex);
// 線程安全的數(shù)據(jù)更新
stats[functionName].addExecution(executionTimeMs);
}
2. 異常安全
即使函數(shù)執(zhí)行過(guò)程中拋出異常,ScopedTimer 的析構(gòu)函數(shù)仍會(huì)被調(diào)用,確保計(jì)時(shí)統(tǒng)計(jì)的準(zhǔn)確性。
3. 內(nèi)存管理
使用智能指針std::unique_ptr管理單例實(shí)例,避免內(nèi)存泄漏。
性能考量
這個(gè)工具設(shè)計(jì)時(shí)充分考慮了性能影響:
- 時(shí)間復(fù)雜度:記錄操作為O(1),查詢操作為O(1)
- 空間復(fù)雜度:每個(gè)監(jiān)控函數(shù)只需少量?jī)?nèi)存存儲(chǔ)統(tǒng)計(jì)信息
- 運(yùn)行時(shí)開(kāi)銷(xiāo):主要開(kāi)銷(xiāo)來(lái)自時(shí)間獲取和互斥鎖操作,影響極小
擴(kuò)展建議
添加采樣功能:對(duì)于高頻調(diào)用的函數(shù),可以添加采樣機(jī)制減少性能影響
支持更多統(tǒng)計(jì)指標(biāo):如95百分位數(shù)、標(biāo)準(zhǔn)差等
可視化輸出:生成圖表或JSON格式的統(tǒng)計(jì)報(bào)告
持久化存儲(chǔ):將統(tǒng)計(jì)數(shù)據(jù)保存到文件中供后續(xù)分析
適用場(chǎng)景
這個(gè)工具特別適用于以下場(chǎng)景:
- 性能調(diào)優(yōu)階段:識(shí)別熱點(diǎn)函數(shù)和性能瓶頸
- 算法比較:對(duì)比不同算法實(shí)現(xiàn)的性能差異
- 回歸測(cè)試:監(jiān)控性能回歸問(wèn)題
- 生產(chǎn)環(huán)境監(jiān)控:輕量級(jí)的性能監(jiān)控(建議添加開(kāi)關(guān)控制)
總結(jié)
這個(gè)C++函數(shù)執(zhí)行時(shí)間統(tǒng)計(jì)工具雖然簡(jiǎn)潔,但功能完備、使用方便。它體現(xiàn)了優(yōu)秀工具設(shè)計(jì)的幾個(gè)原則:
- 簡(jiǎn)單易用:一行代碼即可啟用監(jiān)控
- 功能完整:提供全面的統(tǒng)計(jì)信息
- 性能友好:最小化對(duì)原程序的影響
- 線程安全:支持多線程環(huán)境
對(duì)于需要進(jìn)行性能分析的C++項(xiàng)目,這是一個(gè)非常實(shí)用的工具。通過(guò)合理使用,開(kāi)發(fā)者可以快速定位性能問(wèn)題,提升程序效率。
完整代碼
function_timer.h
#pragma once
#include <chrono>
#include <string>
#include <unordered_map>
#include <memory>
#include <mutex>
#include <climits>
struct FunctionStats {
std::string functionName;
long totalTimeMs;
int callCount;
long minTimeMs;
long maxTimeMs;
double avgTimeMs;
FunctionStats() : totalTimeMs(0), callCount(0), minTimeMs(LONG_MAX), maxTimeMs(0), avgTimeMs(0.0) {}
void addExecution(long executionTimeMs) {
totalTimeMs += executionTimeMs;
callCount++;
if (executionTimeMs < minTimeMs) minTimeMs = executionTimeMs;
if (executionTimeMs > maxTimeMs) maxTimeMs = executionTimeMs;
avgTimeMs = static_cast<double>(totalTimeMs) / callCount;
}
};
class FunctionTimer {
private:
static std::unique_ptr<FunctionTimer> instance;
static std::mutex instanceMutex;
std::unordered_map<std::string, FunctionStats> stats;
mutable std::mutex statsMutex;
FunctionTimer() = default;
public:
static FunctionTimer* getInstance();
void recordExecution(const std::string& functionName, long executionTimeMs);
void printStats() const;
void clearStats();
FunctionStats getFunctionStats(const std::string& functionName) const;
std::unordered_map<std::string, FunctionStats> getAllStats() const;
};
class ScopedTimer {
private:
std::string functionName;
std::chrono::steady_clock::time_point startTime;
public:
explicit ScopedTimer(const std::string& funcName);
~ScopedTimer();
};
#define TIMER_SCOPE(funcName) ScopedTimer timer(funcName)
function_timer.cpp
#include "../include/function_timer.h"
#include <iostream>
#include <iomanip>
#include <climits>
#include "../../common/logging/log_helper.h"
std::unique_ptr<FunctionTimer> FunctionTimer::instance = nullptr;
std::mutex FunctionTimer::instanceMutex;
FunctionTimer* FunctionTimer::getInstance() {
std::lock_guard<std::mutex> lock(instanceMutex);
if (instance == nullptr) {
instance = std::unique_ptr<FunctionTimer>(new FunctionTimer());
}
return instance.get();
}
void FunctionTimer::recordExecution(const std::string& functionName, long executionTimeMs) {
std::lock_guard<std::mutex> lock(statsMutex);
if (stats.find(functionName) == stats.end()) {
stats[functionName].functionName = functionName;
}
stats[functionName].addExecution(executionTimeMs);
}
void FunctionTimer::printStats() const {
std::lock_guard<std::mutex> lock(statsMutex);
LogHelper::logInfo("========== 函數(shù)執(zhí)行時(shí)間統(tǒng)計(jì)報(bào)告 ==========");
LogHelper::logInfo("函數(shù)名稱 | 調(diào)用次數(shù) | 總時(shí)間(ms) | 平均時(shí)間(ms) | 最小時(shí)間(ms) | 最大時(shí)間(ms)");
LogHelper::logInfo("----------------------------------------------------------------------");
for (const auto& pair : stats) {
const FunctionStats& stat = pair.second;
std::string logMsg = stat.functionName + " | " +
std::to_string(stat.callCount) + " | " +
std::to_string(stat.totalTimeMs) + " | " +
std::to_string(static_cast<long>(stat.avgTimeMs)) + " | " +
std::to_string(stat.minTimeMs == LONG_MAX ? 0 : stat.minTimeMs) + " | " +
std::to_string(stat.maxTimeMs);
LogHelper::logInfo(logMsg);
}
LogHelper::logInfo("==========================================");
}
void FunctionTimer::clearStats() {
std::lock_guard<std::mutex> lock(statsMutex);
stats.clear();
}
FunctionStats FunctionTimer::getFunctionStats(const std::string& functionName) const {
std::lock_guard<std::mutex> lock(statsMutex);
auto it = stats.find(functionName);
if (it != stats.end()) {
return it->second;
}
return FunctionStats();
}
std::unordered_map<std::string, FunctionStats> FunctionTimer::getAllStats() const {
std::lock_guard<std::mutex> lock(statsMutex);
return stats;
}
ScopedTimer::ScopedTimer(const std::string& funcName)
: functionName(funcName), startTime(std::chrono::steady_clock::now()) {
}
ScopedTimer::~ScopedTimer() {
auto endTime = std::chrono::steady_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(endTime - startTime);
long executionTimeMs = duration.count();
FunctionTimer::getInstance()->recordExecution(functionName, executionTimeMs);
}
以上就是C++統(tǒng)計(jì)函數(shù)執(zhí)行時(shí)間的最佳實(shí)踐的詳細(xì)內(nèi)容,更多關(guān)于C++統(tǒng)計(jì)函數(shù)執(zhí)行時(shí)間的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C++實(shí)現(xiàn)數(shù)組中元素組合出最大值
這篇文章主要介紹了C++實(shí)現(xiàn)數(shù)組中元素組合出最大值,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-05-05
C++11可變參數(shù)模板的具體實(shí)現(xiàn)
C++11引入的可變參數(shù)模板是一項(xiàng)非常強(qiáng)大的特性,它極大地提升了模板的擴(kuò)展性,可變參數(shù)模板允許我們定義可以接受任意數(shù)量和類(lèi)型參數(shù)的模板,這在處理不定數(shù)量參數(shù)的場(chǎng)景中非常有用,感興趣的可以了解一下2025-06-06
C++17中的std::from_chars函數(shù)使用及說(shuō)明
這篇文章主要介紹了C++17中的std::from_chars函數(shù)使用及說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2025-10-10
c++中std::hash以及萬(wàn)能hash的使用方式
這篇文章主要介紹了c++中std::hash以及萬(wàn)能hash的使用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-08-08
Qt實(shí)現(xiàn)繪制網(wǎng)格背景的示例代碼
這篇文章主要介紹了Qt如何實(shí)現(xiàn)繪制網(wǎng)格背景,并且能實(shí)現(xiàn)窗口大小調(diào)整時(shí)網(wǎng)格背景也自動(dòng)調(diào)整重繪,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2022-06-06
QT實(shí)現(xiàn)制作一個(gè)ListView列表的示例代碼
這篇文章主要為大家詳細(xì)介紹了如何使用Qt制作一個(gè)ListView,點(diǎn)擊ListView的Item可以用于測(cè)試OpenCV的各種效果,感興趣的小伙伴可以了解一下2023-02-02
C語(yǔ)言實(shí)現(xiàn)猜數(shù)字小游戲的示例代碼
猜數(shù)字小游戲是我們小時(shí)候喜歡我們一個(gè)經(jīng)典小游戲。這篇文章將利用C語(yǔ)言中的循環(huán)語(yǔ)句、分支語(yǔ)句和函數(shù)實(shí)現(xiàn)這一游戲,需要的可以參考一下2022-10-10

