当前位置: 首页 > article >正文

C++ 日志系统实战第六步:性能测试

全是通俗易懂的讲解,如果你本节之前的知识都掌握清楚,那就速速来看我的项目笔记吧~   

本文项目结束!


性能测试

下面对日志系统做一个性能测试,测试一下平均每秒能打印多少条日志消息到文件。
主要的测试方法是:每秒能打印日志数 = 打印日志条数 / 总的打印日志消耗时间
主要测试要素:同步 / 异步 & 单线程 / 多线程

  • 100w + 条指定长度的日志输出所耗时间
  • 每秒可以输出多少条日志
  • 每秒可以输出多少 MB 日志

测试环境:

  • CPU: AMD Ryzen 7 5800H with Radeon Graphics 3.20 GHz
  • RAM: 16G DDR4 3200
  • ROM: 512G-SSD
  • OS: ubuntu-22.04TLS 虚拟机(2CPU 核心 / 4G 内存)

 

bench.cc

#include"../logs/mylog.h"#include<chrono>
void bench(const std::string &logger_name,size_t thread_count,size_t msg_count,size_t msg_len)
{//1.获取日志器mylog::Logger::ptr logger=mylog::get_logger(logger_name);if(logger.get()==nullptr){return;}std::cout<<"开始测试:"<<msg_count<<"条日志,总大小为:"<<msg_count*msg_len/1024<<"KB"<<std::endl;//2.组织指定长度的日志消息std::string msg(msg_len-1,'a');//少一个字符,以便于结尾有换行符//3.创建指定数量的线程std::vector<std::thread> threads;size_t msg_per_thread=msg_count/thread_count;std::vector<double> cost_arry(thread_count);for(size_t i=0;i<thread_count;i++){threads.emplace_back([&,i](){//4.线程函数内部开始计时auto start_time=std::chrono::high_resolution_clock::now();//5.开始循环写日志for(size_t j=0;j<msg_per_thread;j++){logger->fatal(msg);}//6.线程函数內部结束计时auto end_time=std::chrono::high_resolution_clock::now();std::chrono::duration<double> cost=end_time-start_time;cost_arry[i]=cost.count();std::cout<<"线程 "<<i<<": "<<"\t 输出日志数量:"<<msg_per_thread<<"\t 总耗时:"<<cost.count()<<"s"<<std::endl;});}for(int i=0;i<thread_count;i++){threads[i].join();}//7.计算总耗时:在多线程中,每个线程都会消耗时间,但是线程是并发执行的,所以总耗时是最高的线程的耗时double max_cost=0;for(int i=0;i<thread_count;i++){if(cost_arry[i]>max_cost){max_cost=cost_arry[i];}}size_t msg_per_sec=msg_count/max_cost;size_t size_pre_sec=(msg_count+msg_len)/(max_cost*1024);std::cout<<"总耗时:"<<max_cost<<"s"<<std::endl;std::cout<<"日志输出速度:"<<msg_per_sec<<"条/秒"<<std::endl;std::cout<<"日志输出速度:"<<size_pre_sec<<"KB/秒"<<std::endl;
}
void sync_bench()
{std::shared_ptr<mylog::Logger_builder> builder(new mylog::Global_logger_builder());builder->buildLoggerName("Sync_logger");builder->buildLimitLevel(mylog::Level::Debug);builder->buildLoggerType(mylog::LoggerType::Loggertype_Sync); // 同步日志器builder->buildFormatBuilder("%m%n");builder->buildSinks<mylog::FileSink>("./logfile/sync.log");builder->build();bench("Sync_logger",1,1000000,100);
}
void async_bench()
{std::shared_ptr<mylog::Logger_builder> builder(new mylog::Global_logger_builder());builder->buildLoggerName("Async_logger");builder->buildLimitLevel(mylog::Level::Debug);builder->buildLoggerType(mylog::LoggerType::Loggertype_Async); // 异步日志器builder->buildFormatBuilder("%m%n");builder->buildSinks<mylog::FileSink>("./logfile/async.log");builder->build();bench("Async_logger",3,1000000,100);
}
int main()
{//sync_bench();async_bench();return 0;
}

