C++统计代码执行耗时

C++统计代码执行耗时

文章目录

  • C++统计代码执行耗时
    • 1. 需求
    • 2. 代码结构
    • 3. CMakeLists文件
    • 4. 核心代码
    • 5. 使用测试

1. 需求

统计项目中代码执行耗时

2. 代码结构

# 程序依赖fmt库
.
├── CMakeLists.txt
├── SpendTimer.cpp
├── SpendTimer.h
├── test.cc
└── third_party
    └── fmt
        ├── include
        │   └── fmt
        │       ├── chrono.h
        │       ├── color.h
        │       ├── compile.h
        │       ├── core.h
        │       ├── format.h
        │       ├── format-inl.h
        │       ├── locale.h
        │       ├── os.h
        │       ├── ostream.h
        │       ├── posix.h
        │       ├── printf.h
        │       └── ranges.h
        └── lib
            ├── libfmt.a
            ├── libfmt.so -> libfmt.so.7
            ├── libfmt.so.7 -> libfmt.so.7.0.3
            └── libfmt.so.7.0.3

3. CMakeLists文件

# cmake版本设置  
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)  
# 声明项目名称与语言
project(demo LANGUAGES C CXX)  

# CMAKE_BUILD_TYPE配置构建类型,默认为空,可以选择Debug 或者 Release
if (NOT CMAKE_BUILD_TYPE)
    set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE)
endif()

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(POSITION_INDEPENDENT_CODE 1)

set(THIRD_PATH "./third_party")
# 添加第三方库的头文件搜索路径
include_directories(${THIRD_PATH}/fmt/include)
# 添加第三方库的搜索路径
link_directories(${THIRD_PATH}/fmt/lib)

add_executable(test_main test.cc SpendTimer.cpp SpendTimer.h)
target_link_libraries(test_main
    PUBLIC
    fmt
)

4. 核心代码

/**
 * 程序执行耗时统计计时器,辅助计算代码执行时间
 * @note 不建议直接使用,应使用相关工具宏
 * @see SPEND_TIME, SPEND_TIME_MSG, SPEND_TIMG_CONTROL
 */
class SpendTimer {
public:
    /** 构造函数,记录当前系统时间 */
    explicit SpendTimer() : m_msg(""), m_start_time(std::chrono::steady_clock::now()) {}

    /**
     * 构造函数,记录当前系统时间
     * @param msg 辅导输出信息
     */
    explicit SpendTimer(const std::string& msg)
    : m_msg(msg), m_start_time(std::chrono::steady_clock::now()) {}

    /** 析构函数,计算从构造至析构所消耗的时间,并打印输出 */
    virtual ~SpendTimer() {
        if (m_closed) {
            return;
        }
        std::chrono::duration<double> sec = std::chrono::steady_clock::now() - m_start_time;
        double spend = 0;
        std::string unit;
        if (sec.count() < 0.000001) {
            spend = sec.count() * 1000000000;
            unit = "ns";
        } else if (sec.count() < 0.001) {
            spend = sec.count() * 1000000;
            unit = "us";
        } else if (sec.count() < 1) {
            spend = sec.count() * 1000;
            unit = "ms";
        } else if (sec.count() > 60) {
            spend = sec.count() / 60;
            unit = " m";
        } else if (sec.count() > 86400) {
            spend = sec.count() / 360;
            unit = " h";
        } else {
            spend = sec.count();
            unit = " s";
        }

        std::cout << fmt::format("spend time: {:>7.3f} {} | {} ", spend, unit, m_msg) << std::endl;
    }

private:
    std::string m_msg;
    std::chrono::time_point<std::chrono::steady_clock> m_start_time;

    static bool m_closed;
    friend void close_spend_time();
    friend void open_spend_time();
};

/// 全局关闭耗时打印输出 
void close_spend_time();

/// 全局开启耗时打印输出
void open_spend_time();

inline void close_spend_time() {
    SpendTimer::m_closed = true;
}

inline void open_spend_time() {
    SpendTimer::m_closed = false;
}

定义一个耗时计时器开启关闭状态类,如下:

/**
 * 耗时计时器开启关闭状态看守,记录之前的耗时开关状态,并置为指定状态,释放时恢复原状态
 */
