[转]C++的性能优化实践

C++优化系列之性能调优工具篇 大家好,我是程序喵,虽然假期都快过去了,有很多朋友问程序喵怎么没更文呢?是不是偷懒了!其实我这几天没闲着,一直在整理学习资料,昨晚终于完成了,估计这两天会跟大家见面。 好了,我们CPP优化系列正式开始!今天的文章里,我会介绍一些常用的工具,帮助大家找到代码的“坏味道”(潜在的坑),进而提升代码质量。 那到底什么样的代码才算是高质量代码呢? 对此我整理了一份脑图: 如何能够提升代码质量呢,除了我们自身过硬的编码能力,还需要制定代码检查流程,一般代码检查有以下几种方式: 代码检查要检. 阅读详情

C++的性能优化实践


优化准则:

1. 二八法则:在任何一组东西中,最重要的只占其中一小部分,约20%,其余80%的尽管是多数,却是次要的;在优化实践中,我们将精力集中在优化那20%最耗时的代码上,整体性能将有显著的提升;这个很好理解。函数A虽然代码量大,但在一次正常执行流程中,只调用了一次。而另一个函数B代码量比A小很多,但被调用了1000次。显然,我们更应关注B的优化。
2. 编完代码,再优化;编码的时候总是考虑最佳性能未必总是好的;在强调最佳性能的编码方式的同时,可能就损失了代码的可读性和开发效率;

工具:

1 Gprof

工欲善其事,必先利其器。对于Linux平台下C++的优化,我们使用gprof工具。gprof是GNU profile工具,可以运行于linux、AIX、Sun等操作系统进行C、C++、Pascal、Fortran程序的性能分析,用于程序的性能优化以及程序瓶颈问题的查找和解决。通过分析应用程序运行时产生的“flat profile”,可以得到每个函数的调用次数,消耗的CPU时间(只统计CPU时间,对IO瓶颈无能为力),也可以得到函数的“调用关系图”,包括函数调用的层次关系,每个函数调用花费了多少时间。

2. gprof使用步骤

1) 用gcc、g++、xlC编译程序时,使用-pg参数,如:g++ -pg -o test.exe test.cpp编译器会自动在目标代码中插入用于性能测试的代码片断,这些代码在程序运行时采集并记录函数的调用关系和调用次数,并记录函数自身执行时间和被调用函数的执行时间。
2) 执行编译后的可执行程序,如:./test.exe。该步骤运行程序的时间会稍慢于正常编译的可执行程序的运行时间。程序运行结束后,会在程序所在路径下生成一个缺省文件名为gmon.out的文件,这个文件就是记录程序运行的性能、调用关系、调用次数等信息的数据文件。
3) 使用gprof命令来分析记录程序运行信息的gmon.out文件,如:gprof test.exe gmon.out则可以在显示器上看到函数调用相关的统计、分析信息。上述信息也可以采用gprof test.exe gmon.out> gprofresult.txt重定向到文本文件以便于后续分析。

以上只是gpro的使用步骤简介,关于gprof使用实例详见附录1;

实践

我们的程序遇到了性能瓶颈,在采用架构改造,改用内存数据库之前,我们考虑从代码级入手,先尝试代码级的优化;通过使用gprof分析,我们发现以下2个最为突出的问题:

1.初始化大对象耗时

分析报告:307 6.5% VOBJ1::VOBJ1@240038VOBJ1
在整个执行流程中被调用307次,其对象初始化耗时占到6.5%。
这个对象很大,包含的属性多,属于基础数据结构;
在程序进入构造函数函数体之前,类的父类对象和所有子成员变量对象已经被生成和构造。如果在构造函数体内位其执行赋值操作,显示属于浪费。如果在构造函数时已经知道如何为类的子成员变量初始化,那么应该将这些初始化信息通过构造函数的初始化列表赋予子成员变量,而不是在构造函数函数体中进行这些初始化。因为进入构造函数函数体之前,这些子成员变量已经初始化过一次了。
在C++程序中,创建/销毁对象是影响性能的一个非常突出的操作。首先,如果是从全局堆中生成对象,则需要首先进行动态内存分配操作。众所周知,动态分配/回收在C/C++程序中一直都是非常耗时的。因为牵涉到寻找匹配大小的内存块,找到后可能还需要截断处理,然后还需要修改维护全局堆内存使用情况信息的链表等。
解决方法:我们将大部分的初始化操作都移到初始化列表中,性能消耗降到1.8%。

2.Map使用不当

分析报告:89 6.8% Recordset::GetField
Recordset的getField被调用了89次,性能消耗占到6.8%;
Recordset是我们在在数据库层面的包装,对应取出数据的记录集;(用过ADO的朋友很熟悉);由于我们使用的是底层c++数据库接口,通过对数据库原始api进行一层包装,从而屏蔽开发人员对底层api的直接操作。这样的包装,带来的好处就是不用直接与底层数据库交互,在代码编写方面方便不少,代码可读性也很好;带来的问题就是性能的损失;

