比较日志性能:Glog、Spdlog 和 ofstream 在不同硬件上的表现(推荐Spdlog)

文章目录

  • 比较日志性能:Glog、Spdlog 和 ofstream 在不同硬件上的表现
    • 1. 引言
    • 2. 测试简介
    • 3. 硬件配置
      • 桌面电脑(Ubuntu 18.04)
      • 树莓派 5(Ubuntu 24.04)
    • 4. 测试结果
      • 桌面电脑(Ubuntu 18.04)
      • 树莓派 5(Ubuntu 24.04)
    • 5. 详细分析
    • 6. 实现代码
    • 7. 其他
      • 7.1 Spdlog 的同步和异步支持
      • 7.2 Glog 的同步和异步
      • 7.3 Glog 的多线程和多进程写入顺序问题
    • 8. 结论
      • 8.1 测试版本差异

比较日志性能:Glog、Spdlog 和 ofstream 在不同硬件上的表现

1. 引言

日志记录是嵌入式系统中关键的调试和监控手段。在选择合适的日志库时,性能往往是重要的考量因素。本文对比了 Spdlog 和 Glog 这两个流行的日志库,以及标准的 ofstream 流在嵌入式平台上的性能表现。测试包括同步和异步模式,以全面评估它们在高频日志记录场景下的性能表现。

2. 测试简介

为了比较 Spdlog 和 Glog 在嵌入式 ARM64 平台上的性能表现,设计了测试代码,分别测试了以下场景下的日志记录耗时:

  • ofstream 同步文件写
  • Spdlog 同步日志记录
  • Spdlog 异步日志记录
  • Glog 同步日志记录

测试使用 10 万条日志数据,每个日志记录 200 字节的消息。测试平台包括桌面电脑(Ubuntu 18.04)和树莓派 5(Ubuntu 24.04)。

3. 硬件配置

桌面电脑(Ubuntu 18.04)

  • CPU:AMD Ryzen 5 3500U with Radeon Vega Mobile Gfx
  • 内存:4.8G
  • 操作系统:Ubuntu 18.04.4 LTS
  • GCC 版本:7.5.0
  • G++ 版本:7.5.0

树莓派 5(Ubuntu 24.04)

  • CPU:Cortex-A76
  • 内存:7.8Gi
  • 操作系统:Ubuntu 24.04 LTS
  • GCC 版本:13.2.0
  • G++ 版本:13.2.0

4. 测试结果

桌面电脑(Ubuntu 18.04)

ofstream logging: 0.0719351 seconds
spdlog sync logging: 0.0720132 seconds
spdlog async logging: 0.160619 seconds
glog logging: 0.297419 seconds

树莓派 5(Ubuntu 24.04)

ofstream logging: 0.390023 seconds
spdlog sync logging: 0.0649371 seconds
spdlog async logging: 0.1108 seconds
glog logging: 0.953905 seconds

测试结果表明,在同步日志记录场景下,ofstream 方式的日志记录耗时最短,其次是 Spdlog 同步日志记录,Glog 同步日志记录耗时最长。Spdlog 异步日志记录耗时比 Spdlog 同步日志记录高出约 2 倍

5. 详细分析

  • ofstream:作为标准的文件写操作,其性能表现优异,但在嵌入式系统中,频繁的文件读写操作可能会对系统整体性能造成一定影响。

  • spdlog:在同步场景下通过原子操作和锁机制保证线程安全,相比 Glog 的单线程模型,性能有所提升。Spdlog 的异步日志记录采用多线程和消息队列的方式,将日志记录操作与主线程分离,有效降低了对主线程的影响,但也带来了一定的性能开销。

  • glog:同步日志记录存在性能问题,可能与其单线程模型以及日志格式化等因素有关。Glog 的异步日志记录并未进行测试,因为标准 Glog 库不直接支持异步日志记录。

6. 实现代码

