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

2025-09-02 14:50

本文主要是介绍C++统计函数执行时间的最佳实践,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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

前言

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

工具特性

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

功能完备性

  • 统计函数调用次数、总执行时间、平均时间、最小时间、最大时间
  • 支持多函数同时监控
  • 提供统计报告输出和数据清理功能

易用性

  • 使用RAII(Resource Acquisition Is Initialization)机制自动计时
  • 一行宏定义即可启用监控:TIMER_SCOPE("函数名")
  • 无侵入性设计,不影响原有代码逻辑

线程安全性

  • 使用互斥锁保护共享数据
  • 支持多线程环境下的并发使用

性能友好

  • 基于std::chrono::steady_clock提供高精度计时
  • 单例模式减少内存开销

核心设计

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 << "函数调用了 php" << 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管理单例实例,避免内存泄漏。

性能考量

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

  • 时间复杂度:记录操作为O(1),查询操作为O(1)
  • 空间复杂度:每个监控函数只需少量内存存储统计信息
  • 运行时开销:主要开销来自时间获取和互斥锁操作,影响极小

扩展建议

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

支持更多统计指标:如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::unordereChina编程d_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:www.chinasem.cn: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) + " | " +
                        js    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::phpchrono::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++统计函数执行时间的资料请关注编程China编程(www.chinasem.cn)其它相关文章!

这篇关于C++统计函数执行时间的最佳实践的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1155894

相关文章

PHP应用中处理限流和API节流的最佳实践

《PHP应用中处理限流和API节流的最佳实践》限流和API节流对于确保Web应用程序的可靠性、安全性和可扩展性至关重要,本文将详细介绍PHP应用中处理限流和API节流的最佳实践,下面就来和小编一起学习... 目录限流的重要性在 php 中实施限流的最佳实践使用集中式存储进行状态管理(如 Redis)采用滑动

Java实现远程执行Shell指令

《Java实现远程执行Shell指令》文章介绍使用JSch在SpringBoot项目中实现远程Shell操作,涵盖环境配置、依赖引入及工具类编写,详解分号和双与号执行多指令的区别... 目录软硬件环境说明编写执行Shell指令的工具类总结jsch(Java Secure Channel)是SSH2的一个纯J

ShardingProxy读写分离之原理、配置与实践过程

《ShardingProxy读写分离之原理、配置与实践过程》ShardingProxy是ApacheShardingSphere的数据库中间件,通过三层架构实现读写分离,解决高并发场景下数据库性能瓶... 目录一、ShardingProxy技术定位与读写分离核心价值1.1 技术定位1.2 读写分离核心价值二

深入浅出Spring中的@Autowired自动注入的工作原理及实践应用

《深入浅出Spring中的@Autowired自动注入的工作原理及实践应用》在Spring框架的学习旅程中,@Autowired无疑是一个高频出现却又让初学者头疼的注解,它看似简单,却蕴含着Sprin... 目录深入浅出Spring中的@Autowired:自动注入的奥秘什么是依赖注入?@Autowired

MySQL分库分表的实践示例

《MySQL分库分表的实践示例》MySQL分库分表适用于数据量大或并发压力高的场景,核心技术包括水平/垂直分片和分库,需应对分布式事务、跨库查询等挑战,通过中间件和解决方案实现,最佳实践为合理策略、备... 目录一、分库分表的触发条件1.1 数据量阈值1.2 并发压力二、分库分表的核心技术模块2.1 水平分

C# LiteDB处理时间序列数据的高性能解决方案

《C#LiteDB处理时间序列数据的高性能解决方案》LiteDB作为.NET生态下的轻量级嵌入式NoSQL数据库,一直是时间序列处理的优选方案,本文将为大家大家简单介绍一下LiteDB处理时间序列数... 目录为什么选择LiteDB处理时间序列数据第一章:LiteDB时间序列数据模型设计1.1 核心设计原则

GO语言中函数命名返回值的使用

《GO语言中函数命名返回值的使用》在Go语言中,函数可以为其返回值指定名称,这被称为命名返回值或命名返回参数,这种特性可以使代码更清晰,特别是在返回多个值时,感兴趣的可以了解一下... 目录基本语法函数命名返回特点代码示例命名特点基本语法func functionName(parameters) (nam

深入解析C++ 中std::map内存管理

《深入解析C++中std::map内存管理》文章详解C++std::map内存管理,指出clear()仅删除元素可能不释放底层内存,建议用swap()与空map交换以彻底释放,针对指针类型需手动de... 目录1️、基本清空std::map2️、使用 swap 彻底释放内存3️、map 中存储指针类型的对象

Python Counter 函数使用案例

《PythonCounter函数使用案例》Counter是collections模块中的一个类,专门用于对可迭代对象中的元素进行计数,接下来通过本文给大家介绍PythonCounter函数使用案例... 目录一、Counter函数概述二、基本使用案例(一)列表元素计数(二)字符串字符计数(三)元组计数三、C

python 线程池顺序执行的方法实现

《python线程池顺序执行的方法实现》在Python中,线程池默认是并发执行任务的,但若需要实现任务的顺序执行,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋... 目录方案一:强制单线程(伪顺序执行)方案二:按提交顺序获取结果方案三:任务间依赖控制方案四:队列顺序消