单线程: 

多线程: 

text.cc(用于普通情况) 

#include "../logs/mylog.h"void loggerTest(const std::string &logger_name) {INFO("------------example--------------------");mylog::Logger::ptr lp = mylog::LoggerManager::getInstance().getLogger(logger_name);lp->debug("%s", "logger->debug");lp->info("%s", "logger->info");lp->warn("%s", "logger->warn");lp->error("%s", "logger->error");lp->fatal("%s", "logger->fatal");// INFO("---------------------------------------");std::string log_msg = "hello -";size_t fsize = 0;size_t count = 0;while(count < 10000) {std::string msg = log_msg + std::to_string(count++);lp->error("%s", msg.c_str());}
}
void functional_test() {
}
int main(int argc, char *argv[])
{std::shared_ptr<mylog::Logger_builder> builder(new mylog::Global_logger_builder());builder->buildLoggerName("Async_logger");builder->buildLimitLevel(mylog::Level::Debug);builder->buildLoggerType(mylog::LoggerType::Loggertype_Async); // 异步日志器builder->buildFormatBuilder("[%d{%H:%M:%S}][%t][%p][%c][%f:%l] %m%n");builder->buildSinks<mylog::StdoutSink>();builder->buildSinks<mylog::FileSink>("./logfile/test_file.log");builder->buildSinks<mylog::RollSinkbySize>("./logfile/test_roll.log", 1024 * 1024*0.6);builder->build();loggerTest("Async_logger");return 0;
}

text.cc(用于根据时间分配文件的情况) 

//对时间分块
#include "../logs/mylog.h"void loggerTest(const std::string &logger_name) {INFO("------------example--------------------");mylog::Logger::ptr lp = mylog::LoggerManager::getInstance().getLogger(logger_name);lp->debug("%s", "logger->debug");lp->info("%s", "logger->info");lp->warn("%s", "logger->warn");lp->error("%s", "logger->error");lp->fatal("%s", "logger->fatal");// INFO("---------------------------------------");std::string log_msg = "hello -";size_t fsize = 0;size_t count = 0;time_t start_time = mylog::util::Date::getTime();while(mylog::util::Date::getTime() - start_time < 5) {std::string msg = log_msg + std::to_string(count++);usleep(1000);lp->error("%s", msg.c_str());}
}
void functional_test() {
}
int main(int argc, char *argv[])
{std::shared_ptr<mylog::Logger_builder> builder(new mylog::Global_logger_builder());builder->buildLoggerName("Async_logger");builder->buildLimitLevel(mylog::Level::Debug);builder->buildLoggerType(mylog::LoggerType::Loggertype_Async); // 异步日志器builder->buildFormatBuilder("[%d{%H:%M:%S}][%t][%p][%c][%f:%l] %m%n");builder->buildSinks<mylog::StdoutSink>();builder->buildSinks<mylog::FileSink>("./logfile/test_file.log");builder->buildSinks<mylog::RollSinkbyTime>("./logfile/test_roll.log", mylog::TimeInterval::SECOND); // 按时间分块builder->build();loggerTest("Async_logger");return 0;
}


感谢你看到这里~日志系统的项目已经全部实现完成了!

未来共同进步,期待你的关注👉【A charmer】

相关文章:

C++ 日志系统实战第六步:性能测试

全是通俗易懂的讲解&#xff0c;如果你本节之前的知识都掌握清楚&#xff0c;那就速速来看我的项目笔记吧~ 本文项目结束&#xff01; 性能测试 下面对日志系统做一个性能测试&#xff0c;测试一下平均每秒能打印多少条日志消息到文件。 主要的测试方法是&#xff1a;每秒能…...

低代码平台搭建