#include <glog/logging.h>
#include <spdlog/async.h>
#include <spdlog/sinks/basic_file_sink.h>
#include <spdlog/spdlog.h>#include <chrono>
#include <cstdio>  // for std::remove
#include <fstream>
#include <iostream>
#include <memory>
#include <string>
#include <vector>const int LOG_COUNT = 100000;
const int MESSAGE_SIZE = 200;std::vector<std::string> generate_messages(int count, int size) {std::vector<std::string> messages(count);std::string sample_message(size, 'x');for (int i = 0; i < count; ++i) {messages[i] = "This is a test log message number " + std::to_string(i) + ": " + sample_message;}return messages;
}void initialize_logging() {FLAGS_log_dir = ".";FLAGS_logtostderr = false;FLAGS_alsologtostderr = false;google::InitGoogleLogging("glog_async_worker");spdlog::init_thread_pool(8192, 1);  // Assuming 1 background thread for the example
}void shutdown_logging() {google::ShutdownGoogleLogging();spdlog::shutdown();
}void prepare_log_files() {// Create or truncate the log filesstd::ofstream("ofstream_log.txt").close();std::ofstream("spdlog_sync.txt").close();std::ofstream("spdlog_async.txt").close();std::ofstream("glog_example.INFO").close();
}void test_logging(const std::string& test_name, std::function<void(const std::vector<std::string>&)> log_function,const std::vector<std::string>& messages) {auto start = std::chrono::high_resolution_clock::now();log_function(messages);auto end = std::chrono::high_resolution_clock::now();std::chrono::duration<double> elapsed = end - start;std::cout << test_name << ": " << elapsed.count() << " seconds" << std::endl;
}void test_ofstream(const std::vector<std::string>& messages) {std::ofstream log_file("ofstream_log.txt");for (const auto& message : messages) {log_file << message << "\n";}
}void test_spdlog_sync(const std::vector<std::string>& messages) {auto logger = spdlog::basic_logger_mt("spdlog_sync", "spdlog_sync.txt");for (const auto& message : messages) {logger->info(message);}
}void test_spdlog_async(const std::vector<std::string>& messages) {auto logger = spdlog::basic_logger_mt<spdlog::async_factory>("spdlog_async", "spdlog_async.txt");for (const auto& message : messages) {logger->info(message);}
}void test_glog(const std::vector<std::string>& messages) {for (const auto& message : messages) {LOG(INFO) << message;}
}int main() {initialize_logging();auto messages = generate_messages(LOG_COUNT, MESSAGE_SIZE);prepare_log_files();test_logging("ofstream logging", test_ofstream, messages);prepare_log_files();test_logging("spdlog sync logging", test_spdlog_sync, messages);prepare_log_files();test_logging("spdlog async logging", test_spdlog_async, messages);prepare_log_files();test_logging("glog logging", test_glog, messages);shutdown_logging();return 0;
}

7. 其他

7.1 Spdlog 的同步和异步支持

  • Spdlog 明确支持同步和异步两种日志记录模式。
  • 在异步模式下,Spdlog 使用单独的线程处理日志写入操作,减少了日志记录对主线程的影响,特别是在高并发写入日志的场景下,能显著提高性能。

7.2 Glog 的同步和异步

  • Glog 原生设计为同步日志库,即日志记录操作在调用线程中执行。
  • 同步模式在高日志输出频率的场景中,可能会影响应用程序的性能,尤其是对响应时间有严格要求的场景。
  • 标准 Glog 库本身不直接支持异步日志记录。
  • 社区中存在一些非官方的扩展,如 G2log 和 G3log,它们基于 C++11 编写,提供了异步日志功能。

7.3 Glog 的多线程和多进程写入顺序问题

  • Glog 的设计没有明确保证多线程或多进程同时写入同一日志文件时,日志的顺序能严格按照写入时的时间顺序。
  • 高并发写入情况下,不同线程或进程的日志条目可能因操作系统调度、磁盘 I/O 缓冲等原因交错写入,导致日志顺序混乱。

8. 结论

在嵌入式 ARM64 平台上:

  • 追求极致性能:建议使用 ofstream 进行日志记录。
  • 兼顾性能和线程安全spdlog 是一个不错的选择。
  • 高性能要求场景glog 在性能方面表现不佳,不推荐用于对性能要求较高的嵌入式系统。