分析:(2点原因)
1)在GetField函数中,使用了map[“a”]来查询数据,如果找不到“a”,则map会自动插入key ”a”,并设value为0;而m.find(“a”)不会自动插入上述pair,执行效率更高;原有逻辑:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

    string Recordset::GetField(const string &strName)

{

    int nIndex;

    if (hasIndex==false)

    {

        nIndex = m_nPos;

    }

    else

    {

        nIndex = m_vSort[m_nPos].m_iorder;

    }

    if (m_fields[strName]==0)

    {

        LOG_ERR("Recordset::GetField:"<<strName<<" Not Find!!");

    }

    return m_records[nIndex].GetValue(m_fields[strName] - 1) ;

}

改造后的逻辑:

1

2

3

4

5

6

7

    string Recordset::GetField(const string &strName)

{

    unordered_map::iterator iter = m_fields.find(strName);

    if (iter == m_fields.end())

    {

        LOG_ERR("[Recordset::GetField] "<< strName <second - 1) ;

        return "";

    }

    return iter->second;

}

调整后的Recordset::GetField的执行时间约是之前的1/2;且易读性更高;

2)在Recordset中,对于每个字段的存储,使用的是map m_fields; g++中的stl标准库中默认使用的红黑树作为map的底层数据结构;
通过附录中的文档2,我们发现其实有更快的结构, 在效率上,unorder map优于hash map, hash map 优于 红黑树;如果不要求map有序,unordered_map 是更好的选择;
解决方法:将map结构换成unordered_map,性能消耗降到1.4%;

总结

我们修改不到30行代码,整体性能提升10%左右,效果明显;打蛇打七寸,性能优化的关键在于找准待优化的点,之后的事,也就水到渠成;
 

附录:

附1:prof工具介绍及实践
附2: map hash_map unordered_map 性能测试

[特殊字符]️ 站在巨人肩膀上:基于 SenseVoice.cpp 的前端语音识别实践 兼容性差,Chrome 还行,Safari 基本废了各种云端API:又回到了延迟和隐私问题直到我发现了SenseVoice✅ 支持中英日韩粤 5 种语言✅ 模型小(200MB 左右),加载快✅ 识别准确率高,特别是中文✅ 支持实时流式识别✅ 内置 VAD(语音活动检测)更幸运的是,GitHub 上有大佬@lovemefan已经用 C++ 重写了推理引擎(SenseVoice.cpp),我只需要基于这个库编译成版本就行了。🚀性能好:WebAssembly 接近原生性能🔒隐私安全。 阅读详情

相关推荐

C++与Qt实战:构建本地汉字转拼音工具,解决多音字与批量处理难题

在数据处理与文本处理领域,字符编码转换与自然语言处理是基础且高频的需求。其核心原理在于建立字符与目标表示(如拼音)之间的准确映射,并处理上下文依赖(如多音字)。这项技术的价值在于能自动化完成繁琐的手工转换,提升数据标准化与检索效率,广泛应用于中文信息处理、数据清洗、排序及搜索优化等场景。本文聚焦于利用C++的高效性与Qt的跨平台GUI能力,通过集成第三方拼音库(如cpp-pinyin)解决多音字消歧,并封装异步处理逻辑以应对批量文本转换,最终实现一个功能完备、支持文件导入导出的本地桌面工具,为C++工程实践

weixin_30664615的博客 346

C++高性能优化编程之如何测量性能(一)

性能测量 1、为什么要进行性能优化 2、性能测试的指标是什么 3、测量性能及改善变更记录文档 4、性能测量分析工具的使用 4.1、使用Linux Perf性能分析器进行性能测量分析 4.2、使用Google GperfTools性能分析器进行性能测量分析 5、性能测量微基准测试分析 5.1、使用计时时间测量函数执行时长微基准测试分析 5.2、使用Google Benchmark库微基准测试分析

weixin_30197685的博客 1956

⭐⭐⭐⭐⭐Linux C++性能优化秘籍:从编译器到代码,探究高性能C++程序的实现之道

高性能C++编程涉及多个方面,包括编译器优化、C++代码性能优化基本原则、C++对象管理与性能优化、多线程编程与性能优化、Linux系统调用优化等。通过学习和掌握这些要点,程序员可以有效地提高C++程序在Linux环境下的性能。接下来的章节将对这些核心要点进行详细的介绍。

探索C++编程的奥秘,分享深入的技术见解和实践,旨在激发读者创造力与解决问题的思维。 3722

linux c++提高程序性能

提高c++程序运行效率的方法

qq_36123543的博客 304