学习低代码平台搭建需要掌握几个核心模块,尤其是动态表单引擎和DSL(领域特定语言)设计,以下是系统化的知识总结: 一、低代码平台的核心模块 低代码平台的核心是让用户通过可视化交互快速生成应用,核心模块包括: 可视化设计器(拖拽布局、组件配置)DSL(领域特定语言)…...

AI编程对传统软件开发的冲击和思考

2025年&#xff0c;如果你所在的软件公司还活着&#xff0c;恭喜&#xff0c;你的老板很坚挺&#xff0c;很有福报。 不过&#xff0c;25年年底的时候&#xff0c;就不好说了&#xff01; Claude说年底的时候&#xff0c;Claude就可以实现不间断一直编程模式。 一个比996还狠…...

Java桌面应用开发详解:自制截图工具从设计到打包的全流程【附源码与演示】

&#x1f525; 本文详细介绍一个Java/JavaFX学习项目——轻量级智能截图工具的开发实践。通过这个项目&#xff0c;你将学习如何使用Java构建桌面应用&#xff0c;掌握JavaFX界面开发、系统托盘集成、全局快捷键注册等实用技能。本文主要关注基础功能实现&#xff0c;适合Java初…...

手写一个简单的线程池

手写一个简单的线程池 项目仓库&#xff1a;https://gitee.com/bossDuy/hand-tearing-thread-pool 基于一个b站up的课程&#xff1a;https://www.bilibili.com/video/BV1cJf2YXEw3/?spm_id_from333.788.videopod.sections&vd_source4cda4baec795c32b16ddd661bb9ce865 理…...

AI开发实习生面试总结(持续更新中...)

1.广州视宴&#xff08;ai开发实习生&#xff09; 首先是自我介绍~ 1.第二个项目中的热力图是用怎么样的方式去做的&#xff1f; 2.在第二个项目中&#xff0c;如何用热力图去实现它的实时变化 答&#xff1a;我这里直接说我项目里面其实静态的热力图&#xff0c;不是动态的…...

python实战:Python脚本后台运行的方法

在Linux/Unix系统中,有几种方法可以让Python脚本在后台运行: 1. 使用 & 符号 最简单的后台运行方式是在命令末尾添加 &: python your_script.py &这样会将脚本放入后台运行,但关闭终端时脚本可能会被终止。 2. 使用 nohup 命令 nohup 可以让脚本在退出终端…...

siparmyknife:SIP协议渗透测试的瑞士军刀!全参数详细教程!Kali Linux教程!

简介 SIP Army Knife 是一个模糊测试器&#xff0c;用于搜索跨站点脚本、SQL 注入、日志注入、格式字符串、缓冲区溢出等。 安装 源码安装 通过以下命令来进行克隆项目源码&#xff0c;建议请先提前挂好代理进行克隆。 git clone https://github.com/foreni-packages/sipa…...

【Hexo】2.常用的几个命令

new 在根目录下执行 hexo new "文章标题" 命令&#xff0c;会在 source/_posts 目录下生成一个 .md 文件。 hexo new "文章标题"clean 在根目录下执行 hexo clean 命令&#xff0c;会清除 public 目录下的所有文件。 hexo cleangenerate 在根目录下执…...

OceanBase 系统表查询与元数据查询完全指南

文章目录 一、OceanBase 元数据基础概念1.1 元数据的定义与重要性1.2 OceanBase 元数据分类体系二、系统表查询核心技术2.1 核心系统表详解2.1.1 集群管理表2.1.2 租户资源表2.2 高级查询技巧2.2.1 跨系统表关联查询2.2.2 历史元数据查询三、元数据查询实战应用3.1 日常运维场景…...

【Java高阶面经:微服务篇】4.大促生存法则:微服务降级实战与高可用架构设计

一、降级决策的核心逻辑:资源博弈下的生存选择 1.1 大促场景的资源极限挑战 在电商大促等极端流量场景下,系统面临的资源瓶颈呈现指数级增长: 流量特征: 峰值QPS可达日常的50倍以上(如某电商大促下单QPS从1万突增至50万)流量毛刺持续时间短(通常2-4小时),但对系统稳…...