8.1 测试版本差异

需要注意的是,不同平台、不同版本的操作系统及编译器版本可能会对测试结果产生影响。本文测试结果基于特定版本的硬件和软件配置,其他配置可能会有不同的性能表现。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/30258.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[Linux] vi编辑器

命令模式&文本模式 命令模式就输入命令然后执行&#xff0c;文本模式就是系统把你的输入都当成写进文件里的字符 切换模式&#xff1a; 刚进入默认是命令模式&#xff0c;按: i I a A o O 进入文本模式&#xff0c; 通过他们进入文本模式有什么不同&#xff1f; 然后按esc进…

python 版本切换,更换当前默认版本

电脑可以安装多个版本&#xff0c;但是好像没有正规的维护python版本的工具&#xff0c;比如前端就有nvm切换node版本&#xff0c;但是python我没找到比较好的&#xff08;有大佬知道路过方便留言一下&#xff0c;跪谢。。&#xff09; 废话不多说&#xff0c;更改默认版本很简…

字节跳动万卡集群网络分析

从公开的信息披露,截至2023年9月,字节跳动已经建立超过一万张的英伟达Ampere架构GPU集群,目前正在建设Hopper架构的集群。英伟达Ampere架构主要包括A100和A800型号的芯片,Hopper架构相较前者则更新,主要包括H100和H800芯片 字节和北大公布的论文,关于网络拓扑的描述主要…

DIVE INTO DEEP LEARNING 36-49

文章目录 36. Data augmentation36.1 Training with enhanced data36.2 Enhancement measures36.3 Data augmentation summary 37. Fine tuning37.1 Fine tuning Introduce37.2 Fine tuning Step37.3 Fine tuning summary 38. Object detection38.1 Object detection38.2 Edge …

[Linux] Shell

chsh不是一种sh,而是一个命令行使用程序&#xff0c;用于更改默认shell CentOS是个开源软件&#xff0c;没有sh,sh是商业版的&#xff0c; 按ls /bin/*sh显示的sh实际上是个链接文件&#xff0c;连接的bash 在命令行输入新的sh名&#xff0c;会启动一个新的进程&#xff0c; 输…

厂里资讯之app端文章搜索

app端文章搜索 1) 内容介绍 文章搜索 ElasticSearch环境搭建 索引库创建 文章搜索多条件复合查询 索引数据同步 搜索历史记录 Mongodb环境搭建 异步保存搜索历史 查看搜索历史列表 删除搜索历史 联想词查询 联想词的来源 联想词功能实现 2) 搭建ElasticSearch环境 …

MyBatis系列七: 一级缓存,二级缓存,EnCache缓存

缓存-提高检索效率的利器 官方文档 一级缓存基本介绍快速入门Debug一级缓存执行流程一级缓存失效分析 二级缓存基本介绍快速入门Debug二级缓存执行流程注意事项和使用细节 mybatis的一级缓存和二级缓存执行顺序小实验细节说明 EnCache缓存基本介绍配置和使用EhCache细节说明 My…

SpringBoot整合Minio(支持公有及私有bucket)

&#x1f60a; 作者&#xff1a; 一恍过去 &#x1f496; 主页&#xff1a; https://blog.csdn.net/zhuocailing3390 &#x1f38a; 社区&#xff1a; Java技术栈交流 &#x1f389; 主题&#xff1a; SpringBoot整合Minio(支持公有及私有bucket) ⏱️ 创作时间&#xff1…

java多版本管理

一 java 多版本管理 使用 jenv, 地址&#xff1a;https://github.com/jenv/jenv mac 操作 brew install jenv# Shell: zsh echo export PATH"$HOME/.jenv/bin:$PATH" >> ~/.zshrc echo eval "$(jenv init -)" >> ~/.zshrc source ~/.zshrc需要…

张大哥笔记:如何选择一个人就值得做的副业

很多人喜欢把上班称为主业&#xff0c;把上班之外的工作称为副业&#xff0c;不管以哪种方式称呼都可以&#xff0c;只要能赚钱就行&#xff0c;上班的本质就是出卖时间&#xff0c;不管你是月入5000还是月入2万&#xff0c;都是给老板打工&#xff01; 但搞笑的就是月入2万的人…

