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

相关文章

C++中unordered_set哈希集合的实现

《C++中unordered_set哈希集合的实现》std::unordered_set是C++标准库中的无序关联容器,基于哈希表实现,具有元素唯一性和无序性特点,本文就来详细的介绍一下unorder... 目录一、概述二、头文件与命名空间三、常用方法与示例1. 构造与析构2. 迭代器与遍历3. 容量相关4

C++中悬垂引用(Dangling Reference) 的实现

《C++中悬垂引用(DanglingReference)的实现》C++中的悬垂引用指引用绑定的对象被销毁后引用仍存在的情况,会导致访问无效内存,下面就来详细的介绍一下产生的原因以及如何避免,感兴趣... 目录悬垂引用的产生原因1. 引用绑定到局部变量,变量超出作用域后销毁2. 引用绑定到动态分配的对象,对象

Linux kill正在执行的后台任务 kill进程组使用详解

《Linuxkill正在执行的后台任务kill进程组使用详解》文章介绍了两个脚本的功能和区别,以及执行这些脚本时遇到的进程管理问题,通过查看进程树、使用`kill`命令和`lsof`命令,分析了子... 目录零. 用到的命令一. 待执行的脚本二. 执行含子进程的脚本,并kill2.1 进程查看2.2 遇到的

JDK21对虚拟线程的几种用法实践指南

《JDK21对虚拟线程的几种用法实践指南》虚拟线程是Java中的一种轻量级线程,由JVM管理,特别适合于I/O密集型任务,:本文主要介绍JDK21对虚拟线程的几种用法,文中通过代码介绍的非常详细,... 目录一、参考官方文档二、什么是虚拟线程三、几种用法1、Thread.ofVirtual().start(

从基础到高级详解Go语言中错误处理的实践指南

《从基础到高级详解Go语言中错误处理的实践指南》Go语言采用了一种独特而明确的错误处理哲学,与其他主流编程语言形成鲜明对比,本文将为大家详细介绍Go语言中错误处理详细方法,希望对大家有所帮助... 目录1 Go 错误处理哲学与核心机制1.1 错误接口设计1.2 错误与异常的区别2 错误创建与检查2.1 基础

Python函数作用域与闭包举例深度解析

《Python函数作用域与闭包举例深度解析》Python函数的作用域规则和闭包是编程中的关键概念,它们决定了变量的访问和生命周期,:本文主要介绍Python函数作用域与闭包的相关资料,文中通过代码... 目录1. 基础作用域访问示例1:访问全局变量示例2:访问外层函数变量2. 闭包基础示例3:简单闭包示例4

springboot依靠security实现digest认证的实践

《springboot依靠security实现digest认证的实践》HTTP摘要认证通过加密参数(如nonce、response)验证身份,避免明文传输,但存在密码存储风险,相比基本认证更安全,却因... 目录概述参数Demopom.XML依赖Digest1Application.JavaMyPasswo

java中ssh2执行多条命令的四种方法

《java中ssh2执行多条命令的四种方法》本文主要介绍了java中ssh2执行多条命令的四种方法,包括分号分隔、管道分隔、EOF块、脚本调用,可确保环境配置生效,提升操作效率,具有一定的参考价值,感... 目录1 使用分号隔开2 使用管道符号隔开3 使用写EOF的方式4 使用脚本的方式大家平时有没有遇到自

mybatis直接执行完整sql及踩坑解决

《mybatis直接执行完整sql及踩坑解决》MyBatis可通过select标签执行动态SQL,DQL用ListLinkedHashMap接收结果,DML用int处理,注意防御SQL注入,优先使用#... 目录myBATiFBNZQs直接执行完整sql及踩坑select语句采用count、insert、u

Python中isinstance()函数原理解释及详细用法示例

《Python中isinstance()函数原理解释及详细用法示例》isinstance()是Python内置的一个非常有用的函数,用于检查一个对象是否属于指定的类型或类型元组中的某一个类型,它是Py... 目录python中isinstance()函数原理解释及详细用法指南一、isinstance()函数