通过上传使大模型读取并分析文件实战

一、技术背景与需求分析 我们日常在使用AI的时候一定都上传过文件&#xff0c;AI会根据用户上传的文件内容结合用户的请求进行分析&#xff0c;给出用户解答。但是这是怎么实现的呢&#xff1f;在我们开发自己的大模型应用时肯定是不可避免的要思考这个问题&#xff0c;今天我会…...

VueRouter路由组件的用法介绍

1.1、<router-link>标签 <router-link>标签的作用是实现路由之间的跳转功能&#xff0c;默认情况下&#xff0c;<router-link>标签是采用超链接<a>标签显示的&#xff0c;通过to属性指定需要跳转的路由地址。当然&#xff0c;如果你不想使用默认的<…...

数据结构第1章 (竟成)

第 1 章 编程基础 1.1 前言 因为数据结构的代码大多采用 C 语言进行描述。而且&#xff0c;408 考试每年都有一道分值为 13 - 15 的编程题&#xff0c;要求使用 C/C 语言编写代码。所以&#xff0c;本书专门用一章来介绍 408 考试所需的 C/C 基础知识。有基础的考生可以快速浏览…...

Terraform创建阿里云基础组件资源

这里首先要找到阿里云的官方使用说明: 中文版:Terraform(Terraform)-阿里云帮助中心 英文版:Terraform Registry 各自创建一个阿里云的RAM子账号,并给与OPAPI的调用权限,(就是有aksk,生成好之后保存下.) 创建路径: 登陆阿里云主账号-->控制台-->右上角企业-->人员…...

企业级调度器LVS

访问效果 涉及内容&#xff1a;浏览拆分、 DNS 解析、反向代理、负载均衡、数据库等 1 集群 1.1 集群类型简介 对于⼀个业务项⽬集群来说&#xff0c;根据业务中的特性和特点&#xff0c;它主要有三种分类&#xff1a; 高扩展 (LB) &#xff1a;单个主机负载不足的时候&#xf…...

【Web前端】HTML网页编程基础

HTML5简介与基础骨架 HTML5是用来描述网页的一种语言&#xff0c;被称为超文本标记语言。用HTML5编写的文件&#xff0c;后缀以.html结尾 HTML是一种标记语言&#xff0c;标记语言是一套标记标签。标签是由尖括号包围的关键字&#xff0c;例如<html> 标签有两种表现形…...

阿里开源 CosyVoice2:打造 TTS 文本转语音实战应用

1、引言 1.1、CosyVoice2 简介 阿里通义实验室推出音频基座大模型 FunAudioLLM,包含 SenseVoice 和 CosyVoice 两大模型。 CosyVoice:模拟音色与提升情感表现力 多语言 支持的语言: 中文、英文、日文、韩文、中文方言(粤语、四川话、上海话、天津话、武汉话等)跨语言及…...

【C/C++】红黑树插入/删除修复逻辑解析

文章目录 红黑树插入修复逻辑解析✅ 函数原型✅ 外层循环条件✅ 拿到祖父节点✅ Case 1&#xff1a;父节点是祖父的左孩子① 叔叔节点是红色 → 情况1&#xff1a;**颜色翻转&#xff08;Recolor&#xff09;**② 叔叔节点是黑色或为空 → 情况2或3&#xff1a;**旋转 颜色修复…...

RabbitMQ可靠传输——持久性、发送方确认

一、持久性 前面学习消息确认机制时&#xff0c;是为了保证Broker到消费者直接的可靠传输的&#xff0c;但是如果是Broker出现问题&#xff08;如停止服务&#xff09;&#xff0c;如何保证消息可靠性&#xff1f;对此&#xff0c;RabbitMQ提供了持久化功能&#xff1a; 持久…...

