源自OSRM中的经典代码

背景

OSRM backend 代码中有一个timing_util.hpp的头文件,其利用宏以及c++11 chrono 实现了统计代码运行时间的工具。
在工程中统计代码运行时间非常常用,本文介绍OSRM timing_util的实现原理,并用示例来说明。

实现解析

timing_util.hpp

#ifndef TIMING_UTIL_HPP
#define TIMING_UTIL_HPP

#include <chrono>
#include <cstdint>

namespace osrm
{
namespace util
{
// 用TIMER_START 定义一个变量记录开始的时间
#define TIMER_START(_X) auto _X##_start = std::chrono::steady_clock::now(), _X##_stop = _X##_start
// 用TIMER_STOP 定义一个变量记录结束的时间
#define TIMER_STOP(_X) _X##_stop = std::chrono::steady_clock::now()
// TIMER_NSEC 定义start到stop经历了多少纳秒
#define TIMER_NSEC(_X)                                                                             \
    std::chrono::duration_cast<std::chrono::nanoseconds>(_X##_stop - _X##_start).count()
// TIMER_USEC 定义start到stop历经多少微秒
#define TIMER_USEC(_X)                                                                             \
    std::chrono::duration_cast<std::chrono::microseconds>(_X##_stop - _X##_start).count()
// TIMER_MSEC 定义start到stop经历多少毫秒
#define TIMER_MSEC(_X)                                                                             \
    (0.000001 *                                                                                    \
     std::chrono::duration_cast<std::chrono::nanoseconds>(_X##_stop - _X##_start).count())
// TIMER_SEC 定义start到stop经历多少秒
#define TIMER_SEC(_X)                                                                              \
    (0.000001 *                                                                                    \
     std::chrono::duration_cast<std::chrono::microseconds>(_X##_stop - _X##_start).count())
// TIMER_MIN 定义start到stop经历多少分钟
#define TIMER_MIN(_X)                                                                              \
    std::chrono::duration_cast<std::chrono::minutes>(_X##_stop - _X##_start).count()
}
}

#endif // TIMING_UTIL_HPP

timing_util在定义宏变量时使用 ##,##的作用是把宏参数和相邻的字符进行字符串连接,# 的作用是把宏参数当做一个字符串。以下是关于宏中# 以及## 用法的示例。

/*************************************************************************
    > File Name: test_macro.cpp
    > Author: ce39906
    > Mail: ce39906@163.com
    > Created Time: 2018-06-05 17:38:01
 ************************************************************************/
#include <iostream>

#define STR(s) #s
#define CONS(a, b) int(a##e##b)

int main()
{
    // 输出字符串abc
    std::cout << STR(abc) << std::endl;
    // 输出2000 (2e3 == 2000)
    std::cout << CONS(2, 3) << std::endl;
    return 0;
}

TIMING_UTIL统计运行时间示例

timing_util.cpp

/*************************************************************************
    > File Name: timing_util.cpp
    > Author: ce39906
    > Mail: ce39906@163.com
    > Created Time: 2018-06-05 17:46:50
 ************************************************************************/
#include "timing_util.hpp"
#include <iostream>

using namespace osrm::util;

int main()
{
    TIMER_START(x);
    for (int i = 0; i < 10000; i++)
    {
        for (int j = 0; j < 10000; j++)
        {
            int ij = i * j;
        }
    }
    TIMER_STOP(x);
    std::cout << "Two Level Loop Cost " << TIMER_NSEC(x) << " ns.\n";
    std::cout << "Two Level Loop Cost " << TIMER_USEC(x) << " us.\n";
    std::cout << "Two Level Loop Cost " << TIMER_MSEC(x) << " ms.\n";
    std::cout << "Two Level Loop Cost " << TIMER_SEC(x) << " s.\n";
    std::cout << "Two Level Loop Cost " << TIMER_MIN(x) << " min.\n";
    return 0;
}

编译

g++ timing_util.cpp -o timing_util --std=c++11

运行

./timing_util

运行结果如下
avatar