《C++后端开发最全面试题-从入门到Offer》目录

当今科技行业对C++开发者的需求持续高涨,从金融科技到游戏开发,从嵌入式系统到高性能计算,C++凭借其卓越的性能和灵活性始终占据着关键地位。然而,成为一名优秀的C++工程师并非易事,不仅需要扎实的语言基础,还要掌握现代C++特性、设计模式、性能优化技巧以及各种工业级开发经验。本专栏《C++后端开发最全面试题-从入门到Offer》正是为渴望在C++领域深入发展、准备技术面试或希望提升工程实践能力的开发者量身打造的全方位指南。

大模型大数据攻城狮的专栏 993

c++ 应用程序性能优化 第二版

本资源只是业余学习之用,如有涉及侵权,还请其他告知,谢谢

C++ I/O 性能优化指南

通过上述方法,可以显著提升 C++ 程序的 I/O 性能。具体优化方案需要根据实际应用场景进行选择和调整。希望本文能帮助你在开发高性能 C++ 应用时,更好地理解和应用这些优化技巧。

weixin_44727517的博客 1231

C++高效编程:内存与性能优化(pdf版)

C++高效编程:内存与性能优化(pdf版),深入C++经典好书!

C++的性能优化实践【转】

原文:http://www.cnblogs.com/me115/archive/2013/06/05/3117967.html 1. 二八法则:在任何一组东西中,最重要的只占其中一小部分,约20%,其余80%的尽管是多数,却是次要的;在优化实践中,我们将精力集中在优化那20%最耗时的代码上,整体性能将有显著的提升;这个很好理解。函数A虽然代码量大,但在一次正常执行流程中,只调用了一次。...

weixin_30838921的博客 96

C++高效编程-内存与性能优化.7z

C++高效编程-内存与性能优化 [美] R.Alexander G.Bensley 著 王峰 史金虎 翻译

嵌入式Linux内存使用与性能优化

嵌入式Linux内存使用与性能优化 如何提高程序运行的性能,降低内存使用

3个步骤实现完全离线的语音识别:Whisper.cpp让隐私与效率兼得

在数字化时代,语音识别技术无处不在,但你是否曾担心过隐私泄露?当你的语音数据被上传到云端处理时,敏感信息可能面临风险。更重要的是,网络不稳定或离线环境下的语音识别需求如何满足?传统的云端语音识别方案虽然强大,却受限于网络连接和数据隐私问题。今天,我们一起来探索一个全新的解决方案——Whisper.cpp,它能在本地设备上实现高效、准确的语音转文字功能,彻底告别网络依赖。 ## 痛点分析:云端语音

gitblog_00876的博客 403

Linux性能调优命令精华

通过一张图完美的列出了跟Linux性能相关的所有命令!

C++数字转字符串性能优化:从to_string到to_chars的深度对比与实践指南

在C++编程中,数字到字符串的转换是基础且高频的操作,其性能直接影响程序的吞吐量和延迟。其核心原理是将数值数据按指定格式(如十进制、十六进制、浮点数精度)编码为字符序列,涉及内存分配、格式化算法和本地化处理等底层机制。这项技术的价值在于,高效的转换能显著降低系统开销,尤其在日志记录、数据序列化和网络通信等场景中。对于需要处理海量数据的系统,如高频交易或嵌入式应用,选择最优的转换方法至关重要。本文聚焦于C++数字转字符串的性能调优,通过对比std::to_string、std::ostringstream、s

weixin_30918633的博客 343

oVirt 4.4.10超详细安装指南:从零搭建企业级虚拟化环境(附常见错误排查)

本文提供了oVirt 4.4.10企业级虚拟化平台的超详细安装指南,涵盖环境规划、系统准备、Engine安装配置、计算节点部署、存储系统集成及高级运维技巧。通过实战操作手册和常见错误排查方法,帮助用户从零搭建稳定高效的虚拟化环境,特别适合企业IT管理员参考实施。

wasm7browser的博客 351

IEEE LaTeX模板中algorithm排版避坑指南:如何优雅地嵌入算法描述?

本文详细解析了在IEEE LaTeX模板中优雅排版algorithm的实用技巧,包括基础配置、高级自定义及常见问题解决方案。通过嵌套环境与[H]参数的应用,帮助研究者克服IEEEtran模板对算法排版的限制,实现专业且美观的算法呈现。

weixin_28340315的博客 408

10个提示词技巧:如何写好负面提示词,让UniPic2-Metaquery-9B出图更干净

UniPic2-Metaquery-9B 是 Skywork 推出的统一多模态模型,基于 Qwen2.5-VL-Instruct 与 SD3.5-Medium 构建,一个模型同时支持**文生图(T2I)、图像编辑与图像理解**。它的负面提示词(Negative Prompt)能有效剔除模糊、畸变、伪影等画面瑕疵——本文整理 10 个实用提示词技巧,帮你快速写出干净的负面提示词,让 UniPic2-