AWS stop/start 使实例存储lost + 注意点

先看一下官方的说明: EC2有一个特性,当执行stop/start操作(注意,这个并不是重启/reboot,而是先停止/stop,再启动/start)时,该EC2会迁移到其它的底层硬件上。 对于实例存储来说,由于实例存储是由其所在的底层硬件来提供的,此时相当于分配到了一块全新的空的磁盘。 但是从…...

数字计数--数位dp

1.不考虑前导零 2.每一位计数&#xff0c;就是有点“数页码”的意思 P2602 [ZJOI2010] 数字计数 - 洛谷 相关题目&#xff1a;记得加上前导零 数页码--数位dp-CSDN博客 https://blog.csdn.net/2301_80422662/article/details/148160086?spm1011.2124.3001.6209 #include…...

掌握递归:编程中的优雅艺术

当然可以&#xff01;你愿意迈出学习递归的重要一步&#xff0c;真的很棒&#xff01;&#x1f31f; 递归&#xff0c;虽然一开始看着有点绕&#xff0c;但掌握之后&#xff0c;你会发现它是编程中非常优雅且强大的工具。 我用简单又清晰的方式教你。请跟着我一步步来&#xf…...

无人机开启未来配送新篇章

低空物流&#xff08;无人机物流&#xff09;是利用无人机等低空飞行器进行货物运输的物流方式&#xff0c;依托低空空域&#xff08;通常在120-300米&#xff09;实现快速、高效、灵活的配送服务。它是低空经济的重要组成部分&#xff0c;广泛应用于快递配送、医疗物资运输、农…...

el-input宽度自适应方法总结

使用 style 或 class 直接设置宽度 可以通过内联样式或 CSS 类来直接设置 el-input 的宽度为 100%&#xff0c;使其自适应父容器的宽度 <template><div style"width: 100%;"><el-input style"width: 100%;" v-model"input">…...

Qt状态机QStateMachine

QStateMachine QState 提供了一种强大且灵活的方式来表示状态机中的状态&#xff0c;通过与状态机类(QStateMachine)和转换类(QSignalTransition&#xff0c; QEventTransition)结合&#xff0c;可以实现复杂的状态逻辑和用户交互。合理使用嵌套状态机、信号转换、动作与动画、…...

驱动开发学习20250523

kobj_type 功能&#xff1a;表示内核对象类型&#xff0c;描述通过ktype字段嵌入kobject的对象类型&#xff0c;控制在创建和销毁kobject时以及在读取或写入属性时发生的操作。 struct kobj_type {void (*realease)(struct kobject *);const struct sysfs_ops sysfs_ops;stru…...

Java详解LeetCode 热题 100(20):LeetCode 48. 旋转图像(Rotate Image)详解

文章目录 1. 题目描述2. 理解题目3. 解法一&#xff1a;转置 翻转3.1 思路3.2 Java代码实现3.3 代码详解3.4 复杂度分析3.5 适用场景 4. 解法二&#xff1a;四点旋转法4.1 思路4.2 Java代码实现4.3 代码详解4.4 复杂度分析4.5 适用场景 5. 详细步骤分析与示例跟踪5.1 解法一&a…...

CAU人工智能class4 批次归一化

归一化 在对输入数据进行预处理时会用到归一化&#xff0c;将输入数据的范围收缩到0到1之间&#xff0c;这有利于避免纲量对模型训练产生的影响。 但当模型过深时会产生下述问题&#xff1a; 当一个学习系统的输入分布发生变化时&#xff0c;这种现象称之为“内部协变量偏移”…...

Android11以上通过adb复制文件到内置存储让文件管理器可见

之前Android版本如果需要将文件通过adb push放到内置存储&#xff0c;push到/data/media/10下的目录即可&#xff0c;直接放/sdcard/文件管理器是看不到的。 现在最新的Android版本直接将文件放在/sdcard或/data/media/10下文件管理器也看不到 可以将文件再复制一份到一下路径…...