一、需求分析
在开发阶段中,经常会需要打印出某些方式或步骤的耗时情况,大致需求如下:
- 能打印出某个步骤的耗时;
- 有开关可以控制打开和关闭耗时统计;
- 使用方便。
二、准备工作
之前介绍过一个 log 输出的工具类,可以沿用,链接为:https://blog.csdn.net/afei__/article/details/81030373。
LogUtils.h 示例:
#ifndef _LOG_UTILS_H_
#define _LOG_UTILS_H_
#ifdef __ANDROID__ // Android平台
#include <android/log.h>
#else // 其它平台
#include <stdio.h>
#endif // __ANDROID__
#include <string.h>
#define DEBUG // 可以通过 CmakeLists.txt 等方式来定义在这个宏,实现动态打开和关闭LOG
// Windows 和 Linux 这两个宏是在 CMakeLists.txt 通过 ADD_DEFINITIONS 定义的
#ifdef Windows
#define __FILENAME__ (strrchr(__FILE__, '\\') + 1) // Windows下文件目录层级是'\\'
#else
#define __FILENAME__ (strrchr(__FILE__, '/') + 1) // Linux下文件目录层级是'/',默认使用这种方式
#endif // Windows
#ifdef DEBUG // 如果打开了 DEBUG 开关
#ifdef __ANDROID__
#define TAG "JNI"
#define LOGV(fmt, ...) __android_log_print(ANDROID_LOG_VERBOSE, TAG, "[%s][%s][%d]: " fmt, __FILENAME__, __FUNCTION__, __LINE__, ##__VA_ARGS__)
#define LOGD(fmt, ...) __android_log_print(ANDROID_LOG_DEBUG, TAG, "[%s][%s][%d]: " fmt, __FILENAME__, __FUNCTION__, __LINE__, ##__VA_ARGS__)
#define LOGI(fmt, ...) __android_log_print(ANDROID_LOG_INFO, TAG, "[%s][%s][%d]: " fmt, __FILENAME__, __FUNCTION__, __LINE__, ##__VA_ARGS__)
#define LOGW(fmt, ...) __android_log_print(ANDROID_LOG_WARN, TAG, "[%s][%s][%d]: " fmt, __FILENAME__, __FUNCTION__, __LINE__, ##__VA_ARGS__)
#define LOGE(fmt, ...) __android_log_print(ANDROID_LOG_ERROR, TAG, "[%s][%s][%d]: " fmt, __FILENAME__, __FUNCTION__, __LINE__, ##__VA_ARGS__)
#else
#define LOGV(fmt, ...) printf("[%s][%s][%d]: " fmt "\n", __FILENAME__, __FUNCTION__, __LINE__, ##__VA_ARGS__)
#define LOGD(fmt, ...) printf("[%s][%s][%d]: " fmt "\n", __FILENAME__, __FUNCTION__, __LINE__, ##__VA_ARGS__)
#define LOGI(fmt, ...) printf("[%s][%s][%d]: " fmt "\n", __FILENAME__, __FUNCTION__, __LINE__, ##__VA_ARGS__)
#define LOGW(fmt, ...) printf("[%s][%s][%d]: " fmt "\n", __FILENAME__, __FUNCTION__, __LINE__, ##__VA_ARGS__)
#define LOGE(fmt, ...) printf("[%s][%s][%d]: " fmt "\n", __FILENAME__, __FUNCTION__, __LINE__, ##__VA_ARGS__)
#endif // __ANDROID__
#else // 如果没打开 DEBUG 开关,则只是一些空的语句
#define LOGV(fmt, ...)
#define LOGD(fmt, ...)
#define LOGI(fmt, ...)
#define LOGW(fmt, ...)
#define LOGE(fmt, ...)
#endif // DEBUG
#endif // _LOG_UTILS_H_
三、耗时工具类
1. TimeUtils.h
#ifndef _TIME_UTILS_H_
#define _TIME_UTILS_H_
#include "LogUtils.h"
#ifdef DEBUG // 在 LogUtils.h 中定义了,也可以单独使用另一个宏开控制开关
#include <ctime>
#include <chrono>
#define __TIC__(tag) auto time_##tag##_start = std::chrono::high_resolution_clock::now()
#define __TOC__(tag) auto time_##tag##_end = std::chrono::high_resolution_clock::now();\
std::chrono::duration<double> time_##tag##_elapsed = std::chrono::duration_cast<std::chrono::duration<double>>(time_##tag##_end - time_##tag##_start);\
LOGD(#tag " time: %.3f ms", time_##tag##_elapsed.count() * 1000)
#else
#define __TIC__(tag)
#define __TOC__(tag)
#endif // DEBUG
#endif //_TIME_UTILS_H_
2. 使用示例
#include "TimeUtils.h" // 包含这个头文件
int dump_image(const char *path, unsigned char *data, unsigned int len) {
FILE *file = fopen(path, "wb");
if (file == NULL) {
LOGE("fopen %s failed.", path);
return -1;
}
__TIC__(fwrite); // 耗时统计起始处
int size = fwrite(data, 1, len, file);
__TOC__(fwrite); // 耗时统计终止处,注意括号内的内容必须一致
fclose(file);
return 0;
}
然后运行程序就会有类似如下的信息输出:
D/JNI: [ImageUtils.cpp][dump_image][97]: fwrite: 1.037 ms