class SpendTimerGuad {
public:
    /**
     * 构造函数,记录当前状态,并根据 open 指示开启或关闭耗时统计
     * @param open 是否开启耗时统计
     */
    explicit SpendTimerGuad(bool open) : m_open(open) {
        if (open) {
            open_spend_time();
        } else {
            close_spend_time();
        }
    }

    /** 析构函数,退出当前指定状态,恢复原状态 */
    ~SpendTimerGuad() {
        if (m_open) {
            close_spend_time();
        } else {
            open_spend_time();
        }
    }

private:
    bool m_open;
};

定义一些使用工具宏:

#define SPEND_TIME(id)                                                    \
    std::stringstream sptmsg_buf_##id(std::stringstream::out);            \
    sptmsg_buf_##id << #id << " (" << __FILE__ << ":" << __LINE__ << ")"; \
    util::SpendTimer test_spend_timer_##id(sptmsg_buf_##id.str());

/**
 * 代码执行耗时计时器,附带输出信息
 * @param id 自定义耗时计时器id
 * @param ... 符合 fmt::format 方式的输出信息
 */
#define SPEND_TIME_MSG(id, ...)                      \
    std::string msg_##id = fmt::format(__VA_ARGS__); \
    util::SpendTimer test_spend_timer_##id(           \
      fmt::format("{} {} ({}:{})", #id, msg_##id, __FILE__, __LINE__)); 

/**
 * 用于动态控制当前代码块及其子块中的耗时计时器,主要用于测试代码中关闭和开启部分耗时统计
 */
#define SPEND_TIMG_CONTROL(open) util::SpendTimerGuad spend_timer_guard_##open(open);

5. 使用测试

/*
 * test.cc
 * brief: 测试耗时统计工具
 * Created on: 2020-9-5
 *     Author: erices
 */
#include 

#include "SpendTimer.h"

uint64_t Fibonacci(uint32_t i)
{
    if (1 == i)
    {
        return 1;
    }
    else if(2 == i)
    {
        return 2;
    }

    return Fibonacci(i-1) + Fibonacci(i-2);
}

int main()
{
    SPEND_TIMG_CONTROL(true);
    {
        SPEND_TIME_MSG(1, "Fibonacci(20) spend time ");
        Fibonacci(20);
    }

    {
        SPEND_TIME_MSG(2, "Fibonacci(30) spend time ");
        Fibonacci(30);
    }

    {
        SPEND_TIME_MSG(3, "Fibonacci(40) spend time ");
        Fibonacci(40);
    }
    
    return 0;
}
# 测试结果
➜  build ./test_main 
spend time:  26.933 us | 1 Fibonacci(20) spend time  (/root/workspace/util/test.cc:29) 
spend time:   3.047 ms | 2 Fibonacci(30) spend time  (/root/workspace/util/test.cc:34) 
spend time: 346.920 ms | 3 Fibonacci(40) spend time  (/root/workspace/util/test.cc:39) 

编译注意事项:

由于系统中装了多版本gcc库,故编译时需要显示指定版本。未指定版本

➜  build cmake ..
-- The C compiler identification is GNU 4.8.5
-- The CXX compiler identification is GNU 4.8.5
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /root/workspace/util/build

指定gcc版本:

export CC=/usr/local/bin/gcc
export CXX=/usr/local/bin/g++
➜  build cmake ..
-- The C compiler identification is GNU 9.1.0
-- The CXX compiler identification is GNU 9.1.0
-- Check for working C compiler: /apps/sylar/bin/gcc
-- Check for working C compiler: /apps/sylar/bin/gcc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /apps/sylar/bin/g++
-- Check for working CXX compiler: /apps/sylar/bin/g++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /root/workspace/util/build

执行结果:

➜  build ./test_main 
spend time:  26.933 us | 1 Fibonacci(20) spend time  (/root/workspace/util/test.cc:29) 
spend time:   3.047 ms | 2 Fibonacci(30) spend time  (/root/workspace/util/test.cc:34) 
spend time: 346.920 ms | 3 Fibonacci(40) spend time  (/root/workspace/util/test.cc:39) 

你可能感兴趣的:(C/C++,c++)