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

news2025/7/16 2:43:19

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

本文项目结束!


性能测试

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

  • 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】

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

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

相关文章

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 理…

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

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

【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:模拟音色与提升情感表现力 多语言 支持的语言: 中文、英文、日文、韩文、中文方言(粤语、四川话、上海话、天津话、武汉话等)跨语言及…

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

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

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

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

Qt状态机QStateMachine

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

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下文件管理器也看不到 可以将文件再复制一份到一下路径…

篇章二 需求分析(一)

目录 1.知名MQ 2.需求分析 2.1 核心概念 2.2 生产者消费者模型的类别 2.3 BrokerServer 内部的关键概念&#xff08;MQ&#xff09; 1.虚拟主机&#xff08;Virtual Host&#xff09; 2.交换机&#xff08;Exchange&#xff09; 3.队列&#xff08;Queue&#xff09; 4…

图解深度学习 - 机器学习简史

前言 深度学习并非总是解决问题的最佳方案&#xff1a;缺乏足够数据时&#xff0c;深度学习难以施展&#xff1b;某些情况下&#xff0c;其他机器学习算法可能更为高效。 若初学者首次接触的是深度学习&#xff0c;可能会形成一种偏见&#xff0c;视所有机器学习问题为深度学…

Gmsh 代码深度解析与应用实例

在科学计算与工程仿真领域&#xff0c;Gmsh 是一款广受欢迎的开源有限元网格生成器&#xff0c;它不仅支持复杂的几何建模&#xff0c;还能高效生成高质量的网格&#xff0c;并具备强大的后处理功能。本文将深入解析几段具有代表性的 Gmsh 代码&#xff0c;从基础几何创建到高级…