关于app爬虫的环境准备

摘要 有些数据需要在手机应用中才能查看&#xff0c;没有网页版&#xff0c;所以学习移动端的爬虫是有必要的。 手机系统分为安卓和苹果两大系统&#xff0c;本次讲解主要以安卓手机为例 有安卓手机的可以使用手机&#xff0c;没有的可以使用模拟器&#xff0c;本次以夜神模…

基于C++、MFC和Windows套接字实现的简单聊天室程序开发

一、一个简单的聊天室程序 该程序由服务器端和客户端两个项目组成&#xff0c;这两个项目均基于对话框的程序。服务器端项目负责管理客户端的上线、离线状态&#xff0c;以及转发客户端发送的信息。客户端项目则负责向服务器发送信息&#xff0c;并接收来自服务器的信息&#…

YAML 快速上手

文章目录 1.语法2.历史版本3.数据结构对象数组复合结构标量 4.引用5.文本块6.显示指定类型7.单文件多文档8.解析9.完整示例参考文献 YAML&#xff08;YAML Ain’t a Markup Language&#xff09;是专门用来写配置文件的语言&#xff0c;简洁强大&#xff0c;相比于 JSON 和 XML…

R包开发详细教程

开发一个R包可以帮助你组织和共享代码。以下是一个详细的步骤教程&#xff0c;介绍如何开发一个R包。 步骤 1: 准备工作 确保你已经安装了以下R包&#xff1a; install.packages("devtools") install.packages("roxygen2") install.packages("test…

[机器学习算法]决策树

1. 理解决策树的基本概念 决策树是一种监督学习算法&#xff0c;可以用于分类和回归任务。决策树通过一系列规则将数据划分为不同的类别或值。树的每个节点表示一个特征&#xff0c;节点之间的分支表示特征的可能取值&#xff0c;叶节点表示分类或回归结果。 2. 决策树的构建…

基于深度学习的图像压缩

基于深度学习的图像压缩 图像压缩是指将图像数据量减小的同时尽量保留其视觉质量的过程。传统的图像压缩方法&#xff08;如JPEG、PNG等&#xff09;已经广泛应用&#xff0c;但随着深度学习技术的发展&#xff0c;基于深度学习的图像压缩方法逐渐显现出其优越性。以下是一些关…

【AI原理解析】— Kimi模型

目录 一、技术背景与基础 二、核心技术特点 深度学习与神经网络&#xff1a; 超长上下文学习&#xff1a; 多模态对齐&#xff1a; 个性化调优&#xff1a; 知识增强&#xff1a; 推理优化&#xff1a; 三、模型架构 一、技术背景与基础 Kimi模型是一种基于深度学习和…

enum库

Python enum 模块教程 enum 是 Python 3.4 引入的一个模块&#xff0c;用于定义枚举类型。枚举类型是一种特殊的数据类型&#xff0c;由一组命名的值组成&#xff0c;这些值称为枚举成员。使用 enum 可以提高代码的可读性和可维护性&#xff0c;特别是在处理一组相关的常量值时…

Laravel 的事件监听器与服务提供者和服务容器的二三事

一. Laravel 的事件监听器与服务提供者和服务容器有密切的关系。 服务提供者用于注册服务、绑定依赖关系以及执行框架的初始化设置。在服务提供者的 register 方法中&#xff0c;可以注册事件和事件监听器。 服务容器则负责管理对象的创建和依赖注入。事件监听器通常会被注册…

人工智能和机器学习的应用日益广泛,在医疗健康领域的具体应用是什么?

人工智能&#xff08;AI&#xff09;和机器学习&#xff08;ML&#xff09;在医疗健康领域的应用日益广泛&#xff0c;涵盖了从疾病预测、辅助诊断、药物研发到健康管理等多个方面。以下是一些具体的应用实例和成功案例&#xff1a; 疾病预测与辅助诊断&#xff1a;机器学习算…