`
colin115
  • 浏览: 40014 次
社区版块
存档分类
最新评论

C++的性能优化实践

    博客分类:
  • 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@240038 VOBJ1
在整个执行流程中被调用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,执行效率更高; 原有逻辑:

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) ;
}

改造后的逻辑:

string Recordset::GetField(const string &strName)
{
    unordered_map<string, int>::iterator iter = m_fields.find(strName);
    if (iter == m_fields.end())
    {
        LOG_ERR("[Recordset::GetField] "<< strName <<" Not Find!!");
    }
    int nIndex = hasIndex ? m_vSort[m_nPos].m_iorder : m_nPos;
    return m_records[nIndex].GetValue(iter->second - 1) ;
}

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

2)在Recordset中,对于每个字段的存储,使用的是map<string, int> m_fields;  g++中的stl标准库中默认使用的红黑树作为map的底层数据结构;

通过附录中的文档2,我们发现其实有更快的结构, 在效率上,unorder map优于hash map, hash map 优于 红黑树; 如果不要求map有序,unordered_map 是更好的选择;

解决方法:将map结构换成unordered_map,性能消耗降到1.4%;  

总结

我们修改不到30行代码,整体性能提升10%左右,效果明显; 打蛇打七寸,性能优化的关键在于找准待优化的点,之后的事,也就水到渠成;
by the way,对于Linux平台使用C++工作的朋友,推荐一本好书:《程序员的自我修养》。这本书介绍了运行库相关的各种技术。 对装载、链接和库进行了深入浅出的剖析。看过真是大呼过瘾;

附录:

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

Posted by: 大CC | 03JUN,2013

博客:blog.me115.com 

0
2
分享到:
评论

相关推荐

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

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

    深入应用C++11:代码优化与工程级应用

    C++11新增加了相当多的现代编程语言的特性,相比C++98/03,它在生产力、安全性、性能和易用性上都有了大幅提高。比如auto和decltype让我们从书写冗长的类型和繁琐的类型推断中解脱出来,智能指针让我们再也不用担心...

    C++面向对象高效编程(高清pdf扫描版)

    本书以帮助读者掌握C++面向对象高效编程方法为目的,详细介绍了C++编程中的各种概念和应用技巧。全书共分为两部分,第一部分...书中带有大量的代码实例,使读者不仅能够从理论上得以提高,而且还能够轻松地在实践中应用

    C++并发编程中的内存管理笔记.md

    通过学习可以系统掌握C++中的内存管理与优化方法,包括动态内存、智能指针、并发内存管理、性能优化等方面。 使用建议: 重点学习并发内存管理和优化部分的实现代码,最好可以边看边在IDE中模拟实践。也可以在实际项目...

    10份2021 Pure C++大会 (PPT汇总).zip

    除此之外,还有工程实践,如动态库你该有新的更深入的认识了,还有性能优化相关的内容。 共10份文档: Ivica Bogosavljevic - The performance price of virtual functions in C++.pdf 卜恪 - The Unified C++ ...

    QCon广州 2019年全球软件开发大会PPT合集(30份).zip

    构建多线程的 Electron 应用和性能优化实践 高可用的深度学习技术架构 高并发场景下分布式实时信令系统的架构实践 动静相宜基于 JS 和 C++ 实现移动端⾼性能、强动态的视频 AR 拍摄框架 从 Darknet 到 Tensorfow- ...

    C++程序设计实践项目——学生信息管理系统,基于Qt+MySQL.zip

    performance_schema:自MySQL 5.5版本引入,用于收集服务器性能数据,帮助诊断和优化系统性能。 test(非必要):默认提供的测试数据库,通常用于学习和实验,生产环境中可考虑删除。 sys(自MySQL 5.7版本):...

    C++实现线程池详解(基于boost源码以及封装等线程池)

    一、要实现高效的线程池,可以考虑以下几点 二、实现线程池可以按照以下...7.2 线程池性能优化技巧 八、实际案例分析与优秀实践 8.1 案例一:并发网络服务 8.2 案例二:并行计算与数据处理 8.3 案例三:高性能Web服务器

    Cocos2d-x实战 C++卷,完整扫描版

    《Cocos2d-x实战:C++卷》[1] 系统论述了Cocos2d-x游戏开发理论与实践。全书内容涵盖了Cocos2d-x的核心类、瓦片地图、物理引擎、音乐音效、数据持久化、网络通信、数据交换格式、内存管理、性能优化、平台移植、程序...

    C++后端学习的技术栈

    1.精通C++编程语言:掌握现代语言特性,遵循最佳实践,并严格遵守《Effective C++》、C++核心指南等既定编码规范。 2.深刻理解数据结构、算法与软件设计模式:能据此编写出优化且易于维护的代码,解决复杂问题并提升...

    优化的C ++ 提高性能的成熟技术

    本实用指南教授开发人员性能调优原则,以便在C ++中实现优化。您将学习如何使已经体现C ++设计最佳实践的代码运行得更快,并且在任何计算机上消耗更少的资源 - 无论是手表,电话,工作站,超级计算机还是全球范围的...

    GMTC北京 2018年全球前端技术大会PPT合集(42份).zip

    剖析 HTML5 游戏引擎的渲染原理及动画性能优化 快应用开发与实现指南 跨容器高性能的离线化方案的实践和探索 跨平台2D渲染对象模型与数据可视化实践 客户端监控与异常排查实践 开源 Flix - 谈异构列表解决方案 基于...

    mmdet实例分割+MMDeploy+物体检测+图像掩码+提取应用+CV实战+c++

    【内容概要】 本代码示例是一个完整的C++应用程序,专注于利用MMDeploy框架进行物体检测,并从检测...实现性能优化技巧,如模型预热,提升实际应用中的响应速度。 掌握结果记录与可视化输出,便于分析模型性能与调试。

    第三章 鲲鹏应用性能测试与调优.pptx

    本章主要介绍在数据库、大数据和HPC场景下进行性能测试的方法,使用华为鲲鹏性能优化工具Kunpeng Tuning Kit对C/C++类程序和Java Mixed-Mode类程序进行性能分析的方法,以及对NUMA和线程并发数进行性能调优的案例。

    C++编程进阶与高级特性深入解析 构建强大可靠应用的全面指南 课程+课件

    课程提供了丰富的实例和项目,让我有机会实践这些概念,并深入了解如何进行性能优化和错误处理。我学到了很多关于多线程编程和并发性的知识,使我能够更好地利用多核处理器和编写线程安全的代码。 这门课程给了我很...

    Linux多线程服务端编程:使用muduo C++网络库

    5.2性能需求. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . 112 5.3多线程异步日志. . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . 114 5.4其他方案. . . . . . . . . ....

    韩冬:大数据之Mongodb的理论实践与优化

    mongodb简介:开源、高性能和无模式,C++开发,key-value存储(nosql--&gt;not only sql)。发展现状:新浪微博的Redis、Google的Bigtable和Amazon的SimpleDB都是Nosql型数据库。

    cc++程序员面试宝典-switch语句

    内容涵盖了switch语句的定义、基本语法、使用场景、优点、注意事项、与if语句的区别、实战应用、多重分支、范围检查、字符串处理、默认情况、性能考虑、灵活性、多态性、安全性、调试、性能优化和最佳实践等高级知识...

    Multicore and GPU programming an integrated approach

    1. 全面性强:书中涵盖了多核和GPU计算的基础概念、编程模型、算法实现以及性能优化等方面,使读者可以全面了解并行计算的基础知识和实践技巧。 2. 实用性强:书中讲解的并行计算技术都是实际开发中常用的,通过...

    c语言c++项目源代码_c语言学生成绩管理系统源码.rar

    1. **高效性能**:经过精心优化,系统在加载大量学生数据时仍能保持快速响应,确保用户体验流畅。 2. **灵活扩展**:系统采用模块化设计,各功能模块相对独立,方便后续功能的扩展和定制,满足个性化需求。 3. **...

Global site tag (gtag.js) - Google Analytics