C 语言

关注公众号 jb51net

关闭
首页 > 软件编程 > C 语言 > C++统计函数执行时间

C++统计函数执行时间的最佳实践

作者:天天进步2015

在软件开发过程中,性能分析是优化程序的重要环节,了解函数的执行时间分布对于识别性能瓶颈至关重要,本文将分享一个C++函数执行时间统计工具,希望对大家有所帮助

前言

在软件开发过程中,性能分析是优化程序的重要环节。特别是在C++这样的高性能语言中,了解函数的执行时间分布对于识别性能瓶颈至关重要。今天我们来介绍一个轻量级的C++函数执行时间统计工具,它能够帮助开发者快速定位性能问题。

工具特性

这个函数计时器具有以下核心特性:

功能完备性

易用性

线程安全性

性能友好

核心设计

1. 数据结构设计

struct FunctionStats {
    std::string functionName;
    long totalTimeMs;      // 总执行时间
    int callCount;         // 调用次数
    long minTimeMs;        // 最小执行时间
    long maxTimeMs;        // 最大执行时间
    double avgTimeMs;      // 平均执行时间
};

FunctionStats 结构体封装了单个函数的完整统计信息,通过 addExecution 方法动态更新统计数据。

2. 单例模式管理器

FunctionTimer 类采用线程安全的单例模式,确保全局只有一个统计管理器实例:

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自动计时

ScopedTimer 类是整个工具的核心,利用C++的RAII特性实现自动计时:

class ScopedTimer {
    std::string functionName;
    std::chrono::steady_clock::time_point startTime;
public:
    explicit ScopedTimer(const std::string& funcName);
    ~ScopedTimer();  // 析构时自动记录执行时间
};

当对象创建时记录开始时间,当对象销毁(离开作用域)时自动计算并记录执行时间。

使用方法

基本用法

#include "function_timer.h"

void someFunction() {
    TIMER_SCOPE("someFunction");  // 添加这一行即可
    
    // 原有的函数逻辑
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
}

int main() {
    // 执行一些被监控的函数
    for(int i = 0; i < 10; i++) {
        someFunction();
    }
    
    // 打印统计报告
    FunctionTimer::getInstance()->printStats();
    
    return 0;
}

高级用法

// 获取特定函数的统计信息
FunctionStats stats = FunctionTimer::getInstance()->getFunctionStats("someFunction");
std::cout << "函数调用了 " << stats.callCount << " 次" << std::endl;

// 获取所有统计数据
auto allStats = FunctionTimer::getInstance()->getAllStats();
for(const auto& pair : allStats) {
    std::cout << pair.first << ": " << pair.second.avgTimeMs << "ms" << std::endl;
}

// 清理统计数据
FunctionTimer::getInstance()->clearStats();

输出示例

========== 函数执行时间统计报告 ==========
函数名称 | 调用次数 | 总时间(ms) | 平均时间(ms) | 最小时间(ms) | 最大时间(ms)
----------------------------------------------------------------------
someFunction | 10 | 1005 | 100 | 99 | 102
anotherFunction | 5 | 250 | 50 | 48 | 53
==========================================

实现亮点

1. 线程安全保证

使用std::mutexstd::lock_guard确保多线程环境下的数据一致性:

void recordExecution(const std::string& functionName, long executionTimeMs) {
    std::lock_guard<std::mutex> lock(statsMutex);
    // 线程安全的数据更新
    stats[functionName].addExecution(executionTimeMs);
}

2. 异常安全

即使函数执行过程中抛出异常,ScopedTimer 的析构函数仍会被调用,确保计时统计的准确性。

3. 内存管理

使用智能指针std::unique_ptr管理单例实例,避免内存泄漏。

性能考量

这个工具设计时充分考虑了性能影响:

扩展建议

添加采样功能:对于高频调用的函数,可以添加采样机制减少性能影响

支持更多统计指标:如95百分位数、标准差等

可视化输出:生成图表或JSON格式的统计报告

持久化存储:将统计数据保存到文件中供后续分析

适用场景

这个工具特别适用于以下场景:

总结

这个C++函数执行时间统计工具虽然简洁,但功能完备、使用方便。它体现了优秀工具设计的几个原则:

对于需要进行性能分析的C++项目,这是一个非常实用的工具。通过合理使用,开发者可以快速定位性能问题,提升程序效率。

完整代码

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("========== 函数执行时间统计报告 ==========");
    LogHelper::logInfo("函数名称 | 调用次数 | 总时间(ms) | 平均时间(ms) | 最小时间(ms) | 最大时间(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++统计函数执行时间的最佳实践的详细内容,更多关于C++统计函数执行时间的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文