gitblog_01179的博客 184

手机拍照也能玩高光谱?教你用TensorFlow Lite在Android上实现实时RGB转高光谱

本文介绍了如何利用TensorFlow Lite在Android设备上实现实时RGB到高光谱的图像重构技术。通过深度学习模型优化和移动端部署策略,使智能手机具备专业级光谱分析能力,适用于农业检测、化妆品分析等多个领域。

weixin_29091105的博客 246

终极指南:C++枚举魔法库完整配置的5个关键步骤

Magic Enum是现代C++开发中不可或缺的静态反射工具,专门为枚举类型提供强大的字符串转换和迭代功能。这个头文件库能够让开发者无需编写繁琐的宏代码或样板代码,轻松实现枚举值的各种操作。 ## 🚀 快速入门:环境准备与编译器要求 在开始使用枚举魔法库之前,您需要确保开发环境满足以下基本要求: **编译器兼容性清单**: - Clang/LLVM 5.0及以上版本 - MSVC++ 14

gitblog_01139的博客 412

基于Simulink/Matlab的VSG并网系统单相接地与相间短路故障仿真建模与特性分析

本文详细介绍了基于Simulink/Matlab搭建虚拟同步发电机(VSG)并网系统仿真模型的方法,并重点分析了单相接地与相间短路故障下的系统特性。通过设置三相故障模块参数,模拟了故障发生时的电压、电流变化及VSG动态响应,为理解故障机理、优化控制策略及设计继电保护提供了仿真依据与实践指导。

t8u9v0w1x的博客 514

riscv32-gcc工具链实战:从下载到编译的完整指南

本文提供了一份详尽的riscv32-gcc工具链实战指南,涵盖从官方渠道下载预编译版本、正确选择riscv32-glibc版本、配置环境变量到实战编译的全过程。通过清晰的步骤和避坑指南,帮助开发者快速搭建稳定的RISC-V交叉编译环境,并成功编译从Hello World到Linux内核的程序。

s3t4u的博客 675

C++实现文本转语音引擎:从架构设计到工程实践

文本转语音(TTS)技术是语音合成领域的核心,它通过将文本信息转换为可听的语音信号,实现了人机交互的自然化。其基本原理涉及语言学分析、声学建模和信号处理等多个环节。在工程实践中,高性能的TTS系统对于嵌入式设备、桌面应用和IoT场景具有重要价值,能够提供低延迟、高质量的语音输出。本文聚焦于使用C++从零构建一个轻量级、模块化的TTS引擎,详细探讨了如何集成ONNX Runtime进行神经声学模型推理,并实现了高效的流式音频播放。通过结合现代神经网络架构(如FastSpeech 2和HiFi-GAN)与经典的

weixin_33730836的博客 409

ABAQUS单元刚度矩阵输出全攻略:从理论到实践(含MTX/DAT文件对比)

本文详细解析了ABAQUS中单元刚度矩阵的输出方法,涵盖理论原理、MTX与DAT文件格式对比及二次开发应用。通过具体操作步骤和性能优化建议,帮助用户高效获取并利用刚度矩阵数据,特别适合需要进行有限元分析验证和二次开发的工程师。

lg888的博客 1006

实时手机检测-通用模型C++接口开发教程

本文介绍了如何在星图GPU平台上自动化部署实时手机检测-通用镜像,并开发高效的C++接口。该镜像能够实现实时手机目标检测,可广泛应用于视频监控、移动设备管理等场景,通过ONNX Runtime框架优化推理性能,提升部署效率。

weixin_42510201的博客 74

深度解析:C# Modbus TCP协议解析与异常处理(工控上位机必备)

协议解析要精准:掌握MBAP头和PDU的结构,尤其是常用功能码的请求/响应格式,避免因字节处理错误导致通信失败;异常处理要全面:覆盖通信层、协议层、数据层的所有异常类型,针对工业场景制定重试、重连、滤波等策略;资源管理要规范:使用释放资源,采用连接池复用连接,避免端口泄露;工业场景要适配:结合工控现场的特点(网络波动、电磁干扰、设备忙),优化通信效率和数据处理逻辑。通过以上解析和策略,可确保C#上位机与工业设备的Modbus TCP通信具备高稳定性、高可靠性、高容错性,满足工控领域的严苛要求。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 997

Vulkan入门系列3 - 绘制三角形代码解析(全)

【代码】Vulkan入门系列3 - 绘制三角形完整代码(带详细注释)

GPU全栈博主 1033
上一篇: [转]性能调优攻略
下一篇: Linux epoll详解
LinuxG_G
博客等级 码龄15年 58粉丝 176原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值